/* CSS commun de l'interface admin/web. */

/* Réserve toujours la gouttière de scrollbar verticale : évite le léger
   décalage horizontal (~1px) du contenu centré entre une page courte (sans
   scrollbar, ex. /shopping-lists avec peu de listes) et une page longue (avec
   scrollbar). Sans ça, l'ascenseur apparaît/disparaît selon la page et toute
   la barre du haut « saute ». */
html {
  scrollbar-gutter: stable;
}

:root,
[data-theme="dark"] {
      --bg:#0f172a;
      --panel:#111827;
      --panel-2:#1f2937;
      --panel-sunken:#0b1220;
      --hover-bg:#2b3a52;
      --topbar-bg:#020617;
      --text:#e5e7eb;
      --muted:#94a3b8;
      --border:#334155;
      --primary:#e8714f;
      --primary-hover:#d15a3e;
      --secondary:#475569;
      --secondary-hover:#334155;
      --danger:#dc2626;
      --danger-hover:#b91c1c;
      --success:#3f9a63;
      --success-hover:#347f53;
      --warning-text:#fbbf24;
      --shadow-color:rgba(0,0,0,.35);
    }

    * { box-sizing: border-box; }

    body {
      margin: 0;
      font-family: Arial, sans-serif;
      background: var(--bg);
      color: var(--text);
    }

    a { color: inherit; text-decoration: none; }

    /* ============================================================ */
    /* Accessibilité tactile globale                                  */
    /* touch-action: manipulation supprime le délai ~300ms iOS Safari */
    /* de "double-tap-to-zoom" sur les éléments cliquables, le tap   */
    /* devient instantané.                                           */
    /* -webkit-tap-highlight-color: transparent retire le carré gris */
    /* natif iOS/Android au tap (remplacé par notre propre :active). */
    /* ============================================================ */
    button, a, [role="button"], summary,
    label.theme-option, label.menu-filter-pill, label.menu-filter-pill-wide,
    label.menu-ingredient-label {
      touch-action: manipulation;
      -webkit-tap-highlight-color: transparent;
    }

    .container {
      max-width: 1200px;
      margin: 0 auto;
      padding: 20px;
    }

    .topbar {
      background: var(--topbar-bg);
      border-bottom: 1px solid var(--border);
      position: sticky;
      top: 0;
      z-index: 20;
    }

    .topbar-inner {
      max-width: 1200px;
      margin: 0 auto;
      padding: 14px 20px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 16px;
    }

    .brand {
      display: flex;
      align-items: center;
    }

    .brand a,
    .nav a {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      min-height: 44px;
      padding: 10px 14px;
      background: var(--panel-2);
      border: 1px solid var(--border);
      border-radius: 10px;
    }

    .brand a {
      font-size: 22px;
      line-height: 1;
    }

    .nav {
      display: flex;
      gap: 10px;
      flex-wrap: wrap;
      align-items: center;
    }

    .nav form {
      margin: 0;
    }

    .nav-btn {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 8px;
      min-height: 44px;
      padding: 10px 14px;
      background: var(--panel-2);
      border: 1px solid var(--border);
      border-radius: 10px;
      color: var(--text);
      cursor: pointer;
    }

    .topbar-user {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      min-height: 44px;
      padding: 10px 14px;
      background: var(--panel-sunken);
      border: 1px solid var(--border);
      border-radius: 10px;
      color: var(--muted);
      white-space: nowrap;
    }

    .auth-shell {
      width: 100%;
      max-width: 420px;
      margin: 7vh auto 0;
    }

    .auth-note {
      color: var(--muted);
      margin-top: 0;
      margin-bottom: 18px;
    }

    .auth-actions {
      display: flex;
      gap: 10px;
      flex-wrap: wrap;
      margin-top: 18px;
    }

    .nav-icon {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      width: 18px;
      height: 18px;
      flex: 0 0 auto;
    }

    .nav-icon svg {
      width: 100%;
      height: 100%;
      display: block;
    }

    .nav-label {
      white-space: nowrap;
    }

    .page-title {
      margin: 8px 0 18px;
      font-size: 30px;
    }

    .page-subtitle {
      color: var(--muted);
      margin-top: -8px;
      margin-bottom: 24px;
    }

    .page-header {
      display: flex;
      align-items: center;
      justify-content: flex-start;
      gap: 12px;
      flex-wrap: wrap;
      margin: 8px 0 18px;
    }

    .page-header .page-title {
      margin: 0;
    }

    .page-header-action {
      flex-shrink: 0;
    }

    .panel {
      background: var(--panel);
      border: 1px solid var(--border);
      border-radius: 14px;
      padding: 18px;
      margin-bottom: 18px;
    }

    .grid-2 {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 16px;
    }

    .grid-3 {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 16px;
    }

    .row {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 16px;
      margin-bottom: 14px;
    }

    label {
      display: block;
      margin-bottom: 6px;
      font-weight: bold;
    }

    .required {
    color: var(--danger);
    font-weight: bold;
    }

    input, textarea, select {
      width: 100%;
      padding: 11px 12px;
      border-radius: 10px;
      border: 1px solid var(--border);
      background: var(--panel-sunken);
      color: var(--text);
      font-size: 15px;
    }

    textarea {
      min-height: 120px;
      resize: vertical;
    }

    table {
      width: 100%;
      border-collapse: collapse;
    }

    th, td {
      padding: 12px 10px;
      border-bottom: 1px solid var(--border);
      text-align: left;
      vertical-align: top;
    }

    .actions {
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
      align-items: center;
    }

    .btn {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 6px;
      padding: 10px 14px;
      border-radius: 10px;
      border: 1px solid transparent;
      cursor: pointer;
      font-size: 14px;
      text-decoration: none;
      background: var(--primary);
      color: white;
    }

    /* État désactivé GLOBAL pour tous les .btn (variantes incluses :
       primary/secondary/danger/success/ghost). Avant : seuls 2 contextes
       ponctuels dimmaient leurs boutons → ailleurs (ex. /admin/users, vue
       super-admin : « Mettre à jour » / « Retirer » désactivés sur les
       lignes responsables) le bouton restait pleine couleur, indiscernable
       d'un bouton actif. Opacité + curseur not-allowed = lisible sur les
       3 thèmes. */
    .btn:disabled,
    .btn[disabled] {
      opacity: 0.5;
      cursor: not-allowed;
      box-shadow: none;
    }

    .ingredients-footer {
    display: flex;
    justify-content: flex-end;
    margin-top: 12px;
    }

    .add-ingredient-icon {
      display: none;
    }

    .btn:hover { background: var(--primary-hover); }

    .btn.secondary {
      background: var(--panel-2);
      color: var(--text);
      border: 1px solid var(--border);
    }

    .btn.secondary:hover {
      background: var(--hover-bg);
      border-color: var(--primary);
    }

    .btn.danger {
      background: var(--danger);
    }

    .btn.danger:hover {
      background: var(--danger-hover);
    }

    .btn.success {
      background: var(--success);
    }

    .btn.success:hover {
      background: var(--success-hover);
    }

    .flash {
      background: #0b2545;
      border: 1px solid #1d4ed8;
      color: #dbeafe;
      padding: 12px 14px;
      border-radius: 10px;
      margin-bottom: 16px;
    }

    .muted {
      color: var(--muted);
    }

    .card-link {
      display: block;
      background: var(--panel);
      border: 1px solid var(--border);
      border-radius: 14px;
      padding: 18px;
      transition: transform .08s ease;
    }

    .card-link:hover {
      transform: translateY(-1px);
      border-color: var(--primary);
    }

    .stat {
      font-size: 32px;
      font-weight: bold;
      margin-top: 6px;
    }

    .ingredient-grid {
      display: grid;
      grid-template-columns: 2.2fr 1fr 1fr 1.3fr auto;
      gap: 10px;
      align-items: start;
    }

    .ingredient-row {
      margin-bottom: 10px;
    }

    .autocomplete {
    position: relative;
    }

    .autocomplete-menu {
      position: absolute;
      top: calc(100% + 4px);
      left: 0;
      right: 0;
      z-index: 50;
      display: none;
      background: var(--panel-sunken);
      border: 1px solid var(--border);
      border-radius: 10px;
      max-height: 220px;
      overflow-y: auto;
      box-shadow: 0 8px 24px var(--shadow-color, rgba(0, 0, 0, .25));
      -webkit-overflow-scrolling: touch;
      touch-action: pan-y;
      overscroll-behavior: contain;
    }

    .autocomplete-menu.show {
      display: block;
    }

    .autocomplete-item {
      display: block;
      width: 100%;
      padding: 10px 12px;
      border: 0;
      background: transparent;
      color: var(--text);
      text-align: left;
      cursor: pointer;
    }

    .autocomplete-item:hover {
      background: var(--panel-2);
    }

    .ingredient-head {
      color: var(--muted);
      font-size: 13px;
      margin-bottom: 8px;
    }

    .picker-actions {
      display: flex;
      flex-direction: column;
      gap: 8px;
    }

    .chip {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      background: var(--panel-2);
      border: 1px solid var(--border);
      border-radius: 999px;
      padding: 7px 10px;
      font-size: 13px;
      color: var(--text);
    }

    .chip button {
      background: transparent;
      color: var(--muted);
      border: 0;
      cursor: pointer;
      font-size: 14px;
      padding: 0;
    }

    .searchbar {
      display: grid;
      grid-template-columns: 1fr auto;
      gap: 10px;
    }

    .search-actions {
      justify-content: flex-end;
    }

    .search-icon {
      display: none;
      width: 18px;
      height: 18px;
      flex: 0 0 auto;
    }

    .search-icon svg {
      width: 100%;
      height: 100%;
      display: block;
    }

    .search-label {
      white-space: nowrap;
    }

    .inline-form {
      display: inline;
    }

    @media (max-width: 900px) {
  .grid-2, .grid-3, .row {
    grid-template-columns: 1fr;
  }

    .topbar-inner {
      flex-direction: row;
      align-items: center;
      justify-content: space-between;
      padding: 10px 12px;
      gap: 8px;
    }

    .nav {
      flex: 1 1 auto;
      min-width: 0;
      justify-content: flex-end;
      flex-wrap: nowrap;
      gap: 6px;
    }

    .brand a,
    .nav a,
    .nav-btn {
      width: 44px;
      min-width: 44px;
      height: 44px;
      padding: 0;
    }

    .nav-icon {
      display: block;
    }

    .nav-label {
      display: none;
    }

    .topbar-user {
      display: none;
    }

  .ingredient-head {
    display: none;
  }

  .ingredient-grid {
    grid-template-columns: minmax(0, 1fr) 52px;
    column-gap: 10px;
    row-gap: 10px;
    align-items: start;
  }

  .ingredient-grid > input,
  .ingredient-grid > .autocomplete {
    grid-column: 1;
    min-width: 0;
  }

  .ingredient-grid > .remove-ingredient-btn {
    grid-column: 2;
    grid-row: 1 / span 4;
    align-self: start;
    width: 52px;
    min-width: 52px;
    padding: 10px 0;
  }

  #ingredients-container .ingredient-row + .ingredient-row {
    border-top: 1px solid var(--border);
    padding-top: 14px;
    margin-top: 14px;
  }

  .autocomplete-menu {
    position: static;
    margin-top: 6px;
    max-height: 180px;
  }

  .ingredients-footer {
    justify-content: flex-end;
  }

  .add-ingredient-btn {
    width: 52px;
    min-width: 52px;
    padding: 10px 0;
  }

  .add-ingredient-label {
    display: none;
  }

  .add-ingredient-icon {
    display: inline;
    font-size: 22px;
    line-height: 1;
  }

}

.table-wrap {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.recipes-table {
  width: 100%;
}

.col-actions,
.cell-actions {
  width: 1%;
  white-space: nowrap;
}

.recipe-actions {
  justify-content: flex-start;
}

/* Liste des recettes (vue admin) — cards empilées : infos en haut, actions en bas. */
.recipes-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.recipe-row {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel-2);
  transition: border-color 0.12s ease;
}

.recipe-row:hover {
  border-color: var(--primary);
}

.recipe-row-head {
  display: grid;
  grid-template-columns: 72px 1fr auto;
  gap: 12px;
  align-items: center;
}

.recipe-row-thumb-link {
  display: block;
  border-radius: 10px;
  overflow: hidden;
  transition: transform 0.12s ease;
}

.recipe-row-thumb-link:hover {
  transform: scale(1.03);
}

.recipe-row-thumb {
  width: 72px;
  height: 72px;
  border-radius: 10px;
  overflow: hidden;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  position: relative;
}

.recipe-row-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.recipe-row-thumb-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--panel-2) 0%, var(--panel-sunken) 100%);
}

.recipe-row-thumb-fallback {
  font-size: 28px;
  opacity: 0.4;
}

.recipe-row-info {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.recipe-row-name {
  font-weight: 600;
  font-size: 16px;
  color: var(--text);
  text-decoration: none;
  line-height: 1.25;
  word-break: break-word;
}

.recipe-row-name:hover {
  color: var(--primary);
}

.recipe-row-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--muted);
  font-size: 13px;
  flex-wrap: wrap;
}

.recipe-row-toggle-form {
  margin: 0;
  display: inline-flex;
}

.recipe-row-toggle-btn {
  /* Bouton 40px visible + zone tap étendue à 44 via ::after. */
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  background: color-mix(in srgb, var(--primary) 12%, var(--panel-sunken));
  color: var(--primary);
  border: 1px solid color-mix(in srgb, var(--primary) 40%, var(--border));
  border-radius: 50%;
  font-size: 22px;
  line-height: 1;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease, transform 0.12s ease;
}

.recipe-row-toggle-btn::after {
  content: "";
  position: absolute;
  inset: -2px;
}

.recipe-row-toggle-btn:hover,
.recipe-row-toggle-btn:focus-visible {
  background: var(--primary);
  color: #ffffff;
  outline: none;
  transform: scale(1.08);
}

.recipe-row-toggle-btn:active {
  transform: scale(0.96);
}

/* Variante "retirer" : couleur danger pour signaler que la recette est
   déjà dans la sélection et que ce clic l'enlève. */
.recipe-row-toggle-btn-remove {
  background: color-mix(in srgb, var(--danger) 14%, var(--panel-sunken));
  color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 45%, var(--border));
}

.recipe-row-toggle-btn-remove:hover,
.recipe-row-toggle-btn-remove:focus-visible {
  background: var(--danger);
  color: #ffffff;
}

.recipe-row-empty {
  list-style: none;
  text-align: center;
  padding: 16px;
}

@media (max-width: 700px) {
  .recipes-table th,
  .recipes-table td {
    padding: 10px 8px;
    font-size: 14px;
  }

  .recipes-table .col-type {
    display: none;
  }

  /* (refonte des boutons de la liste des recettes : voir
     « Liste des recettes — refonte boutons » en fin de fichier.) */

.searchbar {
  grid-template-columns: 1fr;
  gap: 8px;
}

.searchbar .actions {
  flex-direction: row;
  align-items: center;
  justify-content: center;
  flex-wrap: nowrap;
  gap: 6px;
}

.searchbar .btn {
  width: 44px;
  min-width: 44px;
  height: 44px;
  padding: 0;
}

.search-icon {
  display: block;
}

.search-label {
  display: none;
}


}

    .recipe-form {
  padding-bottom: 90px;
}

/* Import recette depuis URL externe (vague 8.1 Phase 1).             */
/* Panel discret au-dessus du form sur /recipes/new uniquement.       */

.recipe-import-panel {
  margin: 0 0 16px;
  padding: 14px 16px;
  background: color-mix(in srgb, var(--primary) 6%, var(--panel));
  border: 1px solid color-mix(in srgb, var(--primary) 20%, var(--border));
  border-radius: 12px;
}

/* Tabs (vague 8.1 Phase 2) ----------------------------------------- */
.recipe-import-panel-tabs {
  display: flex;
  gap: 4px;
  margin: -4px -4px 12px;
  border-bottom: 1px solid color-mix(in srgb, var(--primary) 15%, var(--border));
}

.recipe-import-panel-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: color 0.12s ease, border-color 0.12s ease;
  margin-bottom: -1px; /* aligne avec border-bottom du conteneur */
}

.recipe-import-panel-tab:hover,
.recipe-import-panel-tab:focus-visible {
  color: var(--text);
  outline: none;
}

.recipe-import-panel-tab.is-active {
  color: var(--primary);
  border-bottom-color: var(--primary);
}

.recipe-import-panel-pane {
  display: none;
}

.recipe-import-panel-pane.is-active {
  display: block;
}

.recipe-import-panel-hint {
  font-size: 13px;
  color: var(--muted);
  margin: 0 0 10px;
}

/* Textarea pane Texte ---------------------------------------------- */
.recipe-import-panel-textarea-wrap {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.recipe-import-panel-textarea {
  width: 100%;
  min-height: 180px;
  padding: 10px 12px;
  font-family: inherit;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text);
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 10px;
  resize: vertical;
}

.recipe-import-panel-textarea:focus {
  outline: 2px solid color-mix(in srgb, var(--primary) 40%, transparent);
  outline-offset: 1px;
}

.recipe-import-panel-text-actions {
  display: flex;
  justify-content: flex-end;
}

.recipe-import-panel-text-actions .btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Badge quota IA (Vague 9.1) — affiché en haut du panel d'import,
   uniquement si le tenant n'est pas en mode illimité. */
.recipe-import-panel-quota {
  margin: 0 0 12px 0;
  padding: 6px 10px;
  font-size: 13px;
  color: var(--text-muted);
  background: color-mix(in srgb, var(--primary) 6%, transparent);
  border: 1px solid color-mix(in srgb, var(--primary) 18%, transparent);
  border-radius: 6px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Pane Photo ------------------------------------------------------- */
.recipe-import-panel-image-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.recipe-import-panel-image-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  cursor: pointer;
}

.recipe-import-panel-image-feedback {
  margin-top: 8px;
  font-size: 13px;
  color: var(--text-muted);
  font-style: italic;
  word-break: break-all;
}

.recipe-import-panel-image-submit-wrap {
  margin-top: 12px;
  display: flex;
  justify-content: flex-end;
}

.recipe-import-panel-image-submit-wrap .btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
}

.recipe-import-panel-image-submit-wrap .btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}


.recipe-import-panel-row {
  display: flex;
  gap: 8px;
  align-items: stretch;
}

.recipe-import-panel-input {
  flex: 1;
  min-width: 0;
  /* Reprend le style des autres input du form (cf section input/textarea) */
}

.recipe-import-panel-row .btn {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
}

/* :not([hidden]) sinon `display: inline-block` override l'attribut
   HTML `hidden` et le spinner reste visible au load (bug visuel :
   il tournait dans le bouton dès l'affichage du form). Le JS bascule
   `spinner.hidden = true/false` selon l'état du fetch. */
.recipe-import-panel-spinner:not([hidden]) {
  width: 14px;
  height: 14px;
  border: 2px solid color-mix(in srgb, currentColor 25%, transparent);
  border-top-color: currentColor;
  border-radius: 50%;
  animation: recipe-import-spin 0.7s linear infinite;
  display: inline-block;
}

@keyframes recipe-import-spin {
  to { transform: rotate(360deg); }
}

.recipe-import-panel-error {
  margin: 8px 0 0;
  font-size: 13px;
  color: var(--danger);
}

@media (max-width: 540px) {
  .recipe-import-panel-row {
    flex-direction: column;
  }
  .recipe-import-panel-row .btn {
    justify-content: center;
  }
}

.form-actions {
  margin-top: 8px;
}

.floating-savebar {
  position: fixed;
  left: 16px;
  /* --kb-inset (posé par recipe_form.js via la VisualViewport API) = hauteur
     recouverte par le clavier virtuel mobile. max() : au repos on garde la
     position basse, clavier ouvert on remonte juste au-dessus du clavier. */
  bottom: max(16px, calc(var(--kb-inset, 0px) + 12px));
  transform: translateY(120%);
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
  z-index: 40;
}

.floating-savebar.show {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.floating-save-btn {
  width: 52px;
  height: 52px;
  padding: 0;
  border-radius: 999px;
  box-shadow: 0 10px 24px rgba(0, 0, 0, .35);
}

.floating-save-btn svg {
  width: 22px;
  height: 22px;
  display: block;
}

@media (max-width: 700px) {
  .floating-savebar {
    left: 12px;
    /* Au repos : au-dessus de la bottom-nav (~51px) avec un dégagement
       confortable pour ne pas être collé. Clavier ouvert : --kb-inset prend
       le dessus et place le bouton au-dessus du clavier (la bottom-nav est de
       toute façon masquée par le clavier). */
    bottom: max(calc(51px + env(safe-area-inset-bottom, 0) + 22px), calc(var(--kb-inset, 0px) + 12px));
  }

  .floating-save-btn {
    width: 48px;
    height: 48px;
  }
}


.admin-inline-form,
.admin-user-form,
.admin-table-form {
  display: grid;
  gap: 10px;
}

.admin-inline-form {
  grid-template-columns: minmax(220px, 1fr) auto;
  align-items: end;
}

.admin-table-form {
  grid-template-columns: minmax(150px, 1fr) auto;
  align-items: center;
}

/* Vague 9.1 — page /admin/quotas */
.admin-quotas-form {
  /* Forms invisibles utilisés via l'attribut HTML5 form="id" pour
     pouvoir répartir inputs/buttons sur plusieurs <td>. Aucun visuel
     à afficher pour le form lui-même. */
  display: contents;
}

.admin-quotas-table input.admin-quotas-input[type="number"] {
  width: 90px;
  min-height: 36px;
  padding: 4px 8px;
}

.admin-quotas-checkbox-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  min-height: 36px;
}

.admin-quotas-submit {
  min-height: 36px;
  padding: 4px 12px;
}

.admin-rules {
  display: grid;
  gap: 12px;
}

.account-password-form,
.account-default-tenant-form,
.account-info-list {
  display: grid;
  gap: 14px;
}

.account-info-list > div {
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel-sunken);
}

.topbar-user strong {
  color: var(--text);
}

@media (max-width: 800px) {
  .admin-inline-form,
  .admin-table-form,
  .admin-grid {
    grid-template-columns: 1fr;
  }
}



/* Styles spécifiques : ingredients_admin.html */

body.page-ingredients-admin .ingredient-admin-stack {
    display: grid;
    gap: 14px;
  }

  body.page-ingredients-admin .ingredient-duplicate-card {
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 16px;
    background: var(--panel-sunken);
  }

  body.page-ingredients-admin .ingredient-duplicate-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
  }

  body.page-ingredients-admin .ingredient-duplicate-title {
    font-size: 22px;
    font-weight: bold;
    margin-top: 4px;
  }

  body.page-ingredients-admin .ingredient-badges {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
  }

  body.page-ingredients-admin .ingredient-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 10px;
    border-radius: 999px;
    background: var(--panel-2);
    border: 1px solid #475569;
    font-size: 13px;
  }

  body.page-ingredients-admin .ingredient-variant-list {
    display: grid;
    gap: 10px;
  }

  body.page-ingredients-admin .ingredient-group-merge-form {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    align-items: center;
    margin-top: 12px;
    margin-bottom: 12px;
  }

  body.page-ingredients-admin .ingredient-group-merge-form input[type="text"] {
    flex: 1 1 280px;
  }

  body.page-ingredients-admin .ingredient-group-merge-form select {
    flex: 1 1 280px;
    min-width: 220px;
  }

  body.page-ingredients-admin .ingredient-meta-list {
    display: grid;
    gap: 6px;
    margin-top: 10px;
  }

  body.page-ingredients-admin .ingredient-meta-line {
    font-size: 13px;
    color: var(--muted);
  }

  body.page-ingredients-admin .ingredient-variant-row {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) minmax(220px, 1fr) auto;
    gap: 10px;
    align-items: center;
    padding: 12px;
    border-radius: 12px;
    background: var(--panel);
    border: 1px solid var(--border);
  }

  body.page-ingredients-admin .ingredient-variant-name {
    font-weight: bold;
    margin-bottom: 4px;
  }

  body.page-ingredients-admin .ingredient-variant-recipes {
    font-size: 13px;
    color: var(--muted);
  }

  body.page-ingredients-admin .ingredient-rename-inline {
    display: contents;
  }

  body.page-ingredients-admin .ingredient-rename-inline input {
    min-width: 0;
  }

  body.page-ingredients-admin .ingredient-suggestion-note {
    margin-top: 12px;
    color: var(--muted);
    font-size: 13px;
  }

  body.page-ingredients-admin .ingredient-table-form {
    display: grid;
    grid-template-columns: minmax(180px, 1fr) auto;
    gap: 8px;
    align-items: center;
  }

  body.page-ingredients-admin .ingredient-name-cell {
    min-width: 220px;
  }

  body.page-ingredients-admin .ingredient-name-cell strong {
    display: block;
    margin-bottom: 4px;
  }

  body.page-ingredients-admin .ingredient-table-recipes {
    color: var(--muted);
    font-size: 13px;
  }

  body.page-ingredients-admin .inline-recipe-link {
    text-decoration: underline;
    text-underline-offset: 2px;
  }

  body.page-ingredients-admin .panel-collapsible > summary {
    list-style: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
  }

  body.page-ingredients-admin .panel-collapsible > summary::-webkit-details-marker {
    display: none;
  }

  body.page-ingredients-admin .panel-collapsible-title {
    display: flex;
    flex-direction: column;
    gap: 6px;
  }

  body.page-ingredients-admin .panel-collapsible-title h2 {
    margin: 0;
  }

  body.page-ingredients-admin .panel-collapsible-chevron {
    font-size: 18px;
    color: var(--muted);
    transition: transform 0.18s ease;
  }

  body.page-ingredients-admin .panel-collapsible[open] .panel-collapsible-chevron {
    transform: rotate(90deg);
  }

  body.page-ingredients-admin .panel-collapsible-body {
    margin-top: 14px;
  }

  body.page-ingredients-admin .ingredient-duplicate-toolbar {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
  }

  body.page-ingredients-admin .ingredient-ignored-list {
    display: grid;
    gap: 10px;
  }

  body.page-ingredients-admin .ingredient-ignored-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px;
    border-radius: 12px;
    background: var(--panel);
    border: 1px solid var(--border);
  }

  body.page-ingredients-admin .ingredient-ignored-text {
    display: grid;
    gap: 4px;
  }

  body.page-ingredients-admin .ingredient-ignored-names {
    font-size: 13px;
    color: var(--muted);
  }

  body.page-ingredients-admin .ingredient-ignored-summary-note {
    margin-top: 6px;
  }

  body.page-ingredients-admin .panel-collapsible {
    transition: border-color .18s ease, box-shadow .18s ease, background .18s ease;
  }

  body.page-ingredients-admin .panel-collapsible > summary {
    padding: 6px 4px;
    border-radius: 12px;
    transition: background .18s ease, transform .18s ease;
  }

  body.page-ingredients-admin .panel-collapsible > summary:active {
    transform: scale(0.995);
  }

  body.page-ingredients-admin .panel-collapsible-title {
    min-width: 0;
  }

  body.page-ingredients-admin .panel-collapsible-title h2 {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 22px;
  }

  body.page-ingredients-admin .panel-collapsible-hint {
    font-size: 12px;
    color: var(--muted);
    letter-spacing: 0.01em;
  }

  body.page-ingredients-admin .panel-collapsible-chevron {
    width: 34px;
    height: 34px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border);
    background: color-mix(in srgb, var(--text) 6%, transparent);
    font-size: 18px;
  }

  body.page-ingredients-admin .panel-collapsible-name-main {
    border-color: color-mix(in srgb, var(--primary) 50%, var(--border));
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--primary) 12%, transparent) inset;
    background:
      linear-gradient(180deg, color-mix(in srgb, var(--primary) 12%, transparent), color-mix(in srgb, var(--primary) 4%, transparent)),
      var(--panel);
  }

  body.page-ingredients-admin .panel-collapsible-name-main > summary {
    background: color-mix(in srgb, var(--primary) 12%, transparent);
  }

  body.page-ingredients-admin .panel-collapsible-name-main > summary:hover {
    background: color-mix(in srgb, var(--primary) 18%, transparent);
  }

  body.page-ingredients-admin .panel-collapsible-name-main .panel-collapsible-title h2 {
    color: color-mix(in srgb, var(--primary) 28%, var(--text));
  }

  body.page-ingredients-admin .panel-collapsible-name-main .panel-collapsible-title h2::before {
    content: "●";
    font-size: 14px;
    color: var(--primary);
  }

  body.page-ingredients-admin .panel-collapsible-name-main:hover .panel-collapsible-chevron {
    background: color-mix(in srgb, var(--primary) 18%, transparent);
    border-color: color-mix(in srgb, var(--primary) 50%, var(--border));
    color: var(--primary);
  }

  body.page-ingredients-admin .panel-collapsible-name-muted {
    border-color: color-mix(in srgb, var(--primary) 25%, var(--border));
    background:
      linear-gradient(180deg, color-mix(in srgb, var(--primary) 6%, transparent), color-mix(in srgb, var(--primary) 2%, transparent)),
      var(--panel);
  }

  body.page-ingredients-admin .panel-collapsible-name-muted > summary {
    background: color-mix(in srgb, var(--primary) 6%, transparent);
  }

  body.page-ingredients-admin .panel-collapsible-name-muted > summary:hover {
    background: color-mix(in srgb, var(--primary) 10%, transparent);
  }

  body.page-ingredients-admin .panel-collapsible-name-muted .panel-collapsible-title h2 {
    color: color-mix(in srgb, var(--primary) 22%, var(--text));
  }

  body.page-ingredients-admin .panel-collapsible-name-muted .panel-collapsible-title h2::before {
    content: "●";
    font-size: 14px;
    color: var(--primary);
  }

  body.page-ingredients-admin .panel-collapsible-name-muted:hover .panel-collapsible-chevron {
    background: color-mix(in srgb, var(--primary) 11%, transparent);
    border-color: color-mix(in srgb, var(--primary) 35%, var(--border));
    color: var(--primary);
  }

  body.page-ingredients-admin .panel-collapsible-category-main {
    border-color: color-mix(in srgb, var(--success) 50%, var(--border));
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--success) 12%, transparent) inset;
    background:
      linear-gradient(180deg, color-mix(in srgb, var(--success) 12%, transparent), color-mix(in srgb, var(--success) 4%, transparent)),
      var(--panel);
  }

  body.page-ingredients-admin .panel-collapsible-category-main > summary {
    background: color-mix(in srgb, var(--success) 12%, transparent);
  }

  body.page-ingredients-admin .panel-collapsible-category-main > summary:hover {
    background: color-mix(in srgb, var(--success) 18%, transparent);
  }

  body.page-ingredients-admin .panel-collapsible-category-main .panel-collapsible-title h2 {
    color: color-mix(in srgb, var(--success) 30%, var(--text));
  }

  body.page-ingredients-admin .panel-collapsible-category-main .panel-collapsible-title h2::before {
    content: "●";
    font-size: 14px;
    color: var(--success);
  }

  body.page-ingredients-admin .panel-collapsible-category-main:hover .panel-collapsible-chevron {
    background: color-mix(in srgb, var(--success) 18%, transparent);
    border-color: color-mix(in srgb, var(--success) 50%, var(--border));
    color: var(--success);
  }

  body.page-ingredients-admin .panel-collapsible-category-muted {
    border-color: color-mix(in srgb, var(--success) 25%, var(--border));
    background:
      linear-gradient(180deg, color-mix(in srgb, var(--success) 6%, transparent), color-mix(in srgb, var(--success) 2%, transparent)),
      var(--panel);
  }

  body.page-ingredients-admin .panel-collapsible-category-muted > summary {
    background: color-mix(in srgb, var(--success) 6%, transparent);
  }

  body.page-ingredients-admin .panel-collapsible-category-muted > summary:hover {
    background: color-mix(in srgb, var(--success) 10%, transparent);
  }

  body.page-ingredients-admin .panel-collapsible-category-muted .panel-collapsible-title h2 {
    color: color-mix(in srgb, var(--success) 22%, var(--text));
  }

  body.page-ingredients-admin .panel-collapsible-category-muted .panel-collapsible-title h2::before {
    content: "●";
    font-size: 14px;
    color: var(--success);
  }

  body.page-ingredients-admin .panel-collapsible-category-muted:hover .panel-collapsible-chevron {
    background: color-mix(in srgb, var(--success) 11%, transparent);
    border-color: color-mix(in srgb, var(--success) 35%, var(--border));
    color: var(--success);
  }

  @media (max-width: 900px) {
body.page-ingredients-admin .ingredient-variant-row,
body.page-ingredients-admin .ingredient-table-form {
      grid-template-columns: 1fr;
    }

    body.page-ingredients-admin .ingredient-ignored-row {
      flex-direction: column;
      align-items: stretch;
    }

    body.page-ingredients-admin .ingredient-rename-inline {
      display: grid;
      grid-template-columns: 1fr;
      gap: 10px;
    }

}


/* Styles spécifiques : shopping_list_detail.html */

/* Dans une liste, on cache la navbar globale pour garder toute la place au téléphone. */
  body.page-shopping-list-detail .topbar {
    display: none;
  }

  body.page-shopping-list-detail .container {
    max-width: 760px;
    padding: 0 10px 14px;
  }

  body.page-shopping-list-detail .shopping-app {
    display: grid;
    gap: 10px;
  }

  body.page-shopping-list-detail .shopping-topbar {
    position: sticky;
    top: 0;
    z-index: 40;
    display: grid;
    gap: 7px;
    padding: 7px 8px 8px;
    margin: 0 -10px;
    border-radius: 0 0 16px 16px;
    /* color-mix garde une légère transparence pour que le blur fasse effet,
       tout en s'adaptant au thème (dark sombre, clair off-white, rose pâle). */
    background: color-mix(in srgb, var(--topbar-bg) 95%, transparent);
    border: 1px solid var(--border);
    border-top: 0;
    backdrop-filter: blur(10px);
  }

  body.page-shopping-list-detail .shopping-topbar-row {
    display: grid;
    grid-template-columns: 42px minmax(0, 1fr) 42px;
    gap: 8px;
    align-items: center;
  }

  body.page-shopping-list-detail .shopping-icon-btn,
body.page-shopping-list-detail .shopping-icon-link {
    width: 42px;
    height: 38px;
    min-height: 38px;
    padding: 0;
    border-radius: 13px;
    font-size: 19px;
  }

  body.page-shopping-list-detail .shopping-title-inline {
    display: grid;
    min-width: 0;
  }

  body.page-shopping-list-detail .shopping-title-inline input {
    min-height: 38px;
    padding: 6px 9px;
    border-radius: 13px;
    font-size: 16px;
    font-weight: 800;
    text-align: center;
    background: var(--panel-sunken);
  }

  body.page-shopping-list-detail .shopping-save-state {
    min-height: 0;
    color: var(--muted);
    font-size: 0;
    text-align: center;
  }

  body.page-shopping-list-detail .shopping-progress {
    height: 8px;
    overflow: hidden;
    border-radius: 999px;
    background: var(--panel-sunken);
    border: 1px solid var(--border);
  }

  body.page-shopping-list-detail .shopping-progress > span {
    display: block;
    height: 100%;
    background: var(--success);
    transition: width .18s ease, background .18s ease;
  }

  body.page-shopping-list-detail .shopping-progress > span:not([class*="progress-w-"]) {
    width: 0;
  }

  body.page-shopping-list-detail .shopping-categories {
    display: grid;
    gap: 8px;
    padding-bottom: 72px;
  }

  body.page-shopping-list-detail .shopping-category,
body.page-shopping-list-detail .shopping-edit-category {
    display: grid;
    gap: 6px;
    padding: 13px 12px;
  }

  body.page-shopping-list-detail .shopping-category.is-empty,
body.page-shopping-list-detail .shopping-edit-category.is-empty {
    opacity: .72;
  }

  body.page-shopping-list-detail .shopping-category-title {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    align-items: center;
    margin-bottom: 2px;
  }

  body.page-shopping-list-detail .shopping-category-title h2 {
    margin: 0;
    font-size: 20px;
    line-height: 1.2;
  }

  body.page-shopping-list-detail .shopping-category-count {
    color: var(--muted);
    font-size: 12px;
  }

  body.page-shopping-list-detail .shopping-row {
    display: grid;
    grid-template-columns: 34px minmax(0, 1fr);
    gap: 9px;
    align-items: start;
    padding: 7px 0;
    border-bottom: 1px solid rgba(148, 163, 184, .12);
    /* Toute la ligne est cliquable en mode courses (cf JS). */
    cursor: pointer;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    border-radius: 8px;
    transition: background 120ms ease, transform 90ms ease;
  }

  /* Retour visuel au tap/clic sur la ligne entière. */
  body.page-shopping-list-detail .shopping-row:active {
    background: var(--hover-bg);
    transform: scale(0.99);
  }

  body.page-shopping-list-detail .shopping-row:last-child {
    border-bottom: 0;
  }

  body.page-shopping-list-detail .shopping-check,
body.page-shopping-list-detail .shopping-edit-check {
    width: 24px;
    height: 24px;
    margin: 2px 0 0;
    accent-color: var(--success);
  }

  body.page-shopping-list-detail .shopping-line-main {
    display: flex;
    align-items: baseline;
    gap: 6px;
    flex-wrap: wrap;
    min-width: 0;
  }

  body.page-shopping-list-detail .shopping-line-name {
    font-size: 17px;
    font-weight: 700;
    word-break: break-word;
  }

  body.page-shopping-list-detail .shopping-line-quantity {
    color: var(--muted);
    font-size: 15px;
  }

  body.page-shopping-list-detail .shopping-row.is-checked .shopping-line-name,
body.page-shopping-list-detail .shopping-row.is-checked .shopping-line-quantity,
body.page-shopping-list-detail .shopping-edit-row.is-checked .shopping-edit-text {
    text-decoration: line-through;
    opacity: .58;
  }

  body.page-shopping-list-detail .shopping-empty-category {
    color: var(--muted);
    font-size: 14px;
    padding: 5px 0 2px 34px;
  }

  body.page-shopping-list-detail .shopping-checked-section {
    display: grid;
    gap: 6px;
    padding: 13px 12px;
    opacity: .85;
  }

  body.page-shopping-list-detail .shopping-checked-section[hidden] {
    display: none;
  }

  body.page-shopping-list-detail .shopping-checked-summary {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    list-style: none;
    font-size: 16px;
    font-weight: 700;
    color: var(--muted);
  }

  body.page-shopping-list-detail .shopping-checked-summary::-webkit-details-marker {
    display: none;
  }

  body.page-shopping-list-detail .shopping-checked-count {
    font-size: 12px;
    font-weight: 600;
    color: var(--muted);
    background: color-mix(in srgb, var(--success) 18%, transparent);
    border-radius: 999px;
    padding: 2px 9px;
  }

  body.page-shopping-list-detail .shopping-checked-list {
    display: grid;
    gap: 0;
    margin-top: 4px;
  }

  body.page-shopping-list-detail .shopping-checked-list .shopping-row {
    border-bottom: 1px solid color-mix(in srgb, var(--border) 45%, transparent);
  }

  body.page-shopping-list-detail .shopping-checked-list .shopping-row:last-child {
    border-bottom: 0;
  }

  body.page-shopping-list-detail .shopping-editor-panel {
    padding: 0;
    overflow: visible;
  }

  body.page-shopping-list-detail .shopping-rich-editor {
    display: grid;
    gap: 8px;
    padding-bottom: 88px;
  }

  body.page-shopping-list-detail .shopping-edit-heading-input {
    width: 100%;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--text);
    font-size: 20px;
    font-weight: 800;
    line-height: 1.2;
    border-radius: 0;
  }

  body.page-shopping-list-detail .shopping-edit-category-title {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 34px;
    gap: 8px;
    align-items: center;
  }

  body.page-shopping-list-detail .shopping-remove-category {
    width: 32px;
    height: 30px;
    min-height: 30px;
    padding: 0;
    border-radius: 999px;
    font-size: 15px;
  }

  body.page-shopping-list-detail .shopping-edit-heading-input:focus {
    outline: none;
    box-shadow: none;
  }

  body.page-shopping-list-detail .shopping-edit-list {
    display: grid;
    gap: 2px;
  }

  body.page-shopping-list-detail .shopping-edit-row {
    display: grid;
    grid-template-columns: 32px minmax(0, 1fr) 34px;
    gap: 8px;
    align-items: start;
    padding: 6px 0;
    border-bottom: 1px solid rgba(148, 163, 184, .10);
  }

  body.page-shopping-list-detail .shopping-edit-row:last-child {
    border-bottom: 0;
  }

  body.page-shopping-list-detail .shopping-edit-text {
    min-height: 28px;
    padding: 1px 0;
    color: var(--text);
    font-size: 17px;
    font-weight: 600;
    line-height: 1.45;
    word-break: break-word;
    outline: none;
  }

  body.page-shopping-list-detail .shopping-edit-text:empty::before {
    content: "Nouvel ingrédient";
    color: var(--muted);
    opacity: .8;
  }

  body.page-shopping-list-detail .shopping-edit-text:focus {
    outline: none;
  }

  body.page-shopping-list-detail .shopping-remove-row,
body.page-shopping-list-detail .shopping-add-line {
    width: 32px;
    height: 30px;
    min-height: 30px;
    padding: 0;
    border-radius: 999px;
    font-size: 15px;
  }

  body.page-shopping-list-detail .shopping-add-line {
    width: auto;
    justify-self: start;
    padding: 0 10px;
    margin-left: 40px;
    color: var(--muted);
  }

  body.page-shopping-list-detail .shopping-edit-empty-note {
    color: var(--muted);
    font-size: 14px;
    margin-left: 40px;
  }

  body.page-shopping-list-detail .shopping-add-category-between {
    display: flex;
    justify-content: center;
    margin: -2px 0;
  }

  body.page-shopping-list-detail .shopping-add-category-btn {
    width: auto;
    min-height: 30px;
    padding: 0 12px;
    border-radius: 999px;
    color: var(--muted);
    font-size: 13px;
  }

  body.page-shopping-list-detail .shopping-float-lock {
    position: fixed;
    right: 14px;
    /* Décalé pour passer au-dessus de la bottom-nav mobile (50px + safe-area)
       + un petit gap visuel de 12px. Sur desktop la bottom-nav est cachée
       donc le bouton revient en position basse standard via le @media plus bas. */
    bottom: calc(50px + env(safe-area-inset-bottom, 0) + 12px);
    z-index: 50;
  }

  @media (min-width: 701px) {
    body.page-shopping-list-detail .shopping-float-lock {
      bottom: 14px;
    }
  }

  body.page-shopping-list-detail .shopping-float-lock .btn {
    width: 52px;
    min-width: 52px;
    height: 52px;
    min-height: 52px;
    padding: 0;
    border-radius: 999px;
    font-size: 22px;
    box-shadow: 0 12px 28px rgba(0,0,0,.35);
  }

  @media (min-width: 761px) {
body.page-shopping-list-detail .container {
      padding-top: 12px;
    }

    body.page-shopping-list-detail .shopping-topbar {
      margin: 0;
      border-radius: 16px;
      border-top: 1px solid var(--border);
    }

}


/* Styles spécifiques : shopping_lists.html */

body.page-shopping-lists .shopping-lists-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 14px;
    margin-bottom: 24px;
  }

  body.page-shopping-lists .shopping-lists-header .page-title {
    margin-bottom: 8px;
  }

  body.page-shopping-lists .shopping-lists-header .page-subtitle {
    margin-bottom: 0;
  }

  body.page-shopping-lists .shopping-create-form {
    margin: 8px 0 0;
    flex: 0 0 auto;
  }

  body.page-shopping-lists .shopping-create-btn {
    min-width: 52px;
    min-height: 52px;
    border-radius: 999px;
    font-size: 20px;
    font-weight: 800;
    white-space: nowrap;
  }

body.page-shopping-lists .shopping-list-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 14px;
  }

  body.page-shopping-lists .shopping-list-card {
    display: grid;
    gap: 12px;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 16px;
  }

  body.page-shopping-lists .shopping-list-card-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
  }

  body.page-shopping-lists .shopping-list-title {
    font-size: 22px;
    font-weight: 800;
    line-height: 1.15;
  }

  body.page-shopping-lists .shopping-list-badges {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
  }

  body.page-shopping-lists .shopping-list-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 10px;
    border-radius: 999px;
    background: var(--panel-2);
    border: 1px solid var(--border);
    color: var(--muted);
    font-size: 13px;
  }

  body.page-shopping-lists .shopping-progress {
    height: 10px;
    overflow: hidden;
    border-radius: 999px;
    background: var(--panel-sunken);
    border: 1px solid var(--border);
  }

  body.page-shopping-lists .shopping-progress > span {
    display: block;
    height: 100%;
    background: var(--success);
  }

  body.page-shopping-lists .shopping-list-actions {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
  }

  body.page-shopping-lists .shopping-list-actions .menu-action,
body.page-shopping-lists .shopping-list-actions form {
    flex: 1 1 140px;
  }

  @media (max-width: 640px) {
body.page-shopping-lists .shopping-lists-header {
      align-items: center;
      gap: 10px;
    }

    body.page-shopping-lists .shopping-create-btn {
      width: 52px;
      min-width: 52px;
      height: 52px;
      padding: 0;
    }

    body.page-shopping-lists .shopping-create-label {
      display: none;
    }

body.page-shopping-lists .shopping-list-grid {
      grid-template-columns: 1fr;
    }

    body.page-shopping-lists .shopping-list-actions {
      display: flex;
      flex-wrap: nowrap;
      align-items: stretch;
      gap: 10px;
    }

    /* Ouvrir occupe l'espace, Supprimer reste compact (plus petit). */
    body.page-shopping-lists .shopping-list-actions > .menu-action {
      flex: 1 1 auto;
    }

    body.page-shopping-lists .shopping-list-actions > form {
      flex: 0 0 auto;
    }

}


/* Feedback tactile des boutons d'authentification/pairing. */

.auth-actions .btn {
    position: relative;
    overflow: hidden;
    transform: translateZ(0);
    transition: transform .07s ease, filter .07s ease, box-shadow .07s ease, opacity .12s ease;
    -webkit-tap-highlight-color: transparent;
  }

  .auth-actions .btn::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: rgba(255,255,255,.14);
    opacity: 0;
    pointer-events: none;
    transition: opacity .08s ease;
  }

  .auth-actions .btn:active,
  .auth-actions .btn.is-pressed {
    transform: translateY(2px) scale(.985);
    filter: brightness(1.14);
    box-shadow:
      inset 0 5px 12px rgba(0,0,0,.34),
      0 0 0 2px rgba(147,197,253,.26);
  }

  .auth-actions .btn:active::before,
  .auth-actions .btn.is-pressed::before {
    opacity: 1;
  }

/* Utilitaires partagés pour éviter les styles inline répétitifs. */
.u-m-0 { margin: 0; }
.u-mt-0 { margin-top: 0; }
.u-mt-6 { margin-top: 6px; }
.u-mt-8 { margin-top: 8px; }
.u-mt-10 { margin-top: 10px; }
.u-mt-14 { margin-top: 14px; }
.u-mb-8 { margin-bottom: 8px; }
.u-mb-10 { margin-bottom: 10px; }
.u-mb-14 { margin-bottom: 14px; }
.u-mb-22 { margin-bottom: 22px; }
.u-cursor-default { cursor: default; }
.u-opacity-soft { opacity: .78; }
.home-card-title { font-size: 24px; font-weight: bold; margin-top: 6px; }


.audit-table td {
  vertical-align: top;
}

.audit-user-agent {
  max-width: 360px;
  margin-top: 6px;
  overflow-wrap: anywhere;
  font-size: 12px;
}


/* CSP-friendly progress bar widths. */
.progress-w-0 { width: 0%; }
.progress-w-1 { width: 1%; }
.progress-w-2 { width: 2%; }
.progress-w-3 { width: 3%; }
.progress-w-4 { width: 4%; }
.progress-w-5 { width: 5%; }
.progress-w-6 { width: 6%; }
.progress-w-7 { width: 7%; }
.progress-w-8 { width: 8%; }
.progress-w-9 { width: 9%; }
.progress-w-10 { width: 10%; }
.progress-w-11 { width: 11%; }
.progress-w-12 { width: 12%; }
.progress-w-13 { width: 13%; }
.progress-w-14 { width: 14%; }
.progress-w-15 { width: 15%; }
.progress-w-16 { width: 16%; }
.progress-w-17 { width: 17%; }
.progress-w-18 { width: 18%; }
.progress-w-19 { width: 19%; }
.progress-w-20 { width: 20%; }
.progress-w-21 { width: 21%; }
.progress-w-22 { width: 22%; }
.progress-w-23 { width: 23%; }
.progress-w-24 { width: 24%; }
.progress-w-25 { width: 25%; }
.progress-w-26 { width: 26%; }
.progress-w-27 { width: 27%; }
.progress-w-28 { width: 28%; }
.progress-w-29 { width: 29%; }
.progress-w-30 { width: 30%; }
.progress-w-31 { width: 31%; }
.progress-w-32 { width: 32%; }
.progress-w-33 { width: 33%; }
.progress-w-34 { width: 34%; }
.progress-w-35 { width: 35%; }
.progress-w-36 { width: 36%; }
.progress-w-37 { width: 37%; }
.progress-w-38 { width: 38%; }
.progress-w-39 { width: 39%; }
.progress-w-40 { width: 40%; }
.progress-w-41 { width: 41%; }
.progress-w-42 { width: 42%; }
.progress-w-43 { width: 43%; }
.progress-w-44 { width: 44%; }
.progress-w-45 { width: 45%; }
.progress-w-46 { width: 46%; }
.progress-w-47 { width: 47%; }
.progress-w-48 { width: 48%; }
.progress-w-49 { width: 49%; }
.progress-w-50 { width: 50%; }
.progress-w-51 { width: 51%; }
.progress-w-52 { width: 52%; }
.progress-w-53 { width: 53%; }
.progress-w-54 { width: 54%; }
.progress-w-55 { width: 55%; }
.progress-w-56 { width: 56%; }
.progress-w-57 { width: 57%; }
.progress-w-58 { width: 58%; }
.progress-w-59 { width: 59%; }
.progress-w-60 { width: 60%; }
.progress-w-61 { width: 61%; }
.progress-w-62 { width: 62%; }
.progress-w-63 { width: 63%; }
.progress-w-64 { width: 64%; }
.progress-w-65 { width: 65%; }
.progress-w-66 { width: 66%; }
.progress-w-67 { width: 67%; }
.progress-w-68 { width: 68%; }
.progress-w-69 { width: 69%; }
.progress-w-70 { width: 70%; }
.progress-w-71 { width: 71%; }
.progress-w-72 { width: 72%; }
.progress-w-73 { width: 73%; }
.progress-w-74 { width: 74%; }
.progress-w-75 { width: 75%; }
.progress-w-76 { width: 76%; }
.progress-w-77 { width: 77%; }
.progress-w-78 { width: 78%; }
.progress-w-79 { width: 79%; }
.progress-w-80 { width: 80%; }
.progress-w-81 { width: 81%; }
.progress-w-82 { width: 82%; }
.progress-w-83 { width: 83%; }
.progress-w-84 { width: 84%; }
.progress-w-85 { width: 85%; }
.progress-w-86 { width: 86%; }
.progress-w-87 { width: 87%; }
.progress-w-88 { width: 88%; }
.progress-w-89 { width: 89%; }
.progress-w-90 { width: 90%; }
.progress-w-91 { width: 91%; }
.progress-w-92 { width: 92%; }
.progress-w-93 { width: 93%; }
.progress-w-94 { width: 94%; }
.progress-w-95 { width: 95%; }
.progress-w-96 { width: 96%; }
.progress-w-97 { width: 97%; }
.progress-w-98 { width: 98%; }
.progress-w-99 { width: 99%; }
.progress-w-100 { width: 100%; }
.progress-h-0 { background: hsl(0, 78%, 46%); }
.progress-h-1 { background: hsl(1, 78%, 46%); }
.progress-h-2 { background: hsl(2, 78%, 46%); }
.progress-h-3 { background: hsl(3, 78%, 46%); }
.progress-h-4 { background: hsl(4, 78%, 46%); }
.progress-h-5 { background: hsl(5, 78%, 46%); }
.progress-h-6 { background: hsl(6, 78%, 46%); }
.progress-h-7 { background: hsl(7, 78%, 46%); }
.progress-h-8 { background: hsl(8, 78%, 46%); }
.progress-h-9 { background: hsl(9, 78%, 46%); }
.progress-h-10 { background: hsl(10, 78%, 46%); }
.progress-h-11 { background: hsl(11, 78%, 46%); }
.progress-h-12 { background: hsl(12, 78%, 46%); }
.progress-h-13 { background: hsl(13, 78%, 46%); }
.progress-h-14 { background: hsl(14, 78%, 46%); }
.progress-h-15 { background: hsl(15, 78%, 46%); }
.progress-h-16 { background: hsl(16, 78%, 46%); }
.progress-h-17 { background: hsl(17, 78%, 46%); }
.progress-h-18 { background: hsl(18, 78%, 46%); }
.progress-h-19 { background: hsl(19, 78%, 46%); }
.progress-h-20 { background: hsl(20, 78%, 46%); }
.progress-h-21 { background: hsl(21, 78%, 46%); }
.progress-h-22 { background: hsl(22, 78%, 46%); }
.progress-h-23 { background: hsl(23, 78%, 46%); }
.progress-h-24 { background: hsl(24, 78%, 46%); }
.progress-h-25 { background: hsl(25, 78%, 46%); }
.progress-h-26 { background: hsl(26, 78%, 46%); }
.progress-h-27 { background: hsl(27, 78%, 46%); }
.progress-h-28 { background: hsl(28, 78%, 46%); }
.progress-h-29 { background: hsl(29, 78%, 46%); }
.progress-h-30 { background: hsl(30, 78%, 46%); }
.progress-h-31 { background: hsl(31, 78%, 46%); }
.progress-h-32 { background: hsl(32, 78%, 46%); }
.progress-h-33 { background: hsl(33, 78%, 46%); }
.progress-h-34 { background: hsl(34, 78%, 46%); }
.progress-h-35 { background: hsl(35, 78%, 46%); }
.progress-h-36 { background: hsl(36, 78%, 46%); }
.progress-h-37 { background: hsl(37, 78%, 46%); }
.progress-h-38 { background: hsl(38, 78%, 46%); }
.progress-h-39 { background: hsl(39, 78%, 46%); }
.progress-h-40 { background: hsl(40, 78%, 46%); }
.progress-h-41 { background: hsl(41, 78%, 46%); }
.progress-h-42 { background: hsl(42, 78%, 46%); }
.progress-h-43 { background: hsl(43, 78%, 46%); }
.progress-h-44 { background: hsl(44, 78%, 46%); }
.progress-h-45 { background: hsl(45, 78%, 46%); }
.progress-h-46 { background: hsl(46, 78%, 46%); }
.progress-h-47 { background: hsl(47, 78%, 46%); }
.progress-h-48 { background: hsl(48, 78%, 46%); }
.progress-h-49 { background: hsl(49, 78%, 46%); }
.progress-h-50 { background: hsl(50, 78%, 46%); }
.progress-h-51 { background: hsl(51, 78%, 46%); }
.progress-h-52 { background: hsl(52, 78%, 46%); }
.progress-h-53 { background: hsl(53, 78%, 46%); }
.progress-h-54 { background: hsl(54, 78%, 46%); }
.progress-h-55 { background: hsl(55, 78%, 46%); }
.progress-h-56 { background: hsl(56, 78%, 46%); }
.progress-h-57 { background: hsl(57, 78%, 46%); }
.progress-h-58 { background: hsl(58, 78%, 46%); }
.progress-h-59 { background: hsl(59, 78%, 46%); }
.progress-h-60 { background: hsl(60, 78%, 46%); }
.progress-h-61 { background: hsl(61, 78%, 46%); }
.progress-h-62 { background: hsl(62, 78%, 46%); }
.progress-h-63 { background: hsl(63, 78%, 46%); }
.progress-h-64 { background: hsl(64, 78%, 46%); }
.progress-h-65 { background: hsl(65, 78%, 46%); }
.progress-h-66 { background: hsl(66, 78%, 46%); }
.progress-h-67 { background: hsl(67, 78%, 46%); }
.progress-h-68 { background: hsl(68, 78%, 46%); }
.progress-h-69 { background: hsl(69, 78%, 46%); }
.progress-h-70 { background: hsl(70, 78%, 46%); }
.progress-h-71 { background: hsl(71, 78%, 46%); }
.progress-h-72 { background: hsl(72, 78%, 46%); }
.progress-h-73 { background: hsl(73, 78%, 46%); }
.progress-h-74 { background: hsl(74, 78%, 46%); }
.progress-h-75 { background: hsl(75, 78%, 46%); }
.progress-h-76 { background: hsl(76, 78%, 46%); }
.progress-h-77 { background: hsl(77, 78%, 46%); }
.progress-h-78 { background: hsl(78, 78%, 46%); }
.progress-h-79 { background: hsl(79, 78%, 46%); }
.progress-h-80 { background: hsl(80, 78%, 46%); }
.progress-h-81 { background: hsl(81, 78%, 46%); }
.progress-h-82 { background: hsl(82, 78%, 46%); }
.progress-h-83 { background: hsl(83, 78%, 46%); }
.progress-h-84 { background: hsl(84, 78%, 46%); }
.progress-h-85 { background: hsl(85, 78%, 46%); }
.progress-h-86 { background: hsl(86, 78%, 46%); }
.progress-h-87 { background: hsl(87, 78%, 46%); }
.progress-h-88 { background: hsl(88, 78%, 46%); }
.progress-h-89 { background: hsl(89, 78%, 46%); }
.progress-h-90 { background: hsl(90, 78%, 46%); }
.progress-h-91 { background: hsl(91, 78%, 46%); }
.progress-h-92 { background: hsl(92, 78%, 46%); }
.progress-h-93 { background: hsl(93, 78%, 46%); }
.progress-h-94 { background: hsl(94, 78%, 46%); }
.progress-h-95 { background: hsl(95, 78%, 46%); }
.progress-h-96 { background: hsl(96, 78%, 46%); }
.progress-h-97 { background: hsl(97, 78%, 46%); }
.progress-h-98 { background: hsl(98, 78%, 46%); }
.progress-h-99 { background: hsl(99, 78%, 46%); }
.progress-h-100 { background: hsl(100, 78%, 46%); }
.progress-h-101 { background: hsl(101, 78%, 46%); }
.progress-h-102 { background: hsl(102, 78%, 46%); }
.progress-h-103 { background: hsl(103, 78%, 46%); }
.progress-h-104 { background: hsl(104, 78%, 46%); }
.progress-h-105 { background: hsl(105, 78%, 46%); }
.progress-h-106 { background: hsl(106, 78%, 46%); }
.progress-h-107 { background: hsl(107, 78%, 46%); }
.progress-h-108 { background: hsl(108, 78%, 46%); }
.progress-h-109 { background: hsl(109, 78%, 46%); }
.progress-h-110 { background: hsl(110, 78%, 46%); }
.progress-h-111 { background: hsl(111, 78%, 46%); }
.progress-h-112 { background: hsl(112, 78%, 46%); }
.progress-h-113 { background: hsl(113, 78%, 46%); }
.progress-h-114 { background: hsl(114, 78%, 46%); }
.progress-h-115 { background: hsl(115, 78%, 46%); }
.progress-h-116 { background: hsl(116, 78%, 46%); }
.progress-h-117 { background: hsl(117, 78%, 46%); }
.progress-h-118 { background: hsl(118, 78%, 46%); }
.progress-h-119 { background: hsl(119, 78%, 46%); }
.progress-h-120 { background: hsl(120, 78%, 46%); }

.checkbox-line {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-weight: normal;
}

.checkbox-line input[type="checkbox"] {
  width: auto;
  margin-top: 3px;
}

/* Styles spécifiques : admin_users.html */
body.page-admin-users .checkbox-line,
.checkbox-line {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 10px;
  font-weight: normal;
  line-height: 1.35;
}

body.page-admin-users .checkbox-line input[type="checkbox"],
.checkbox-line input[type="checkbox"] {
  width: 18px;
  min-width: 18px;
  height: 18px;
  margin: 1px 0 0;
  padding: 0;
  flex: 0 0 auto;
}

.admin-tenant-create-form {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) auto;
  gap: 10px;
  align-items: end;
  margin: 14px 0;
}

.admin-tenant-list {
  display: grid;
  gap: 10px;
}

.admin-tenant-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel-sunken);
}

.admin-tenant-row form {
  margin: 0;
}

.field-help {
  margin-top: 6px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.35;
}

@media (max-width: 800px) {
  .admin-tenant-create-form,
  .admin-tenant-row {
    grid-template-columns: 1fr;
  }

  .admin-tenant-create-form .btn,
  .admin-tenant-row .btn,
  .admin-tenant-row form {
    width: 100%;
  }
}

/* Invitations user → user (panneau admin). Mêmes briques visuelles que la
   liste des espaces. */
.admin-invite-form {
  display: grid;
  gap: 10px;
  margin-bottom: 16px;
}

.admin-invite-list {
  display: grid;
  gap: 10px;
}

.admin-invite-list-title {
  margin: 4px 0 0;
  font-size: 1rem;
}

.admin-invite-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel-sunken);
}

.admin-invite-row form {
  margin: 0;
}

@media (max-width: 640px) {
  .admin-invite-row {
    grid-template-columns: 1fr;
  }

  .admin-invite-row .btn,
  .admin-invite-row form {
    width: 100%;
  }
}

/* Navigation compacte */
.nav-more {
  display: block;
  position: relative;
  margin-left: 2px;
}

.nav-more > summary {
  list-style: none;
}

.nav-more > summary::-webkit-details-marker {
  display: none;
}

.nav-more-summary {
  cursor: pointer;
}

.nav-more-summary .nav-icon {
  display: block;
}

.nav-more-summary .nav-label {
  display: inline-flex;
}

/* Le clic doit TOUJOURS atterrir sur le <summary> (qui toggle le <details>) :
   sinon, suivant la zone touchée (icône / label / padding), un enfant peut
   capter l'événement sans déclencher l'ouverture — d'où la sensation que la
   partie droite du bouton « n'est pas cliquable » sur desktop. */
.nav-more-summary .nav-icon,
.nav-more-summary .nav-label,
.nav-more-summary .nav-icon * {
  pointer-events: none;
}

.nav-more-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 80;
  display: grid;
  gap: 8px;
  min-width: 230px;
  padding: 10px;
  background: var(--topbar-bg);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 18px 42px rgba(0, 0, 0, .35);
}

.nav-more-menu a,
.nav-more-menu .nav-btn {
  width: 100%;
  justify-content: flex-start;
  min-height: 44px;
  padding: 10px 12px;
}

.nav-more-menu form {
  width: 100%;
}

.nav-more-menu .nav-icon,
.nav-more-menu .nav-label {
  display: inline-flex;
}

.nav-login-link .nav-icon {
  display: none;
}

@media (max-width: 900px) {
  .nav-item-home,
  .nav-item-secondary,
  .nav-logout-form {
    display: none !important;
  }


  .nav-more-summary {
    width: 44px;
    min-width: 44px;
    height: 44px;
    padding: 0;
  }

  .nav-more-summary .nav-label {
    display: none;
  }

  .nav-more[open] .nav-more-summary {
    background: var(--primary);
  }

  .nav-more-menu {
    max-width: calc(100vw - 24px);
  }

  .nav-more-menu .nav-icon {
    display: block;
  }

  .nav-more-menu .nav-label {
    display: inline-flex;
  }

  .nav-more-menu .nav-btn {
    color: var(--text);
  }

  .nav-login-link .nav-icon {
    display: block;
  }
}

.touch-pair-expiry {
  color: #fbbf24;
}

/* ============================================================== */
/* Bottom nav mobile — pattern app native (Instagram/Notion).      */
/* Cachée par défaut, activée sur ≤700px (en remplacement de la    */
/* topbar qui devient elle-même cachée à ce breakpoint).           */
/* ============================================================== */

.bottom-nav {
  display: none;
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 50;
  background: var(--topbar-bg);
  border-top: 1px solid var(--border);
  padding-bottom: env(safe-area-inset-bottom, 0);
  box-shadow: 0 -2px 12px var(--shadow-color, rgba(0, 0, 0, 0.20));
}

.bottom-nav-item {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 5px 4px;
  min-height: 50px;
  color: var(--muted);
  text-decoration: none;
  font-size: 11px;
  background: transparent;
  border: 0;
  cursor: pointer;
  transition: color 0.12s ease, background 0.12s ease;
  position: relative;
}

/* :focus-visible toujours actif (accessibilité clavier). Le :hover est
   isolé dans @media (hover: hover) : sur iOS Safari, un :hover sur un
   lien provoque le « double-tap » (1er tap = applique le hover, 2e tap =
   suit le lien). En le réservant aux appareils à vraie souris, le tap
   tactile navigue du 1er coup (le :active ci-dessous gère le feedback). */
.bottom-nav-item:focus-visible {
  color: var(--text);
  outline: none;
  background: var(--hover-bg);
}

@media (hover: hover) {
  .bottom-nav-item:hover {
    color: var(--text);
    background: var(--hover-bg);
  }
}

.bottom-nav-item.is-active {
  color: var(--primary);
}

/* Petit indicateur barre en haut de l'onglet actif (pattern Notion) */
.bottom-nav-item.is-active::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 28px;
  height: 3px;
  background: var(--primary);
  border-radius: 0 0 3px 3px;
}

.bottom-nav-icon {
  display: inline-flex;
  width: 22px;
  height: 22px;
  align-items: center;
  justify-content: center;
}

.bottom-nav-icon svg {
  width: 100%;
  height: 100%;
}

/* Barre nav mobile : icônes seules, sans libellés (demandé — « on s'en fiche
   du texte »). La barre n'existe qu'en ≤700px, donc display:none global suffit.
   Les libellés du bottom-sheet (.bottom-nav-sheet-item) ne sont PAS touchés. */
.bottom-nav-label {
  display: none;
}

/* Raccourci « + » création rapide (mobile) : pastille verte pour distinguer
   l'action de la navigation. Pas d'état actif (ce n'est pas un onglet). */
.bottom-nav-add-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: var(--success);
  color: #fff;
  box-shadow: 0 2px 8px color-mix(in srgb, var(--success) 45%, transparent);
}

.bottom-nav-add-icon .ico {
  width: 18px;
  height: 18px;
}

.bottom-nav-add .bottom-nav-label {
  color: var(--success);
}

/* Onglet "Plus" : <details> qui ouvre un bottom sheet par-dessus. */

.bottom-nav-more {
  /* details par défaut a display: block — on doit forcer le comportement
     d'onglet (column flex). */
  display: flex !important;
}

.bottom-nav-more > .bottom-nav-more-summary {
  list-style: none;
  user-select: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  flex: 1 1 0;
  padding: 5px 4px;
  min-height: 50px;
  color: var(--muted);
  font-size: 11px;
}

.bottom-nav-more-summary::-webkit-details-marker { display: none; }
.bottom-nav-more-summary::marker { content: ""; }

.bottom-nav-more[open] > .bottom-nav-more-summary {
  color: var(--primary);
}

/* Backdrop + sheet : seulement visibles quand le details est ouvert. */

.bottom-nav-sheet-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease;
  z-index: 60;
}

.bottom-nav-more[open] .bottom-nav-sheet-backdrop {
  opacity: 1;
  pointer-events: auto;
}

.bottom-nav-sheet {
  position: fixed;
  left: 0;
  right: 0;
  /* Le sheet vient se poser AU-DESSUS de la bottom-nav.
     La nav fait min-height 50 + border-top 1 + safe-area, et selon le
     browser (PWA standalone vs Chrome mobile) peut s'étendre un peu
     plus. Buffer généreux pour aussi laisser visible la barre
     indicatrice 3px du tab actif (::before top:0 sur "Plus"). */
  bottom: calc(62px + env(safe-area-inset-bottom, 0));
  z-index: 70;
  background: var(--panel);
  border-top-left-radius: 18px;
  border-top-right-radius: 18px;
  border-top: 1px solid var(--border);
  /* Pas de padding-bottom : le sheet colle directement au top de la
     bottom-nav (qui assure déjà l'espace en dessous via son propre
     padding + safe-area). Évite le gap visuel entre les deux. */
  padding: 0 6px 0;
  box-shadow: 0 -8px 30px var(--shadow-color, rgba(0, 0, 0, 0.35));
  /* translate3d (au lieu de translateY) force un composite layer GPU dès
     le départ → le sheet est pré-rendu hors du layout normal, plus de
     flash où il apparaît brièvement dans la cellule du <details> avant
     de prendre sa position fixed pleine largeur. */
  transform: translate3d(0, calc(100% + 62px + env(safe-area-inset-bottom, 0)), 0);
  transition: transform 0.22s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform;
  max-height: calc(80vh - 62px - env(safe-area-inset-bottom, 0));
  overflow-y: auto;
}

.bottom-nav-more[open] .bottom-nav-sheet {
  transform: translate3d(0, 0, 0);
}

.bottom-nav-sheet-handle {
  width: 40px;
  height: 4px;
  margin: 8px auto 4px;
  background: var(--border);
  border-radius: 2px;
}

.bottom-nav-sheet-header {
  padding: 8px 14px 6px;
}

.bottom-nav-sheet-title {
  font-weight: 600;
  font-size: 14px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Footer : "Se déconnecter" à gauche prend toute la place restante,
   bouton × en bas-droite — proche du pouce qui a tapé "Plus" (4e onglet
   à droite de la bottom-nav). Évite tout missclick sur la déconnexion. */
.bottom-nav-sheet-footer {
  display: flex;
  align-items: stretch;
  gap: 10px;
  margin-top: 8px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

.bottom-nav-sheet-footer .bottom-nav-sheet-form {
  flex: 1 1 auto;
}

.bottom-nav-sheet-footer .bottom-nav-sheet-item {
  width: 100%;
}

.bottom-nav-sheet-close {
  flex: 0 0 auto;
  width: 56px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  color: var(--text);
  font-size: 26px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease, transform 0.12s ease;
}

.bottom-nav-sheet-close:hover,
.bottom-nav-sheet-close:focus-visible {
  background: var(--hover-bg);
  border-color: var(--primary);
  outline: none;
}

.bottom-nav-sheet-close:active {
  transform: scale(0.94);
}

.bottom-nav-sheet-item {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 14px 14px;
  border-radius: 12px;
  color: var(--text);
  text-decoration: none;
  font-size: 15px;
  background: transparent;
  border: 0;
  cursor: pointer;
  text-align: left;
  transition: background 0.12s ease;
}

.bottom-nav-sheet-item:focus-visible {
  background: var(--hover-bg);
  outline: none;
}

@media (hover: hover) {
  .bottom-nav-sheet-item:hover {
    background: var(--hover-bg);
  }
}

.bottom-nav-sheet-item-danger {
  color: var(--danger);
}

.bottom-nav-sheet-icon {
  font-size: 22px;
  width: 28px;
  text-align: center;
  flex-shrink: 0;
}

.bottom-nav-sheet-form {
  margin: 0;
}

/* Activation à ≤700px ----------------------------------------- */

@media (max-width: 700px) {
  /* Topbar cachée — la bottom nav prend le relais */
  .topbar {
    display: none;
  }

  /* Bottom nav visible */
  .bottom-nav {
    display: flex;
  }

  /* Réserver de l'espace en bas du contenu pour ne pas être recouvert
     par la bottom nav (50px hauteur + safe-area iOS) + un buffer de
     16px pour que les boutons en bas de page (Enregistrer, etc.) ne
     soient pas collés à la nav. */
  body {
    padding-bottom: calc(50px + env(safe-area-inset-bottom, 0) + 16px);
  }
}

/* ============================================================== */
/* Pages /menu/* — admin mobile-first.                             */
/* Style "appli pro" : hero card, cards horizontales avec photo,   */
/* chips d'accompagnements, contrôles tactiles 44px minimum.       */
/* ============================================================== */

.menu-inline-form {
  margin: 0;
  display: inline-flex;
}

/* Hero card ----------------------------------------------------- */

.menu-hero {
  position: relative;
  /* Halo décoratif en haut à droite via radial-gradient stacké sur le
     linear, clippé naturellement par le border-radius — pas besoin
     d'overflow: hidden (qui empêcherait les dropdowns enfants comme
     le filtre durée de déborder). */
  background:
    radial-gradient(
      circle at calc(100% - 50px) -10px,
      color-mix(in srgb, var(--primary) 12%, transparent) 0%,
      transparent 35%
    ),
    linear-gradient(135deg, var(--panel) 0%, var(--panel-2) 100%);
  border: 1px solid var(--border);
  border-radius: 18px;
  padding: 22px 22px 18px;
  margin-bottom: 18px;
  box-shadow: 0 6px 20px var(--shadow-color, rgba(0, 0, 0, 0.18));
}

.menu-hero-inner {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  position: relative;
}

/* .menu-hero-inner ne contient que {h1 titre | filtre durée} en row.
   Le H1 (block par défaut) devient flex item — il prend sa largeur
   naturelle (pas 100% comme en block), le filtre durée vient juste
   après lui, collé. */
.menu-hero-duration {
  flex: 0 0 auto;
  max-width: 100%;
}

/* Subtitle sort de l'inner pour être sur sa propre ligne en dessous
   — il n'élargit donc pas la ligne titre+durée. */
.menu-hero-subtitle {
  margin: 8px 0 0;
  color: var(--muted);
  font-size: 15px;
  line-height: 1.4;
}

/* Toolbar (recherche / panier / mémoire / vider) sur sa propre ligne
   en dessous du bloc titre, alignée à gauche. */
.menu-hero-toolbar {
  margin-top: 14px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  position: relative;
  justify-content: flex-start;
}

.menu-hero-title {
  margin: 0;
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text);
}

/* Le CTA "Proposer un menu" est maintenant SOUS le bloc inner
   (titre + toolbar), en pleine largeur du hero. */
.menu-hero-cta-form {
  width: 100%;
  margin-top: 16px;
}

.menu-hero-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: 100%;
  padding: 14px 22px;
  min-height: 56px;
  background: var(--primary);
  color: #ffffff;
  border: 0;
  border-radius: 14px;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 6px 16px color-mix(in srgb, var(--primary) 35%, transparent);
  transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
}

.menu-hero-cta:hover,
.menu-hero-cta:focus-visible {
  background: var(--primary-hover);
  transform: translateY(-1px);
  box-shadow: 0 8px 22px color-mix(in srgb, var(--primary) 40%, transparent);
  outline: none;
}

.menu-hero-cta:active {
  transform: translateY(0);
  box-shadow: 0 4px 12px color-mix(in srgb, var(--primary) 30%, transparent);
}

.menu-hero-cta-emoji {
  font-size: 22px;
  line-height: 1;
}

.menu-hero-cta-label {
  white-space: nowrap;
}

.menu-toolbar-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 14px;
  background: var(--panel-sunken);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 14px;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}

.menu-toolbar-btn:hover,
.menu-toolbar-btn:focus-visible {
  background: var(--hover-bg);
  border-color: var(--primary);
  outline: none;
}

.menu-toolbar-btn-danger:hover,
.menu-toolbar-btn-danger:focus-visible {
  border-color: var(--danger);
}

/* Variant "primary" du bouton toolbar (utilisé pour signaler l'action
   suivante : préparer la liste de courses). Fond neutre comme les autres
   boutons toolbar, mais bordure épaisse couleur primary du thème — le
   bouton se démarque visuellement sans changer la palette générale. */
.menu-toolbar-btn-primary {
  border-width: 2px;
  border-color: var(--primary);
  color: var(--primary);
  font-weight: 600;
}

.menu-toolbar-btn-primary:hover,
.menu-toolbar-btn-primary:focus-visible {
  border-color: var(--primary-hover);
  color: var(--primary-hover);
}

/* Filtres durée -------------------------------------------------- */

.menu-filter {
  position: relative;
}

.menu-filter-summary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 40px;
  padding: 0 14px;
  background: var(--panel-sunken);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 14px;
  cursor: pointer;
  list-style: none;
  user-select: none;
}

.menu-filter-summary::-webkit-details-marker { display: none; }
.menu-filter-summary::marker { content: ""; }

.menu-filter-summary:hover,
.menu-filter-summary:focus-visible {
  background: var(--hover-bg);
  border-color: var(--primary);
  outline: none;
}

.menu-filter-active {
  border-color: var(--primary);
  color: var(--primary);
}

.menu-filter[open] > .menu-filter-summary {
  background: var(--hover-bg);
  border-color: var(--primary);
}

.menu-filter-form {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 30;
  min-width: 220px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px;
  box-shadow: 0 10px 30px var(--shadow-color, rgba(0, 0, 0, 0.25));
}

.menu-filter-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}

.menu-filter-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 13px;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}

@media (hover: hover) {
  .menu-filter-pill:hover {
    border-color: var(--primary);
  }
}

.menu-filter-pill input { accent-color: var(--primary); }

.menu-filter-pill:has(input:checked) {
  background: var(--primary);
  color: #ffffff;
  border-color: var(--primary);
}

.menu-filter-actions {
  display: flex;
  justify-content: flex-end;
}

/* Sections ------------------------------------------------------- */

.menu-section {
  margin-top: 24px;
}

.menu-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.menu-section-title {
  margin: 0 0 12px;
  font-size: 18px;
  font-weight: 600;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 10px;
}

.menu-section-head .menu-section-title {
  margin-bottom: 0;
}

.menu-section-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 22px;
  padding: 0 8px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 12px;
  color: var(--muted);
  font-weight: 500;
}

.menu-stack {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Empty state ---------------------------------------------------- */

.menu-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 28px 18px;
  background: var(--panel);
  border: 1px dashed var(--border);
  border-radius: 14px;
  text-align: center;
  color: var(--muted);
}

.menu-empty-emoji {
  font-size: 32px;
  opacity: 0.6;
}

.menu-empty-text {
  font-size: 14px;
  max-width: 320px;
}

/* Cards menu ----------------------------------------------------- */

.menu-card {
  position: relative;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 14px;
  box-shadow: 0 2px 8px var(--shadow-color, rgba(0, 0, 0, 0.12));
  transition: border-color 0.12s ease, transform 0.12s ease;
}

.menu-card:hover {
  border-color: var(--primary);
}

.menu-card-suggestion {
  border-color: var(--primary);
  background: linear-gradient(135deg, var(--panel) 0%, var(--panel) 60%, var(--panel-2) 100%);
}

.menu-badge {
  position: absolute;
  top: -10px;
  left: 14px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  background: var(--primary);
  color: #ffffff;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  box-shadow: 0 4px 10px color-mix(in srgb, var(--primary) 35%, transparent);
}

.menu-card-body {
  display: grid;
  grid-template-columns: 96px 1fr;
  gap: 14px;
  align-items: start;
}

.menu-card-body-noimg {
  grid-template-columns: 1fr;
}

.menu-card-thumb-link {
  display: block;
  border-radius: 12px;
  overflow: hidden;
  transition: transform 0.12s ease;
}

.menu-card-thumb-link:hover {
  transform: scale(1.02);
}

.menu-card-content {
  min-width: 0;
}

.menu-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 4px;
}

.menu-card-title {
  font-size: 17px;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  line-height: 1.25;
  flex: 1 1 auto;
  min-width: 0;
  word-break: break-word;
}

.menu-card-title:hover {
  color: var(--primary);
}

.menu-card-title-muted {
  color: var(--muted);
}

.menu-card-meta {
  margin-bottom: 8px;
  font-size: 13px;
  color: var(--muted);
}

/* Thumbnails ----------------------------------------------------- */

.menu-thumb {
  position: relative;
  width: 96px;
  height: 96px;
  border-radius: 12px;
  overflow: hidden;
  background: var(--panel-2);
  border: 1px solid var(--border);
  flex-shrink: 0;
}

.menu-thumb-lg {
  width: 96px;
  height: 96px;
}

.menu-thumb-sm {
  width: 56px;
  height: 56px;
}

.menu-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.menu-thumb-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--panel-2) 0%, var(--panel-sunken) 100%);
}

.menu-thumb-fallback {
  font-size: 32px;
  opacity: 0.4;
}

.menu-thumb-sm .menu-thumb-fallback {
  font-size: 22px;
}

/* Servings stepper ---------------------------------------------- */

.menu-servings {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 999px;
  flex-shrink: 0;
}

.menu-servings-btn {
  /* Bouton visible 36px (compact pour le stepper) avec zone de tap
     étendue à 44px via pseudo ::after (recommandation Apple/Google
     pour les accessibilité tactile). */
  position: relative;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  border-radius: 50%;
  color: var(--text);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.12s ease;
}

.menu-servings-btn::after {
  content: "";
  position: absolute;
  inset: -4px;
}

.menu-servings-btn:hover,
.menu-servings-btn:focus-visible {
  background: var(--hover-bg);
  outline: none;
}

.menu-servings-value {
  display: inline-flex;
  align-items: baseline;
  gap: 1px;
  min-width: 30px;
  justify-content: center;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}

.menu-servings-unit {
  font-size: 11px;
  color: var(--muted);
  font-weight: 500;
}

/* Vague 11 — recettes liées génériques (card menu) ---------------- */

.menu-linked-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  margin-top: 8px;
  padding: 6px 12px;
  background: var(--panel-2);
  border: 1px dashed var(--border);
  border-radius: 999px;
  font-size: 13px;
  color: var(--muted);
  text-decoration: none;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

.menu-linked-btn:hover,
.menu-linked-btn:focus-visible {
  border-color: var(--primary);
  color: var(--text);
  background: var(--hover-bg);
  outline: none;
}

.menu-linked-btn.is-active {
  border-style: solid;
  border-color: var(--primary);
  color: var(--text);
}

.menu-linked-btn-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--primary);
  color: #ffffff;
  font-size: 11px;
  font-weight: 700;
}

/* Picker recettes liées — lignes à cocher (multi-sélection) ------- */

.menu-picker-row-check {
  cursor: pointer;
}

.menu-picker-row-checkbox {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  accent-color: var(--primary);
  cursor: pointer;
}

.menu-picker-row-tick {
  flex: 0 0 auto;
  display: inline-flex;
  margin-left: auto;
  color: var(--primary);
  opacity: 0;
  transition: opacity 0.12s ease;
}

.menu-picker-row-check:has(.menu-picker-row-checkbox:checked) {
  border-color: var(--primary);
}

.menu-picker-row-check:has(.menu-picker-row-checkbox:checked) .menu-picker-row-tick {
  opacity: 1;
}

.menu-picker-list-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 14px;
}

/* Fiche recette — bloc « Recettes liées » (navigation) ----------- */

.menu-recipe-linked {
  margin: 0 0 18px;
}

.menu-recipe-linked-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.menu-recipe-linked-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  text-decoration: none;
  color: var(--text);
  transition: background 0.12s ease, border-color 0.12s ease;
}

.menu-recipe-linked-card:hover,
.menu-recipe-linked-card:focus-visible {
  border-color: var(--primary);
  background: var(--hover-bg);
  outline: none;
}

.menu-recipe-linked-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1 1 auto;
}

.menu-recipe-linked-name {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.menu-recipe-linked-meta {
  font-size: 12px;
  color: var(--muted);
}

.menu-recipe-linked-arrow {
  flex: 0 0 auto;
  display: inline-flex;
  color: var(--muted);
}

/* Actions card --------------------------------------------------- */

.menu-card-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}

/* Quand on a un stepper personnes dans les actions (cards "sélection"),
   on pousse le stepper à gauche et le bouton "Retirer" à droite via
   justify-content: space-between. */
.menu-card-actions:has(.menu-servings) {
  justify-content: space-between;
}

.menu-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 14px;
  background: var(--panel-sunken);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

.menu-action:hover,
.menu-action:focus-visible {
  background: var(--hover-bg);
  border-color: var(--primary);
  outline: none;
}

.menu-action-primary {
  background: var(--primary);
  color: #ffffff;
  border-color: var(--primary);
}

.menu-action-primary:hover,
.menu-action-primary:focus-visible {
  background: var(--primary-hover);
  border-color: var(--primary-hover);
}

.menu-action-success {
  background: var(--success);
  color: #ffffff;
  border-color: var(--success);
}

.menu-action-success:hover,
.menu-action-success:focus-visible {
  background: var(--success-hover);
  border-color: var(--success-hover);
}

.menu-action-ghost {
  background: transparent;
}

/* Action destructive (ex. Supprimer dans /recipes) : rouge dès le
   repos pour signaler le danger, fond plein au survol. Le :hover est
   isolé dans @media (hover: hover) — sinon iOS Safari demande un
   double-tap (cf note bottom-nav dans la ROADMAP). */
.menu-action-danger {
  color: var(--danger);
  border-color: var(--danger);
}

.menu-action-danger:focus-visible {
  background: var(--danger);
  color: #ffffff;
  border-color: var(--danger);
  outline: none;
}

@media (hover: hover) {
  .menu-action-danger:hover {
    background: var(--danger);
    color: #ffffff;
    border-color: var(--danger);
  }
}

.menu-action-label {
  white-space: nowrap;
}

/* Picker page --------------------------------------------------- */

.menu-picker-header {
  margin-bottom: 18px;
}

.menu-picker-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  margin-bottom: 12px;
  font-size: 14px;
  color: var(--muted);
  text-decoration: none;
  border-radius: 8px;
  transition: background 0.12s ease, color 0.12s ease;
}

.menu-picker-back:hover {
  background: var(--hover-bg);
  color: var(--text);
}

.menu-picker-title {
  margin: 0 0 4px;
  font-size: 22px;
  font-weight: 700;
  color: var(--text);
}

.menu-picker-subtitle {
  margin: 0;
  color: var(--muted);
  font-size: 14px;
}

.menu-picker-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.menu-picker-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  transition: border-color 0.12s ease, transform 0.12s ease;
}

.menu-picker-row:hover {
  border-color: var(--primary);
}

.menu-picker-row-none {
  grid-template-columns: 1fr auto;
  background: var(--panel-sunken);
  border-style: dashed;
}

.menu-picker-row-info {
  min-width: 0;
}

.menu-picker-row-name {
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
}

.menu-picker-row-meta {
  margin-top: 2px;
  font-size: 12px;
  color: var(--muted);
}

.menu-picker-row-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* Page ingredients --------------------------------------------- */

.menu-ingredients-hero {
  margin-bottom: 18px;
}

.menu-ingredients-hero-inner {
  background: linear-gradient(135deg, var(--panel) 0%, var(--panel-2) 100%);
  border: 1px solid var(--border);
  border-radius: 18px;
  padding: 20px 22px;
  box-shadow: 0 4px 14px var(--shadow-color, rgba(0, 0, 0, 0.15));
}

.menu-ingredients-title {
  margin: 0 0 6px;
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text);
}

.menu-ingredients-subtitle {
  margin: 0;
  color: var(--muted);
  font-size: 14px;
}

.menu-ingredients-form {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.menu-ingredients-categories {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.menu-ingredient-cat {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 14px 16px;
  box-shadow: 0 2px 8px var(--shadow-color, rgba(0, 0, 0, 0.10));
}

.menu-ingredient-cat-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-bottom: 10px;
  margin-bottom: 8px;
  border-bottom: 1px solid var(--border);
}

.menu-ingredient-cat-emoji {
  font-size: 22px;
  line-height: 1;
}

.menu-ingredient-cat-title {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  flex: 1 1 auto;
}

.menu-ingredient-cat-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 22px;
  padding: 0 8px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 12px;
  color: var(--muted);
  font-weight: 500;
}

.menu-ingredient-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.menu-ingredient-row {
  border-radius: 8px;
}

.menu-ingredient-row + .menu-ingredient-row {
  border-top: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
}

.menu-ingredient-label {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 6px;
  cursor: pointer;
  min-height: 44px;
  transition: background 0.12s ease;
  border-radius: 8px;
}

.menu-ingredient-label:hover {
  background: var(--hover-bg);
}

.menu-ingredient-check {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
  pointer-events: none;
}

.menu-ingredient-checkmark {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  border: 2px solid var(--border);
  background: var(--panel-sunken);
  position: relative;
  transition: background 0.12s ease, border-color 0.12s ease;
}

.menu-ingredient-checkmark::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 6px;
  width: 6px;
  height: 11px;
  border-right: 2.5px solid #ffffff;
  border-bottom: 2.5px solid #ffffff;
  transform: rotate(45deg) scale(0);
  transition: transform 0.12s ease;
}

.menu-ingredient-check:checked + .menu-ingredient-checkmark {
  background: var(--primary);
  border-color: var(--primary);
}

.menu-ingredient-check:checked + .menu-ingredient-checkmark::after {
  transform: rotate(45deg) scale(1);
}

.menu-ingredient-check:focus-visible + .menu-ingredient-checkmark {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

.menu-ingredient-text {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex: 1 1 auto;
  min-width: 0;
  flex-wrap: wrap;
}

.menu-ingredient-name {
  font-size: 15px;
  color: var(--text);
  font-weight: 500;
}

.menu-ingredient-check:not(:checked) ~ .menu-ingredient-text .menu-ingredient-name {
  color: var(--muted);
  text-decoration: line-through;
  text-decoration-color: color-mix(in srgb, var(--muted) 50%, transparent);
}

.menu-ingredient-qty {
  font-size: 13px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.menu-ingredients-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 14px;
  position: sticky;
  bottom: 12px;
  box-shadow: 0 6px 20px var(--shadow-color, rgba(0, 0, 0, 0.20));
  z-index: 5;
}

.menu-ingredients-actions .menu-action {
  min-height: 48px;
  font-size: 15px;
}

.menu-empty-link {
  color: var(--primary);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.menu-empty-link:hover {
  color: var(--primary-hover);
}

/* Page manual --------------------------------------------------- */

.menu-manual-hero {
  margin-bottom: 18px;
}

.menu-manual-hero-inner {
  background:
    radial-gradient(
      circle at calc(100% - 50px) -10px,
      color-mix(in srgb, var(--primary) 10%, transparent) 0%,
      transparent 35%
    ),
    linear-gradient(135deg, var(--panel) 0%, var(--panel-2) 100%);
  border: 1px solid var(--border);
  border-radius: 18px;
  padding: 20px 22px;
  box-shadow: 0 4px 14px var(--shadow-color, rgba(0, 0, 0, 0.15));
}

.menu-manual-hero-head {
  margin-bottom: 16px;
}

.menu-manual-title {
  margin: 0 0 6px;
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text);
}

.menu-manual-subtitle {
  margin: 0;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.4;
}

.menu-manual-search {
  display: flex;
  gap: 10px;
  margin-bottom: 14px;
}

.menu-manual-search-field {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0 14px;
  min-height: 48px;
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}

.menu-manual-search-field:focus-within {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 18%, transparent);
}

.menu-manual-search-icon {
  font-size: 16px;
  margin-right: 10px;
  color: var(--muted);
  flex-shrink: 0;
}

.menu-manual-search-input {
  flex: 1 1 auto;
  min-width: 0;
  background: transparent;
  border: 0;
  outline: none;
  color: var(--text);
  font-size: 15px;
  padding: 0;
  min-height: 44px;
}

.menu-manual-search-input::placeholder {
  color: var(--muted);
  opacity: 0.7;
}

.menu-manual-search-input::-webkit-search-cancel-button {
  display: none;
}

.menu-manual-search-clear {
  /* Bouton 32px visible + zone tap 44 via ::after (le bouton croix
     est petit pour rester compact dans le champ recherche). */
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  margin-left: 8px;
  background: var(--panel-2);
  border-radius: 50%;
  color: var(--muted);
  font-size: 18px;
  line-height: 1;
  text-decoration: none;
  flex-shrink: 0;
  transition: background 0.12s ease, color 0.12s ease;
}

.menu-manual-search-clear::after {
  content: "";
  position: absolute;
  inset: -6px;
}

.menu-manual-search-clear:hover {
  background: var(--danger);
  color: #ffffff;
}

.menu-manual-search-submit {
  flex-shrink: 0;
}

.menu-manual-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* Filtres types : panneau plus large avec liste scrollable */

.menu-filter-form-types {
  min-width: 260px;
  max-height: 70vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.menu-filter-types-actions {
  display: flex;
  gap: 8px;
  margin-bottom: 10px;
}

.menu-filter-types-actions .menu-action {
  flex: 1 1 0;
  min-height: 36px;
  font-size: 13px;
}

.menu-filter-types-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 12px;
  max-height: 45vh;
  overflow-y: auto;
  padding-right: 4px;
  /* Scrollbar discrète mais visible (utile vu le grand nombre de types) */
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

.menu-filter-types-list::-webkit-scrollbar {
  width: 6px;
}

.menu-filter-types-list::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 999px;
}

.menu-filter-pill-wide {
  width: 100%;
  justify-content: flex-start;
  padding: 10px 12px;
  border-radius: 8px;
  cursor: pointer;
}

/* Cards résultats (héritent de .menu-card mais variant compact) */

.menu-card-result .menu-card-actions {
  border-top: 1px solid var(--border);
}

/* Page recipe (lecture seule) ----------------------------------- */

.menu-recipe-hero {
  margin-bottom: 18px;
}

.menu-recipe-hero-inner {
  background:
    radial-gradient(
      circle at calc(100% - 50px) -10px,
      color-mix(in srgb, var(--primary) 10%, transparent) 0%,
      transparent 35%
    ),
    linear-gradient(135deg, var(--panel) 0%, var(--panel-2) 100%);
  border: 1px solid var(--border);
  border-radius: 18px;
  padding: 22px;
  box-shadow: 0 4px 14px var(--shadow-color, rgba(0, 0, 0, 0.15));
}

.menu-recipe-hero-with-photo {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 22px;
  align-items: center;
  padding: 18px;
}

.menu-recipe-photo {
  margin: 0;
  border-radius: 14px;
  overflow: hidden;
  background: var(--panel-2);
  aspect-ratio: 1 / 1;
  position: relative;
}

.menu-recipe-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.menu-recipe-head {
  min-width: 0;
}

.menu-recipe-title {
  margin: 0 0 10px;
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text);
  line-height: 1.15;
  word-break: break-word;
}

/* Titre + bouton « Modifier » sur une même ligne (le titre prend l'espace,
   le bouton reste en haut à droite). Libère la ligne d'actions pour que le
   stepper personnes + le bouton « Courses » tiennent côte à côte sur tel. */
.menu-recipe-title-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

.menu-recipe-title-row .menu-recipe-title {
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
}

.menu-recipe-edit-btn {
  flex: 0 0 auto;
}

.menu-recipe-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 14px;
}

.menu-recipe-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 13px;
  color: var(--text);
}

.menu-recipe-badge-servings {
  background: color-mix(in srgb, var(--primary) 12%, var(--panel-sunken));
  border-color: color-mix(in srgb, var(--primary) 40%, var(--border));
  color: var(--primary);
  font-weight: 600;
}

.menu-recipe-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 8px;
}

/* Sur mobile, le bouton « Courses » de la fiche est réduit à son icône
   (libellé masqué) pour que stepper + Modifier + Courses tiennent sur une
   ligne. Le bouton reste accessible via aria-label/title. */
@media (max-width: 640px) {
  .menu-recipe-courses-btn .menu-recipe-courses-label {
    display: none;
  }
}

/* Cards ingrédients / consignes */

.menu-recipe-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 18px 20px;
  margin-bottom: 14px;
  box-shadow: 0 2px 8px var(--shadow-color, rgba(0, 0, 0, 0.10));
}

/* Tabs Ingrédients / Consignes — pattern segmented control. */
.menu-recipe-tabs {
  display: flex;
  gap: 4px;
  padding: 4px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 14px;
  margin-bottom: 14px;
  /* Collant sous la topbar : on garde le switch Ingrédients / Consignes
     accessible quand on scrolle dans la recette (--topbar-h posé par
     admin_common.js). Fond opaque → le contenu passe dessous proprement. */
  position: sticky;
  top: calc(var(--topbar-h, 0px) + 6px);
  z-index: 15;
}

.menu-recipe-tab {
  flex: 1 1 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 14px;
  background: transparent;
  border: 0;
  border-radius: 10px;
  color: var(--muted);
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}

.menu-recipe-tab:hover,
.menu-recipe-tab:focus-visible {
  color: var(--text);
  outline: none;
}

.menu-recipe-tab.is-active {
  background: var(--panel);
  color: var(--primary);
  font-weight: 600;
  box-shadow: 0 1px 3px var(--shadow-color, rgba(0, 0, 0, 0.10));
}

.menu-recipe-tab-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 20px;
  padding: 0 7px;
  background: var(--panel-2);
  border-radius: 999px;
  font-size: 12px;
  color: var(--muted);
  font-weight: 500;
}

.menu-recipe-tab.is-active .menu-recipe-tab-count {
  background: color-mix(in srgb, var(--primary) 14%, transparent);
  color: var(--primary);
}

/* Stepper personnes dans la rangée d'actions, à côté du bouton
   Modifier. Bordure primary subtile pour signaler son interactivité
   et le distinguer visuellement du bouton ghost à côté. */
.menu-recipe-actions .menu-recipe-servings {
  border: 1px solid color-mix(in srgb, var(--primary) 35%, var(--border));
}

.menu-recipe-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding-bottom: 12px;
  margin-bottom: 14px;
  border-bottom: 1px solid var(--border);
}

.menu-recipe-card-title {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
  color: var(--text);
}

/* Stepper personnes pour la carte ingrédients */

.menu-recipe-servings {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 999px;
  flex-shrink: 0;
}

.menu-recipe-servings-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  background: transparent;
  border: 0;
  border-radius: 50%;
  color: var(--text);
  font-size: 18px;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.12s ease;
}

.menu-recipe-servings-btn:hover,
.menu-recipe-servings-btn:focus-visible {
  background: var(--hover-bg);
  outline: none;
}

.menu-recipe-servings-btn.is-disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.menu-recipe-servings-value {
  display: inline-flex;
  align-items: baseline;
  gap: 1px;
  min-width: 34px;
  justify-content: center;
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
}

.menu-recipe-servings-unit {
  font-size: 11px;
  color: var(--muted);
  font-weight: 500;
}

/* Liste ingrédients */

.menu-recipe-ingredients {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.menu-recipe-ingredient {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px dashed color-mix(in srgb, var(--border) 60%, transparent);
}

.menu-recipe-ingredient:last-child {
  border-bottom: 0;
}

/* Nom de l'ingrédient : prend uniquement sa largeur naturelle (max-content)
   plutôt que pousser la quantité à droite via space-between. Sur desktop
   large, la quantité reste collée au nom au lieu d'être à 600px à droite. */
.menu-recipe-ingredient-name {
  font-size: 15px;
  color: var(--text);
  font-weight: 500;
  flex: 0 0 auto;
}

.menu-recipe-ingredient-qty {
  font-size: 14px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Séparateur visuel entre nom et quantité — virgule en grisé. */
.menu-recipe-ingredient-qty:not(:empty)::before {
  content: "— ";
  color: var(--muted);
  margin-right: 2px;
}

/* Liste consignes (étapes numérotées) */

.menu-recipe-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  counter-reset: recipe-step;
}

.menu-recipe-step {
  display: grid;
  grid-template-columns: 32px 1fr;
  gap: 14px;
  align-items: start;
  padding: 6px 10px;
  border-radius: 10px;
  cursor: pointer;
  user-select: none;
  transition: background 0.12s ease;
}

.menu-recipe-step:hover {
  background: color-mix(in srgb, var(--primary) 6%, transparent);
}

/* Toggle au tap : marque visuellement l'étape "faite" (suivi cuisine).
   Comportement repris du Pi (touch_recipe.js : classe .active). */
.menu-recipe-step.is-active {
  background: color-mix(in srgb, var(--primary) 14%, transparent);
}

.menu-recipe-step.is-active .menu-recipe-step-num {
  background: var(--success);
}

.menu-recipe-step-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  background: var(--primary);
  color: #ffffff;
  border-radius: 50%;
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
}

.menu-recipe-step-text {
  font-size: 15px;
  color: var(--text);
  line-height: 1.5;
  padding-top: 6px;
}

/* Mobile responsive --------------------------------------------- */

@media (max-width: 540px) {
  /* Plus de surface utile sur téléphone : on resserre les marges latérales
     du conteneur global (de 20px à 8px) pour récupérer ~24px de largeur,
     surtout utile pour la liste des recettes où les boutons d'action
     "Afficher/Modifier/Supprimer" débordaient. */
  .container {
    padding: 12px 8px;
  }

  /* Panels : padding réduit sur mobile (18px → 12px) */
  .panel {
    padding: 12px;
  }

  /* Liste des recettes : le panel qui wrap la <ul> ne sert à rien sur
     mobile — chaque .recipe-row a déjà son propre fond et bordure. On
     retire le padding/border/background du panel parent pour gagner
     ~24px de largeur utile (sinon on a panel + recipe-row qui doublent
     l'effet "bloc dans un bloc"). */
  .panel:has(> .recipes-list) {
    padding: 0;
    background: transparent;
    border: 0;
    box-shadow: none;
    margin-bottom: 0;
  }

  /* Liste des recettes : cards plus serrées */
  .recipe-row {
    padding: 10px 10px;
    gap: 10px;
  }

  .recipe-row-head {
    gap: 10px;
  }

  .menu-hero {
    padding: 16px 14px 14px;
  }

  /* Sur mobile : on garde le row {titre | toolbar} (comme en desktop)
     pour mettre les filtres directement à droite de "Que cuisiner ?".
     Le wrap permet à la toolbar de passer sous le titre si vraiment
     l'espace manque (très petit écran + beaucoup de boutons). */
  .menu-hero-inner {
    align-items: center;
    gap: 10px;
  }

  .menu-hero-cta-form {
    margin-top: 12px;
  }

  .menu-hero-cta {
    padding: 14px 22px;
    font-size: 16px;
  }

  .menu-hero-title {
    font-size: 22px;
    margin-bottom: 2px;
  }

  .menu-hero-subtitle {
    font-size: 14px;
  }

  .menu-hero-toolbar {
    /* Toolbar pleine largeur en dessous du titre, boutons à gauche. */
    justify-content: flex-start;
    margin-top: 12px;
  }

  /* Filtre durée en mobile : on garde juste l'icône ⏱ pour qu'il reste
     compact à droite de "Que cuisiner ?". Le label complet est dispo
     dans le popover quand on tape dessus. */
  .menu-hero-duration .menu-filter-summary > span:nth-child(2) {
    display: none;
  }

  .menu-hero-duration .menu-filter-summary {
    padding: 0;
    width: 44px;
    height: 44px;
    justify-content: center;
  }

  .menu-toolbar-btn-label {
    display: none;
  }

  .menu-toolbar-btn {
    width: 44px;
    padding: 0;
    justify-content: center;
  }

  .menu-card-body {
    grid-template-columns: 72px 1fr;
    gap: 12px;
  }

  .menu-thumb-lg {
    width: 72px;
    height: 72px;
  }

  .menu-card-title {
    font-size: 16px;
  }

  .menu-card-actions .menu-action {
    flex: 1 1 0;
  }

  /* Mais quand on a le stepper (cards sélection) : largeur naturelle pour
     que stepper à gauche + Retirer à droite restent compacts. */
  .menu-card-actions:has(.menu-servings) .menu-action {
    flex: 0 0 auto;
  }

  .menu-picker-row {
    grid-template-columns: auto 1fr;
  }

  .menu-picker-row-actions {
    grid-column: 1 / -1;
    justify-content: flex-end;
  }

  .menu-filter-form {
    right: 0;
    left: auto;
    min-width: 200px;
  }

  .menu-ingredients-hero-inner {
    padding: 16px 16px;
  }

  .menu-ingredients-title {
    font-size: 22px;
  }

  .menu-ingredient-cat {
    padding: 12px 12px;
  }

  .menu-ingredients-actions {
    padding: 8px 10px;
    /* Sur ≤700px la bottom-nav (position:fixed, ~50px + safe-area iOS)
       passe par-dessus le contenu. Le sticky doit donc s'arrêter
       au-dessus, pas à 8px du bord. */
    bottom: calc(50px + env(safe-area-inset-bottom, 0) + 12px);
  }

  /* Bouton Exporter (et autres actions de la barre sticky) un peu
     plus compact sur mobile pour gagner de la verticale — on garde
     44×44px pour rester dans la guideline tactile Apple/Google. */
  .menu-ingredients-actions .menu-action {
    min-height: 44px;
    font-size: 14px;
  }

  .menu-manual-hero-inner {
    padding: 16px 16px;
  }

  .menu-manual-title {
    font-size: 22px;
  }

  .menu-manual-search {
    flex-direction: column;
  }

  .menu-manual-search-submit {
    width: 100%;
  }

  .menu-filter-form-types {
    /* Sur mobile, le popover absolute occupe quasi toute la largeur
       (left: 0, right: 0). Pas besoin de min-width fixe. */
    min-width: 0;
    width: calc(100vw - 32px);
    max-width: 380px;
  }

  /* Vague 7.10 — Reposition des popovers de filtres en BOTTOM SHEET sur
     tel. Avant, position: absolute + left:0 (relatif au <details> parent
     position:relative) → quand le bouton « Types » se trouvait à droite
     de la rangée, le popover dépassait à gauche et en bas du viewport
     (signalé revue UX : « la fenêtre est placée n'importe où »). En
     mobile on bascule en `position: fixed` ancré bas+gauche+droite avec
     un max-height contenu et un overflow propre. La durée bénéficie du
     même fix. */
  .menu-filter[open] > .menu-filter-form {
    position: fixed;
    top: auto;
    bottom: max(16px, env(safe-area-inset-bottom, 16px));
    left: 16px;
    right: 16px;
    width: auto;
    max-width: none;
    min-width: 0;
    max-height: min(70vh, calc(100dvh - 32px));
    overflow-y: auto;
    z-index: 1000;
    overscroll-behavior: contain;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
    animation: ribouns-bottom-sheet-rise 200ms ease-out both;
  }

  /* Backdrop semi-transparent derrière la bottom sheet pour faire
     comprendre l'overlay (et que le click extérieur sera capté par le
     JS click-outside ci-dessous). */
  .menu-filter[open]::before {
    content: "";
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.35);
    z-index: 999;
    animation: ribouns-freeze-fade-in 180ms ease-out both;
  }
}

@keyframes ribouns-bottom-sheet-rise {
  from { transform: translateY(20%); opacity: 0; }
  to   { transform: translateY(0);   opacity: 1; }
}

@media (max-width: 540px) {

  .menu-recipe-hero-with-photo {
    grid-template-columns: 1fr;
    gap: 14px;
    padding: 16px;
  }

  .menu-recipe-photo {
    max-width: 100%;
    aspect-ratio: 16 / 9;
  }

  .menu-recipe-hero-inner {
    padding: 16px;
  }

  .menu-recipe-title {
    font-size: 22px;
  }

  .menu-recipe-card {
    padding: 14px 16px;
  }

  .menu-recipe-step-text {
    font-size: 14px;
  }
}

/* ============================================================== */
/* Feedback :active tactile — sur écrans à pointer "coarse" (=     */
/* tactile), on ajoute un effet scale + background plus marqué sur */
/* le tap. Donne le feeling "app native" : le doigt sent que ça a  */
/* réagi, plus de double-tap par incertitude.                      */
/* Les boutons qui ont déjà leur propre :active (CTA hero, recipe- */
/* row-toggle, bottom-nav-sheet-close, etc.) gardent leur effet    */
/* spécifique par spécificité CSS — pas d'override.                */
/* ============================================================== */
@media (hover: none) and (pointer: coarse) {
  /* On exclut explicitement .bottom-nav-item du scale : ajouter un
     transform à un onglet qui CONTIENT un sheet position:fixed (l'onglet
     "Plus") créerait un containing block au tap, et le sheet se
     positionnerait par rapport à la cellule de l'onglet (étroite, à
     droite) au lieu du viewport — bug visible où le sheet apparaît
     décalé à droite. Le feedback :active sur les onglets passe par
     background uniquement. */
  .menu-action:active,
  .menu-toolbar-btn:active,
  .menu-servings-btn:active,
  .bottom-nav-sheet-item:active,
  .nav-item:active,
  .card-link:active,
  .recipe-row-thumb-link:active,
  .menu-card-thumb-link:active,
  .recipe-row-name:active,
  .menu-card-title:active {
    transform: scale(0.96);
    transition: transform 90ms ease;
  }

  .menu-action:active,
  .menu-toolbar-btn:active,
  .menu-servings-btn:active {
    background: var(--hover-bg);
  }

  .bottom-nav-item:active,
  .bottom-nav-sheet-item:active {
    background: var(--hover-bg);
  }
}

/* ============================================================== */
/* Thème clair — activé par [data-theme="light"] sur <html>.       */
/* S'appuie sur les variables CSS racine pour basculer toutes les  */
/* surfaces sans dupliquer les sélecteurs.                         */
/* ============================================================== */

[data-theme="light"] {
  /* Palette off-white doux : fond légèrement crème, panels blancs purs,
     bordures et hover teintés chaud pour casser l'effet "feuille blanche". */
  --bg: #fbf9f4;
  --panel: #ffffff;
  --panel-2: #f5f1e8;
  --panel-sunken: #ffffff;
  --topbar-bg: #ffffff;
  --hover-bg: #ece7da;
  --text: #1f1d1a;
  --muted: #5c574f;
  --border: #d8d2c4;
  --primary: #e0664a;
  --primary-hover: #c9543a;
  --secondary: #64748b;
  --secondary-hover: #475569;
  --danger: #dc2626;
  --danger-hover: #b91c1c;
  --success: #3f9a63;
  --success-hover: #347f53;
  --shadow-color: rgba(40, 30, 10, 0.08);
}

/* Hover sur la nav admin (haut de page) — visible sur les deux thèmes. */
.brand a:hover,
.brand a:focus-visible,
.nav a:hover,
.nav a:focus-visible,
.nav-btn:hover,
.nav-btn:focus-visible,
.nav-more-summary:hover,
.nav-more-summary:focus-visible {
  background: var(--hover-bg);
  border-color: var(--primary);
  outline: none;
}

/* Raccourci « + » création rapide (topbar desktop) : accent vert pour le
   distinguer des onglets de navigation. Spécificité .nav a.nav-item-add pour
   passer devant la base .nav a (fond panel) et son :hover. */
.nav a.nav-item-add {
  background: var(--success);
  border-color: transparent;
  color: #fff;
}

.nav a.nav-item-add:hover,
.nav a.nav-item-add:focus-visible {
  background: var(--success-hover);
  border-color: transparent;
  color: #fff;
}

.nav-login-link:hover,
.nav-login-link:focus-visible {
  background: var(--hover-bg);
  border-color: var(--primary);
  outline: none;
}

/* Flash messages — contraste adapté au mode clair. */
[data-theme="light"] .flash {
  background: #eff6ff;
  border-color: #93c5fd;
  color: #1e3a8a;
}

/* ============================================================== */
/* Thème rose pâle — activé par [data-theme="pink"] sur <html>.    */
/* Palette girly basée sur pink-50/100/300/500 de Tailwind.        */
/* ============================================================== */

[data-theme="pink"] {
  --bg: #fdf2f8;
  --panel: #ffffff;
  --panel-2: #fce7f3;
  --panel-sunken: #ffffff;
  --topbar-bg: #ffffff;
  --hover-bg: #fbcfe8;
  --text: #4a1d2e;
  --muted: #9c5775;
  --border: #f9a8d4;
  --primary: #e0664a;
  --primary-hover: #c9543a;
  --secondary: #a78bfa;
  --secondary-hover: #8b5cf6;
  --danger: #dc2626;
  --danger-hover: #b91c1c;
  --success: #3f9a63;
  --success-hover: #347f53;
  --shadow-color: rgba(190, 24, 93, 0.10);
}

[data-theme="pink"] .flash {
  background: #fdf2f8;
  border-color: #f9a8d4;
  color: #831843;
}

/* Styles du formulaire de choix du thème dans /account. */
.account-theme-form .theme-options {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 8px 0 14px;
}

.account-theme-form .theme-option {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  cursor: pointer;
  min-height: 44px;
  color: var(--text);
}

.account-theme-form .theme-option:hover {
  background: var(--hover-bg);
  border-color: var(--primary);
}

.account-theme-form .theme-option input[type="radio"] {
  accent-color: var(--primary);
}

.account-theme-form .theme-option-label {
  white-space: nowrap;
}

/* Pastilles thèmes : pastille circulaire avec la couleur du thème.
   Évite les emoji 🌙 ☀️ 🌸 qui rendent différemment sur iOS / Android
   selon les versions (parfois en noir-blanc, parfois cassés).

   iOS Safari : un span vide en display:inline-block dans un parent
   inline-flex calcule sa baseline depuis le content (vide) → décalage
   vertical visible (le swatch n'est pas centré dans le bouton). Le
   fix : forcer le span en participant flex pleinement (block-level
   dans flex parent), couper la line-height qui ajoute des half-leadings
   verticaux, et expliciter align-self au cas où le parent change. */
.account-theme-form .theme-option-swatch {
  display: block;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  flex: 0 0 20px;
  align-self: center;
  line-height: 0;
  border: 1px solid color-mix(in srgb, var(--text) 20%, transparent);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
}

.account-theme-form .theme-option-swatch-dark {
  background: linear-gradient(135deg, #0f172a 0%, #1f2937 100%);
}

.account-theme-form .theme-option-swatch-light {
  background: linear-gradient(135deg, #fbf9f4 0%, #ffffff 100%);
  border-color: #d8d2c4;
}

.account-theme-form .theme-option-swatch-pink {
  background: linear-gradient(135deg, #fdf2f8 0%, #ec4899 100%);
  border-color: #f9a8d4;
}

.u-hidden {
  display: none !important;
}

/* Dialog d'export — taille et paddings UNIFORMES pour les 4 fenêtres
   avant-plan (signalé en revue UX : « toutes les fenêtres qui s'ouvrent
   en avant plan, on peut pas faire en sorte qu'elles fassent toutes la
   même taille »). Les marges sont resserrées par rapport à l'ancienne
   variante non-compacte pour gagner de la place sur smartphone. */
.export-dialog {
  width: min(540px, calc(100vw - 16px));
  max-height: calc(100vh - 24px);
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--panel);
  color: var(--text);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
  /* Vague 7.9 bugfix — `overflow: hidden` sur la dialog garantit que
     le scroll des contenus dépassants reste contenu dans `.export-
     dialog-body` (qui a son propre `overflow-y: auto`). Sinon, sur
     iOS et certains Android, le scroll touch « fuyait » vers le body
     de la page derrière. */
  overflow: hidden;
}

.export-dialog::backdrop {
  background: rgba(15, 23, 42, 0.55);
  backdrop-filter: blur(2px);
}

.export-dialog-form {
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 24px);
  gap: 0;
}

/* Texte de chargement transitoire (modal picker recettes liées /menu,
   injecté par fetch avant le remplacement par le fragment). */
.export-dialog-loading {
  margin: 0;
  padding: 18px 16px;
  color: var(--muted);
}

.export-dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
}

.export-dialog-title {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
}

.export-dialog-close {
  width: 36px;
  min-width: 36px;
  padding: 0;
  font-size: 18px;
  line-height: 1;
}

.export-dialog-tools {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--panel-2);
}

/* Ligne recherche + bouton « Filtres » (durée/type) des pickers de recettes
   — cohérent avec le picker du planning. Le champ prend l'espace, le bouton
   reste à droite. */
.export-dialog-search-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.export-dialog-search-row .export-dialog-search {
  flex: 1 1 auto;
  min-width: 0;
}

.export-dialog-search-row .recipes-filters-btn {
  flex: 0 0 auto;
}

.export-dialog-search {
  width: 100%;
}

.export-dialog-actions-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.export-dialog-count {
  margin-left: auto;
  font-size: 14px;
}

.export-dialog-list {
  list-style: none;
  margin: 0;
  padding: 4px 0;
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 80px;
  max-height: 50vh;
}

.export-dialog-item {
  padding: 0;
}

.export-dialog-item[hidden] {
  display: none;
}

.export-dialog-item > label {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 14px;
  cursor: pointer;
  min-height: 32px;
}

.export-dialog-item > label:hover {
  background: var(--hover-bg);
}

.export-dialog-item input[type="checkbox"] {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  accent-color: var(--primary);
  cursor: pointer;
}

.export-dialog-item-name {
  flex: 1 1 auto;
  word-break: break-word;
}

.export-dialog-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  padding: 10px 14px;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}

.export-dialog-footer .btn[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

@media (max-width: 540px) {
  .export-dialog-header,
  .export-dialog-tools,
  .export-dialog-footer {
    padding-left: 10px;
    padding-right: 10px;
  }

  .export-dialog-item > label {
    padding-left: 10px;
    padding-right: 10px;
  }

  .export-dialog-footer {
    flex-direction: column-reverse;
    align-items: stretch;
  }

  .export-dialog-footer .btn {
    width: 100%;
  }
}

/* Champ photo dans le formulaire de recette. */
.recipe-image-field {
  display: grid;
  gap: 8px;
}

.recipe-image-preview {
  max-width: 320px;
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--panel-2);
}

.recipe-image-preview img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 220px;
  object-fit: cover;
}

.recipe-image-delete-btn {
  align-self: flex-start;
  max-width: 320px;
}

.recipe-image-input {
  max-width: 360px;
}

/* Picker photo recette : deux labels-boutons côte à côte (📷 Prendre
   une photo / 🖼 Choisir une photo). Les inputs file sont cachés via
   .u-hidden et activés au clic sur le label. */
.recipe-image-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.recipe-image-picker-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 16px;
  background: var(--panel-sunken);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 10px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  transition: background 0.12s ease, border-color 0.12s ease;
}

.recipe-image-picker-btn:hover,
.recipe-image-picker-btn:focus-within {
  background: var(--hover-bg);
  border-color: var(--primary);
}

.recipe-image-picker-emoji {
  font-size: 18px;
  line-height: 1;
}

/* Encadré-dropzone cliquable du form recette (photo au-dessus des
   consignes). Un <label> qui ouvre le sélecteur de fichier au clic. */
.recipe-image-dropzone {
  display: block;
  position: relative;
  max-width: 360px;
  border-radius: 12px;
  border: 2px dashed var(--border);
  background: var(--panel-sunken);
  cursor: pointer;
  overflow: hidden;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}

.recipe-image-dropzone:hover,
.recipe-image-dropzone:focus-within {
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 8%, var(--panel-sunken));
}

/* Photo présente : bord plein (l'image remplit l'encadré). */
.recipe-image-dropzone.has-image {
  border-style: solid;
  border-color: var(--border);
}

.recipe-image-dropzone-img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 240px;
  object-fit: cover;
}

/* Placeholder « Ajouter une photo » (pas d'image). */
.recipe-image-dropzone-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 32px 16px;
  text-align: center;
  color: var(--muted);
}

.recipe-image-dropzone-icon {
  color: var(--primary);
  line-height: 1;
}

/* iOS Safari : SVG en flex item avec width:1em peut s'effondrer → taille px
   explicite (cf CONSIGNES « pièges Safari iOS »). */
.recipe-image-dropzone-icon > svg,
.recipe-image-dropzone-icon .ico {
  width: 30px;
  height: 30px;
}

.recipe-image-dropzone-text {
  font-weight: 600;
  color: var(--text);
}

.recipe-image-dropzone-hint {
  font-size: 13px;
}

/* Overlay « Changer la photo » au survol quand une image est présente. */
.recipe-image-dropzone-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-weight: 600;
  color: #ffffff;
  background: color-mix(in srgb, #000000 45%, transparent);
  opacity: 0;
  transition: opacity 0.15s ease;
}

.recipe-image-dropzone-overlay-icon > svg,
.recipe-image-dropzone-overlay-icon .ico {
  width: 20px;
  height: 20px;
  vertical-align: -0.2em;
}

.recipe-image-dropzone:hover .recipe-image-dropzone-overlay,
.recipe-image-dropzone:focus-within .recipe-image-dropzone-overlay {
  opacity: 1;
}

/* Tactile (pas de hover) : l'overlay « Changer la photo » est invisible tant
   qu'on ne survole pas → sur tel, l'utilisateur ne sait pas qu'on peut taper
   la photo. On l'affiche donc en permanence, allégé (dégradé bas + label
   coin) pour ne pas masquer la photo. */
@media (hover: none) {
  .recipe-image-dropzone.has-image .recipe-image-dropzone-overlay {
    opacity: 1;
    align-items: flex-end;
    justify-content: flex-end;
    padding: 8px 12px;
    font-size: 13px;
    background: linear-gradient(
      to top,
      color-mix(in srgb, #000000 58%, transparent) 0%,
      transparent 55%
    );
  }
}


/* ============================================================== */
/* Vague 7.8 — Planning hebdomadaire des repas.                    */
/* Override en fin de fichier (pattern projet) : styles de la page */
/* /menu/planning, du picker /menu/planning/picker, et de l'intég- */
/* ration des boutons 📅 dans menu_home et la liste des recettes.  */
/* ============================================================== */

/* Page /menu/planning ---------------------------------------------- */

.menu-planning-hero {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px 0 18px;
}

.menu-planning-nav {
  display: flex;
  align-items: center;
  gap: 8px;
  justify-content: space-between;
}

.menu-planning-week-label {
  font-size: 15px;
  color: var(--text);
  flex: 1 1 auto;
  text-align: center;
}

.menu-planning-week-label strong {
  color: var(--primary);
}

.menu-planning-today-link {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
}

.menu-planning-day {
  padding: 14px;
}

.menu-planning-day-today {
  border-color: var(--primary);
  box-shadow: 0 0 0 1px var(--primary);
}

.menu-planning-day-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 10px;
}

.menu-planning-day-label {
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
}

.menu-planning-day-date {
  font-weight: 400;
  color: var(--muted);
  margin-left: 6px;
  font-size: 14px;
}

.menu-planning-slots {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Variante 2 colonnes : Midi + Soir sur la même ligne (signalé en
   revue UX). On garde l'ancien display:flex column comme défaut au cas
   où d'autres consommateurs en dépendent ; .menu-planning-slots-grid
   override pour /menu/planning. */
.menu-planning-slots-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.menu-planning-slot {
  display: grid;
  grid-template-columns: 64px 1fr;
  gap: 12px;
  align-items: center;
  padding: 10px 12px;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 10px;
}

/* En 2-cols, le slot devient plus compact : label en haut, contenu en
   bas, et le bouton + (ou la poubelle) calé à droite. Évite le déba-
   gement horizontal des longs noms de recette. */
.menu-planning-slots-grid .menu-planning-slot {
  grid-template-columns: 1fr auto;
  gap: 8px;
  padding: 8px 10px;
}

.menu-planning-slots-grid .menu-planning-slot-label {
  grid-column: 1 / -1;
}

/* Sous 480px : on bascule à nouveau en 1 col pour respirer (les noms
   de recette doivent rester lisibles sur petit écran). */
@media (max-width: 480px) {
  .menu-planning-slots-grid {
    grid-template-columns: 1fr;
  }
  .menu-planning-slots-grid .menu-planning-slot {
    grid-template-columns: 64px 1fr auto;
  }
  .menu-planning-slots-grid .menu-planning-slot-label {
    grid-column: 1;
  }
}

/* `+` vert (success) — identique au pattern des toggles « ajouter au
   menu / aux courses » sur /recipes. Hover scopé hover-only pour ne
   pas coller sur tactile. */
.menu-planning-slot-add-btn {
  color: var(--success);
  border-color: color-mix(in srgb, var(--success) 40%, var(--border));
  background: color-mix(in srgb, var(--success) 10%, var(--panel-sunken));
}

@media (hover: hover) {
  .menu-planning-slot-add-btn:hover,
  .menu-planning-slot-add-btn:focus-visible {
    background: var(--success);
    border-color: var(--success);
    color: #ffffff;
  }
}

/* Le filled-content (titre + meta + poubelle) en colonne resserrée. */
.menu-planning-slot-filled {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 4px 6px;
}

.menu-planning-slot-title,
.menu-planning-slot-meta {
  grid-column: 1;
  min-width: 0;
  word-break: break-word;
}

.menu-planning-slot-clear-form {
  grid-column: 2;
  grid-row: 1 / span 2;
  margin: 0;
  display: inline-flex;
  align-items: center;
}

/* Survol scopé pour la poubelle de Vider — déjà couvert par les règles
   .recipe-action-danger globales avec @media (hover: hover). Pas besoin
   de re-spécifier ici. */

.menu-planning-slot-label {
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  font-size: 12px;
  letter-spacing: 0.5px;
}

.menu-planning-slot-filled {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.menu-planning-slot-filled .menu-card-title {
  font-size: 15px;
  font-weight: 500;
}

.menu-planning-slot-filled .menu-inline-form {
  margin-top: 6px;
  align-self: flex-start;
}

.menu-planning-slot-add {
  width: 100%;
}

.menu-planning-slot-add > summary {
  list-style: none;
  cursor: pointer;
  width: auto;
}

.menu-planning-slot-add > summary::-webkit-details-marker { display: none; }
.menu-planning-slot-add > summary::marker { content: ""; }

.menu-planning-slot-add-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 10px;
}

.menu-planning-slot-add-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
  color: var(--muted);
}

.menu-planning-slot-add-field select {
  min-height: 44px;
  padding: 0 10px;
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 14px;
}

/* Picker /menu/planning/picker ------------------------------------ */

.menu-planning-picker-hero {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 14px 0 18px;
}

.planning-picker-recipe {
  display: grid;
  grid-template-columns: 72px 1fr;
  gap: 12px;
  align-items: center;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel-2);
}

.planning-picker-recipe .menu-thumb-lg {
  width: 72px;
  height: 72px;
}

.planning-picker-recipe-info {
  min-width: 0;
}

.planning-picker-recipe-name {
  margin: 0 0 4px;
  font-size: 18px;
  font-weight: 600;
  color: var(--text);
}

.planning-picker-recipe-meta {
  color: var(--muted);
  font-size: 13px;
}

.planning-picker-form {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding-bottom: 24px;
}

.planning-picker-section {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px;
  background: var(--panel-2);
  margin: 0;
}

.planning-picker-section-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 0 4px;
}

.planning-picker-week {
  margin-top: 10px;
}

.planning-picker-week-label {
  font-size: 13px;
  color: var(--muted);
  margin-bottom: 6px;
}

.planning-picker-day-grid {
  display: grid;
  /* auto-fit + minmax permet au navigateur de wrapper automatiquement
     selon la largeur dispo : 7 colonnes sur écran large, puis 4-5-3
     selon le viewport, sans débordement horizontal. */
  grid-template-columns: repeat(auto-fit, minmax(64px, 1fr));
  gap: 6px;
}

.planning-picker-day-chip {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: 56px;
  padding: 6px 4px;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 10px;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

.planning-picker-day-chip input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.planning-picker-day-chip:hover,
.planning-picker-day-chip:focus-within {
  border-color: var(--primary);
}

.planning-picker-day-chip:has(input[type="radio"]:checked) {
  background: var(--primary);
  border-color: var(--primary);
  color: #ffffff;
}

.planning-picker-day-chip-today {
  border-color: var(--primary);
}

.planning-picker-day-chip-label {
  font-size: 11px;
  text-transform: uppercase;
  font-weight: 600;
  letter-spacing: 0.5px;
}

.planning-picker-day-chip-date {
  font-size: 13px;
  font-weight: 500;
}

.planning-picker-slot-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 10px;
}

.planning-picker-slot-chip {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 56px;
  padding: 8px 12px;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 12px;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
  font-size: 15px;
  font-weight: 500;
}

.planning-picker-slot-chip input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.planning-picker-slot-chip:hover,
.planning-picker-slot-chip:focus-within {
  border-color: var(--primary);
}

.planning-picker-slot-chip:has(input[type="radio"]:checked) {
  background: var(--primary);
  border-color: var(--primary);
  color: #ffffff;
}

.planning-picker-slot-emoji {
  font-size: 20px;
  line-height: 1;
}

.planning-picker-servings {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 10px;
}

.planning-picker-servings-field {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 6px 12px;
}

.planning-picker-servings-btn {
  /* Bouton visible 40px (un peu plus généreux que le stepper card pour
     le contexte modal) avec zone de tap étendue à 48px via pseudo
     ::after (guideline Apple/Google). */
  position: relative;
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 50%;
  color: var(--text);
  font-size: 22px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition: background 0.12s ease, transform 0.08s ease;
  flex-shrink: 0;
}

.planning-picker-servings-btn::after {
  content: "";
  position: absolute;
  inset: -4px;
}

.planning-picker-servings-btn:hover,
.planning-picker-servings-btn:focus-visible {
  background: var(--hover-bg);
  outline: none;
}

.planning-picker-servings-btn:active {
  transform: scale(0.95);
}

.planning-picker-servings-btn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}

.planning-picker-servings-field input[type="number"] {
  width: 64px;
  text-align: center;
  font-size: 18px;
  font-weight: 600;
  color: var(--text);
  background: transparent;
  border: 0;
  outline: none;
  -moz-appearance: textfield;
}

.planning-picker-servings-field input[type="number"]::-webkit-outer-spin-button,
.planning-picker-servings-field input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.planning-picker-servings-unit {
  font-size: 14px;
  font-weight: 600;
  color: var(--muted);
}

.planning-picker-actions {
  display: flex;
  justify-content: center;
}

.planning-picker-submit {
  min-width: 220px;
  min-height: 52px;
  font-size: 16px;
}

/* Cards menu_home : grouper Planifier + Retirer à droite -------- */

.menu-card-actions-end {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Mobile : afficher uniquement l'emoji pour les actions secondaires
   (planifier 📅 / retirer 🗑) sur les cards menu, pour gagner de la
   place quand le stepper personnes prend déjà la moitié de la ligne.
   Emoji grossi à 20px pour rester lisible une fois le label retiré. */
@media (max-width: 700px) {
  .menu-action-icon-only-mobile {
    padding: 0 14px;
    min-width: 48px;
  }

  .menu-action-icon-only-mobile .menu-action-label {
    display: none;
  }

  .menu-action-icon-only-mobile [aria-hidden="true"] {
    font-size: 20px;
    line-height: 1;
  }
}

/* (refonte de la liste des recettes : voir
   « Liste des recettes — refonte boutons » en fin de fichier.) */

/* ============================================================== */
/* Vague 7.8 Lot D — Ingrédients du planning + mode "Ajouter à".  */
/* ============================================================== */

/* Picker "Liste cible" + radio "Mode" (commun /menu/ingredients +
   /menu/planning/ingredients) -------------------------------- */

.export-target-fieldset,
.export-mode-fieldset {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel-2);
  padding: 14px;
  margin: 14px 0 0;
}

.export-target-legend {
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 0 6px;
}

.export-target-select {
  width: 100%;
  min-height: 44px;
  padding: 0 10px;
  margin-top: 6px;
  background: var(--panel-sunken);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 14px;
}

.export-mode-options {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 6px;
}

.export-mode-option {
  display: grid;
  grid-template-columns: 24px 1fr;
  grid-template-rows: auto auto;
  column-gap: 10px;
  row-gap: 4px;
  align-items: start;
  padding: 12px;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 10px;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}

.export-mode-option:hover,
.export-mode-option:focus-within {
  border-color: var(--primary);
}

.export-mode-option:has(input[type="radio"]:checked) {
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 8%, var(--panel-sunken));
}

.export-mode-option input[type="radio"] {
  grid-column: 1;
  grid-row: 1 / span 2;
  width: 20px;
  height: 20px;
  margin: 2px 0 0;
  align-self: start;
  accent-color: var(--primary);
}

.export-mode-option-title {
  grid-column: 2;
  grid-row: 1;
  font-weight: 600;
  color: var(--text);
}

.export-mode-option-hint {
  grid-column: 2;
  grid-row: 2;
  font-size: 13px;
  color: var(--muted);
  line-height: 1.4;
}

.export-mode-hint-global {
  margin: 10px 0 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.4;
  font-style: italic;
}

/* Page /menu/planning/ingredients : checkboxes jours en haut -- */

.planning-ingredients-form {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding-bottom: 24px;
}

.planning-ingredients-days {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel-2);
  padding: 14px;
  margin: 0;
}

.planning-ingredients-section-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 0 4px;
  margin: 0 0 10px;
}

.planning-ingredients-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 28px;
  height: 22px;
  padding: 0 8px;
  margin-left: 6px;
  background: var(--primary);
  color: #ffffff;
  border-radius: 12px;
  font-size: 12px;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
}

.planning-ingredients-day-grid {
  display: grid;
  /* auto-fit + minmax : wrap automatique selon la largeur dispo.
     Évite le débordement horizontal sur petit mobile où 7 colonnes
     de "Mer 28/05 1 repas" ne tiennent pas. */
  grid-template-columns: repeat(auto-fit, minmax(76px, 1fr));
  gap: 6px;
}

.planning-ingredients-day-chip {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: 76px;
  padding: 8px 4px;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 10px;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease, opacity 0.12s ease;
}

.planning-ingredients-day-chip input[type="checkbox"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.planning-ingredients-day-chip:hover,
.planning-ingredients-day-chip:focus-within {
  border-color: var(--primary);
}

.planning-ingredients-day-chip:has(input[type="checkbox"]:checked) {
  background: var(--primary);
  border-color: var(--primary);
  color: #ffffff;
}

.planning-ingredients-day-chip-today {
  border-color: var(--primary);
}

.planning-ingredients-day-chip-past {
  opacity: 0.5;
}

.planning-ingredients-day-chip-label {
  font-size: 11px;
  text-transform: uppercase;
  font-weight: 600;
  letter-spacing: 0.5px;
}

.planning-ingredients-day-chip-date {
  font-size: 13px;
  font-weight: 500;
}

.planning-ingredients-day-chip-count {
  font-size: 10px;
  opacity: 0.85;
  margin-top: 2px;
}

.planning-ingredients-day-chip-empty {
  font-size: 11px;
  opacity: 0.55;
}

/* Petit écran : gap réduit + padding compact. Grid auto-fit définie
   plus haut s'occupe du wrap naturellement (4 colonnes sur ~320-400px,
   passant à 7 sur écrans plus larges). */
@media (max-width: 480px) {
  .planning-ingredients-day-grid {
    gap: 4px;
  }
  .planning-ingredients-day-chip {
    padding: 6px 4px;
    min-height: 64px;
  }
  .planning-ingredients-day-chip-count,
  .planning-ingredients-day-chip-empty {
    font-size: 10px;
  }
}


/* ============================================================== */
/* Vague 7.8 Lot B — Modal AJAX picker planning + toast.           */
/* ============================================================== */

.planning-picker-dialog {
  width: min(540px, calc(100vw - 24px));
  max-height: calc(100vh - 60px);
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--panel);
  color: var(--text);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35);
  overflow: hidden;
}

.planning-picker-dialog::backdrop {
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(2px);
}

.planning-picker-dialog-form {
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 60px);
}

.planning-picker-dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--panel-sunken);
}

.planning-picker-dialog-title {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.planning-picker-dialog-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 8px;
  color: var(--muted);
  cursor: pointer;
  font-size: 22px;
  line-height: 1;
  flex: 0 0 auto;
}

.planning-picker-dialog-close:hover,
.planning-picker-dialog-close:focus-visible {
  background: var(--hover-bg);
  border-color: var(--border);
  color: var(--text);
  outline: none;
}

.planning-picker-dialog-body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 14px 16px;
  overflow-y: auto;
}

.planning-picker-dialog-body .planning-picker-section {
  margin: 0;
}

.planning-picker-dialog-error {
  margin: 0;
  padding: 10px 12px;
  background: color-mix(in srgb, var(--danger) 12%, var(--panel-sunken));
  border: 1px solid var(--danger);
  border-radius: 10px;
  color: var(--danger);
  font-size: 13px;
}

.planning-picker-dialog-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
  background: var(--panel-sunken);
}

.planning-picker-dialog-submit {
  min-width: 140px;
}

/* Mobile : dialog quasi plein-écran, footer reste accessible. */
@media (max-width: 700px) {
  .planning-picker-dialog {
    width: calc(100vw - 16px);
    max-height: calc(100vh - 32px);
    border-radius: 14px;
  }

  .planning-picker-dialog-body {
    padding: 12px;
    gap: 12px;
  }

  .planning-picker-dialog-header,
  .planning-picker-dialog-footer {
    padding: 12px;
  }

  .planning-picker-dialog-submit {
    min-width: 0;
    flex: 1 1 auto;
  }
}

/* ───── Toast système global (Vague 7.6 Polish UI) ───── */
/* API window.showToast(message, kind, options). Cf static/js/toast.js. */

.toast-container {
  position: fixed;
  z-index: 60;
  /* Desktop : sous la topbar sticky (~56px de haut) pour ne pas
     recouvrir la navigation du haut. Sur mobile (≤700px) la topbar est
     remplacée par la bottom-nav → on remonte le toast (cf media query). */
  top: 72px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
  max-width: calc(100vw - 24px);
}

.toast {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-width: 240px;
  max-width: 100%;
  padding: 12px 18px;
  border-radius: 12px;
  font-size: 14px;
  font-weight: 500;
  color: #ffffff;
  background: var(--success);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
  opacity: 0;
  transform: translateY(-12px);
  transition: opacity 0.18s ease, transform 0.18s ease;
}

.toast.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.toast.is-hiding {
  opacity: 0;
  transform: translateY(-8px);
}

.toast-text {
  flex: 1 1 auto;
}

.toast-close {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  padding: 0;
  background: transparent;
  border: 0;
  color: inherit;
  opacity: 0.85;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}

.toast-close:hover,
.toast-close:focus-visible {
  opacity: 1;
  outline: none;
}

.toast-success { background: var(--success); }
.toast-error   { background: var(--danger); }
.toast-info    { background: var(--primary); }

@media (max-width: 700px) {
  .toast-container {
    top: 12px;
  }
  .toast {
    min-width: 0;
    width: 100%;
    text-align: center;
    justify-content: center;
  }
}


/* ============================================================== */
/* Vague 7.8 — Retour visuel "déjà au planning" sur les boutons    */
/* 📅 des cards /menu. Cards menu_home affichent .is-planned       */
/* quand la recette a une assignation dans la fenêtre 7j courante. */
/* ============================================================== */

.menu-action-plan-is-planned {
  background: color-mix(in srgb, var(--primary) 14%, var(--panel-sunken));
  border-color: var(--primary);
  color: var(--primary);
}

.menu-action-plan-is-planned:hover,
.menu-action-plan-is-planned:focus-visible {
  background: color-mix(in srgb, var(--primary) 22%, var(--panel-sunken));
  border-color: var(--primary);
  color: var(--primary);
}

.menu-action-plan-is-planned [aria-hidden="true"] {
  /* Léger glow primary sur l'icône — précédemment trop appuyé (signalé
     en revue UX, « un flou un peu bizarre, c'est un peu too much »).
     Réduit à 0.6px / 30% pour rester discret. */
  filter: drop-shadow(0 0 0.6px color-mix(in srgb, var(--primary) 30%, transparent));
}

/* Même état « déjà planifié » sur l'icône calendar de /recipes, adapté
   à la classe `.recipe-action-icon` (38–44px, icône Lucide). Hover scopé
   `(hover: hover)` cohérent avec les autres icônes de la rangée. */
.recipe-action-plan-is-planned {
  color: var(--primary);
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 14%, var(--panel-sunken));
}

.recipe-action-plan-is-planned .ico {
  filter: drop-shadow(0 0 0.6px color-mix(in srgb, var(--primary) 30%, transparent));
}

@media (hover: hover) {
  .recipe-action-plan-is-planned:hover,
  .recipe-action-plan-is-planned:focus-visible {
    background: color-mix(in srgb, var(--primary) 22%, var(--panel-sunken));
    border-color: var(--primary);
    color: var(--primary);
  }
}


/* ============================================================== */
/* Polish — /admin/logs : marges entre les blocs.                  */
/* Le bouton "Supprimer les journaux" était collé à la searchbar   */
/* et la pagination collée au tableau. Ajout d'espaces respirables.*/
/* ============================================================== */

.admin-logs-clear-form {
  margin-bottom: 18px;
}

.admin-pagination {
  margin-top: 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}



/* Picker autocomplete : mise en gras des "plats principaux" (Plat
   complet / Plat seul) dans le menu de suggestions du champ "Type"
   du form recette. Mis aussi en tête de liste côté back. */
.autocomplete-item-primary {
  font-weight: 700;
}

/* Entête de groupe dans le menu autocomplete (« Tes ingrédients » /
   « Suggestions » — enrichissement Ciqual du champ nom d'ingrédient).
   Non-interactive, collante en haut du scroll pour rester visible, thémée
   (même fond que le menu → les items défilent dessous sans transparence). */
.autocomplete-group {
  position: sticky;
  top: 0;
  padding: 7px 12px 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--panel-sunken);
  border-bottom: 1px solid var(--border);
  user-select: none;
}


/* ============================================================== */
/* Vague 7.6 — Spinners boutons après clic.                        */
/* Pattern : sur les forms taggés [data-spinner], au submit le     */
/* bouton submitter passe en .is-loading → spinner CSS pur (cercle */
/* qui tourne via @keyframes), texte caché (color:transparent), et */
/* disabled. Empêche le double-clic + donne un feedback immédiat.  */
/* Les handlers AJAX qui existent déjà désactivent eux-mêmes le    */
/* bouton ; cette classe complète juste avec le spinner visuel.    */
/* ============================================================== */

.btn.is-loading,
.menu-action.is-loading,
.menu-toolbar-btn.is-loading {
  position: relative;
  color: transparent !important;
  pointer-events: none;
  cursor: progress;
}

/* Préserver l'icône cachée par color:transparent — sinon le span
   aria-hidden="true" qui contient un emoji devient aussi invisible. */
.btn.is-loading > *,
.menu-action.is-loading > *,
.menu-toolbar-btn.is-loading > * {
  visibility: hidden;
}

.btn.is-loading::after,
.menu-action.is-loading::after,
.menu-toolbar-btn.is-loading::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 18px;
  height: 18px;
  margin: -9px 0 0 -9px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  color: #ffffff;
  animation: btn-spin 0.7s linear infinite;
  visibility: visible;
}

/* Boutons sur fond clair (ghost / secondary) : spinner en couleur primary
   sinon le blanc disparaît dans le fond. */
.btn.secondary.is-loading::after,
.menu-action.menu-action-ghost.is-loading::after {
  color: var(--primary);
}

@keyframes btn-spin {
  to { transform: rotate(360deg); }
}


/* ============================================================== */
/* Vague 7.6 — Skeleton screens sur images recettes lazy-loaded.   */
/* Fond gradient animé qui pulse pendant que <img loading="lazy">  */
/* charge l'image (typiquement quelques 100ms sur 3G). Une fois    */
/* l'image chargée, son opacité passe à 1 et masque le skeleton.   */
/* ============================================================== */

.menu-thumb img,
.recipe-row-thumb img {
  background:
    linear-gradient(
      90deg,
      color-mix(in srgb, var(--text) 6%, var(--panel-sunken)) 0%,
      color-mix(in srgb, var(--text) 12%, var(--panel-sunken)) 50%,
      color-mix(in srgb, var(--text) 6%, var(--panel-sunken)) 100%
    );
  background-size: 200% 100%;
  animation: skeleton-pulse 1.4s ease-in-out infinite;
}

/* Quand l'image est chargée, le background skeleton n'a plus d'utilité.
   Astuce : sur les <img> complets (image.complete=true), pas d'animation
   visible parce que l'image elle-même couvre le fond. Mais l'animation
   tourne quand même dans le DOM. Pour économiser CPU on l'arrête via
   un attribut data-loaded ajouté par le JS au load. */
img[data-loaded="1"] {
  animation: none;
  background: none;
}

@keyframes skeleton-pulse {
  0%   { background-position: 200% 50%; }
  100% { background-position: -200% 50%; }
}

@media (prefers-reduced-motion: reduce) {
  .menu-thumb img,
  .recipe-row-thumb img {
    animation: none;
  }
}


/* ============================================================== */
/* Branding Ribouns — wordmark serif + splash d'ouverture.         */
/* Le wordmark de la topbar et le nom du splash utilisent une      */
/* serif système italique (Georgia) — élégant, zéro dépendance,    */
/* conforme à la CSP (font-src 'self').                            */
/* Le splash est un overlay plein écran affiché uniquement au      */
/* lancement de l'app installée (cf static/js/splash_init.js qui   */
/* pose data-splash sur <html> avant le premier paint).            */
/* ============================================================== */

.brand a.brand-link {
  background: transparent;
  border: 1px solid transparent;
  padding: 6px 6px;
  font-size: inherit;
}

.brand a.brand-link:hover,
.brand a.brand-link:focus-visible {
  background: transparent;
  border-color: transparent;
}

.brand-logo {
  width: 28px;
  height: 28px;
  flex: 0 0 auto;
  display: block;
}

.brand-wordmark {
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
  font-weight: 600;
  font-size: 22px;
  letter-spacing: 0.3px;
  color: var(--text);
}

.app-splash {
  display: none;
}

html[data-splash] .app-splash {
  display: flex;
  position: fixed;
  inset: 0;
  z-index: 9999;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  background: #f1ede4;
  transition: opacity 0.45s ease;
}

html[data-splash="done"] .app-splash {
  opacity: 0;
  pointer-events: none;
}

.app-splash-logo {
  width: 132px;
  height: 132px;
}

.app-splash-name {
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
  font-weight: 600;
  font-size: 42px;
  letter-spacing: 0.5px;
  color: #2f3037;
}

@media (prefers-reduced-motion: reduce) {
  html[data-splash] .app-splash {
    transition: none;
  }
}


/* ============================================================== */
/* Lot 2 — Design system : accent terracotta, boutons, badges,     */
/* chips sélectionnables, en-tête de la carte de connexion.        */
/* Toutes les couleurs dérivent des tokens sémantiques (var) ou de */
/* color-mix → adaptation automatique aux 3 thèmes.                */
/* ============================================================== */

/* Boutons : alias explicite primary + variante ghost. */
.btn.primary {
  background: var(--primary);
  color: #ffffff;
}

.btn.ghost {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border);
}

@media (hover: hover) {
  .btn.primary:hover {
    background: var(--primary-hover);
  }

  .btn.ghost:hover {
    background: var(--hover-bg);
    border-color: var(--primary);
  }
}

/* Badges sémantiques (états / catégories). */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
  background: color-mix(in srgb, var(--primary) 14%, transparent);
  color: color-mix(in srgb, var(--primary) 70%, var(--text));
  border: 1px solid color-mix(in srgb, var(--primary) 32%, transparent);
}

.badge.is-success {
  background: color-mix(in srgb, var(--success) 15%, transparent);
  color: color-mix(in srgb, var(--success) 64%, var(--text));
  border-color: color-mix(in srgb, var(--success) 32%, transparent);
}

.badge.is-danger {
  background: color-mix(in srgb, var(--danger) 15%, transparent);
  color: color-mix(in srgb, var(--danger) 64%, var(--text));
  border-color: color-mix(in srgb, var(--danger) 32%, transparent);
}

.badge.is-warning {
  background: color-mix(in srgb, #d97706 16%, transparent);
  color: color-mix(in srgb, #d97706 62%, var(--text));
  border-color: color-mix(in srgb, #d97706 34%, transparent);
}

.badge.is-muted {
  background: var(--panel-2);
  color: var(--muted);
  border-color: var(--border);
}

/* Chip sélectionnable (catégorie active). */
.chip.is-selected {
  background: var(--primary);
  color: #ffffff;
  border-color: var(--primary);
}

/* En-tête de marque dans la carte de connexion / pages d'auth. */
.auth-card {
  padding: 26px 22px;
}

.auth-brand {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
}

.auth-brand-logo {
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
}

.auth-brand-name {
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
  font-weight: 600;
  font-size: 28px;
  letter-spacing: 0.3px;
  color: var(--text);
}

/* Bascule connexion ↔ inscription (lien sous le formulaire d'auth). */
.auth-switch {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  text-align: center;
  margin-bottom: 0;
}

.auth-switch a {
  color: var(--primary);
  font-weight: 600;
  text-decoration: none;
}

.auth-switch a:hover {
  text-decoration: underline;
}

/* Encart pédagogique sur /register (modèle de partage d'espace). */
.auth-info {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 12px 14px;
  margin-bottom: 18px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary);
  border-radius: 10px;
  background: var(--panel-sunken);
  color: var(--text);
  font-size: 0.92rem;
  line-height: 1.4;
}

.auth-info-icon {
  display: inline-flex;
  color: var(--primary);
  flex: 0 0 auto;
  margin-top: 2px;
}

/* Renvoi du lien de confirmation depuis le login (compte non confirmé). */
.auth-resend-form {
  margin-top: 16px;
}

/* Liens légaux discrets sous les cartes d'auth (accessibles sans compte). */
.legal-footer {
  margin: 18px auto 0;
  text-align: center;
  font-size: 0.82rem;
  color: var(--muted);
}

.legal-footer a {
  color: var(--muted);
  text-decoration: none;
}

.legal-footer a:hover {
  color: var(--primary);
  text-decoration: underline;
}

/* Case de consentement à l'inscription (CGU + confidentialité). */
.auth-consent {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 16px 0 0;
  font-size: 0.88rem;
  color: var(--muted);
  line-height: 1.4;
}

.auth-consent input {
  /* Sans width:auto, la règle globale `input { width: 100% }` étire la case à
     cocher sur toute la largeur (case centrée, texte tassé à droite). */
  width: auto;
  margin-top: 2px;
  flex: 0 0 auto;
}

.auth-consent span {
  flex: 1 1 auto;
  min-width: 0;
}

.auth-consent a {
  color: var(--primary);
}

/* Zone « danger » du compte (suppression). */
.account-danger {
  border-color: color-mix(in srgb, var(--danger) 40%, var(--border));
}

.account-delete-form {
  display: grid;
  gap: 10px;
}

/* Pages légales (CGU / confidentialité) — lisibilité prose. */
.legal-page {
  max-width: 760px;
}

.legal-page h2 {
  margin-top: 22px;
  font-size: 1.1rem;
}

.legal-page ul {
  margin: 8px 0;
  padding-left: 20px;
}

.legal-page li {
  margin: 4px 0;
}

/* Bandeau « confirme ton adresse mail » (inscription libre). Discret mais
   visible, s'adapte aux thèmes via les variables partagées. */
.verify-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 16px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--primary);
  border-radius: 10px;
  background: var(--panel-sunken);
  color: var(--text);
}

.verify-banner-text {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.verify-banner-icon {
  display: inline-flex;
  align-items: center;
  color: var(--primary);
  flex: 0 0 auto;
}

.verify-banner-form {
  flex: 0 0 auto;
  margin: 0;
}

.verify-banner-btn {
  white-space: nowrap;
}

/* Panneau super-admin « Inscription libre » (toggle global). */
.admin-signup-row {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

.admin-signup-state {
  display: inline-flex;
  align-items: center;
  padding: 4px 12px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 0.9rem;
  border: 1px solid var(--border);
}

.admin-signup-state.is-on {
  color: var(--success);
  border-color: color-mix(in srgb, var(--success) 50%, var(--border));
  background: color-mix(in srgb, var(--success) 12%, transparent);
}

.admin-signup-state.is-off {
  color: var(--muted);
}

.auth-title {
  font-size: 26px;
  margin: 0 0 4px;
}


/* ============================================================== */
/* Lot 3 — Iconographie Lucide. .ico suit le font-size (1em) et la */
/* couleur (currentColor) du conteneur → remplacement direct des   */
/* anciens emojis sans changer les tailles.                        */
/* ============================================================== */
.ico {
  width: 1em;
  height: 1em;
  display: inline-block;
  vertical-align: -0.125em;
  flex: 0 0 auto;
}


/* ============================================================== */
/* Résumé repliable des recettes planifiées (page planning →       */
/* liste de courses) : liste les recettes des jours cochés.        */
/* ============================================================== */
.planning-recap {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  margin-bottom: 16px;
  overflow: hidden;
}

.planning-recap-summary {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  cursor: pointer;
  list-style: none;
  font-weight: 600;
  color: var(--text);
}

.planning-recap-summary::-webkit-details-marker {
  display: none;
}

.planning-recap-icon {
  display: inline-flex;
  color: var(--primary);
  font-size: 18px;
}

.planning-recap-title {
  flex: 1;
}

.planning-recap-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  background: color-mix(in srgb, var(--primary) 14%, transparent);
  color: color-mix(in srgb, var(--primary) 72%, var(--text));
}

.planning-recap-chevron {
  display: inline-flex;
  color: var(--muted);
  font-size: 18px;
  transition: transform 0.18s ease;
}

.planning-recap[open] .planning-recap-chevron {
  transform: rotate(180deg);
}

.planning-recap-body {
  padding: 0 16px 14px;
  display: grid;
  gap: 14px;
}

.planning-recap-day-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 6px;
}

.planning-recap-day-date {
  opacity: 0.8;
}

.planning-recap-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 6px;
}

.planning-recap-item {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.planning-recap-slot {
  flex: 0 0 auto;
  min-width: 46px;
  font-size: 12px;
  color: var(--muted);
}

.planning-recap-name {
  flex: 1;
  font-weight: 500;
}

.planning-recap-servings {
  flex: 0 0 auto;
  font-size: 12px;
  color: var(--muted);
}

.planning-recap-empty {
  margin: 0;
  color: var(--muted);
  font-size: 14px;
}

/* Item avec poubelle (AJAX) — utilisé sur /menu/ingredients pour
   retirer une recette de la sélection. Le form est calé à droite et
   le bouton est en mode icon-only compact (32×32). */
.planning-recap-remove-form {
  margin: 0;
  display: inline-flex;
  align-items: center;
}

.planning-recap-remove-btn {
  width: 32px;
  height: 32px;
  border-radius: 8px;
}

.planning-recap-remove-btn .ico {
  width: 16px;
  height: 16px;
}

@media (prefers-reduced-motion: reduce) {
  .planning-recap-chevron {
    transition: none;
  }
}


/* ============================================================== */
/* Page /admin/users (Vague 9.3) — barre de filtres, badges de      */
/* statut, colonne d'actions empilées, ligne grisée si désactivé.   */
/* ============================================================== */
.admin-users-filter-form {
  margin-bottom: 14px;
  align-items: start;
}

.admin-user-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
}

.admin-user-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

.admin-user-row-disabled {
  opacity: 0.6;
}


/* ============================================================== */
/* Loader animé d'import recette : carrousel d'icônes d'aliments    */
/* en orbite + label, en overlay sur le panneau d'import pendant    */
/* l'analyse (URL / texte / photo). Icônes Lucide, couleurs thème.  */
/* ============================================================== */
.recipe-import-panel {
  position: relative;
}

.recipe-import-loader {
  position: absolute;
  inset: 0;
  z-index: 6;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  border-radius: inherit;
  background: color-mix(in srgb, var(--panel) 86%, transparent);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}

.recipe-import-loader:not([hidden]) {
  display: flex;
}

.recipe-import-loader-orbit {
  position: relative;
  width: 108px;
  height: 108px;
}

.recipe-import-loader-slot {
  position: absolute;
  top: 0;
  left: 50%;
  width: 34px;
  height: 34px;
  margin-left: -17px;
  transform-origin: 17px 54px;
  /* Chaque slot a SA propre animation (import-orbit-1…6) avec un angle de
     départ en valeur LITTÉRALE (0, 60, …, 300°). On évite à la fois
     l'animation-delay négatif ET le var()/calc() dans un keyframe : iOS Safari
     ne gère de façon fiable NI l'un NI l'autre sur un élément cloné
     dynamiquement (overlay de suppression) → les 6 icônes s'empilaient en
     « crotte ». Keyframes littérales = chaque icône part de son angle dès la
     1re frame, sans dépendre de delay ni de custom property. */
  animation: import-orbit-1 4.5s linear infinite;
  /* iOS Safari : force le compositing GPU pour que la rotation soit fluide. */
  will-change: transform;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

.recipe-import-loader-slot:nth-child(1) { animation-name: import-orbit-1; }
.recipe-import-loader-slot:nth-child(2) { animation-name: import-orbit-2; }
.recipe-import-loader-slot:nth-child(3) { animation-name: import-orbit-3; }
.recipe-import-loader-slot:nth-child(4) { animation-name: import-orbit-4; }
.recipe-import-loader-slot:nth-child(5) { animation-name: import-orbit-5; }
.recipe-import-loader-slot:nth-child(6) { animation-name: import-orbit-6; }

.recipe-import-loader-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  font-size: 26px;
  color: var(--primary);
  animation: import-orbit-pulse 1.5s ease-in-out infinite;
}

/* iOS Safari : un SVG en flex item avec width:1em (cf .ico) ne suit pas
   toujours le font-size du parent → s'effondre à 0×0. On force ici la
   taille en pixels SPÉCIFIQUEMENT pour les icônes du carousel (pas
   d'impact sur .ico ailleurs dans l'app). flex-shrink:0 empêche aussi
   un éventuel shrink en flex container étroit. */
.recipe-import-loader-icon > svg,
.recipe-import-loader-icon .ico {
  width: 26px;
  height: 26px;
  flex: 0 0 26px;
}

.recipe-import-loader-slot:nth-child(odd) .recipe-import-loader-icon {
  color: color-mix(in srgb, var(--primary) 65%, var(--success));
}

.recipe-import-loader-label {
  margin: 0;
  font-weight: 600;
  color: var(--text);
}

@keyframes import-orbit-1 { from { transform: rotate(0deg);   } to { transform: rotate(360deg); } }
@keyframes import-orbit-2 { from { transform: rotate(60deg);  } to { transform: rotate(420deg); } }
@keyframes import-orbit-3 { from { transform: rotate(120deg); } to { transform: rotate(480deg); } }
@keyframes import-orbit-4 { from { transform: rotate(180deg); } to { transform: rotate(540deg); } }
@keyframes import-orbit-5 { from { transform: rotate(240deg); } to { transform: rotate(600deg); } }
@keyframes import-orbit-6 { from { transform: rotate(300deg); } to { transform: rotate(660deg); } }

@keyframes import-orbit-pulse {
  0%, 100% { transform: scale(0.82); opacity: 0.7; }
  50% { transform: scale(1.1); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  /* Un loader DOIT tourner pour signaler « ça charge » → la rotation de
     l'orbite (.recipe-import-loader-slot) est un mouvement ESSENTIEL, on la
     garde même en mode réduit. On ne coupe que le pulse d'échelle des icônes,
     lui purement décoratif. Sans ça, sur iPhone (« Réduire les animations »
     activé, fréquent) le carousel restait figé en cercle sans tourner. */
  .recipe-import-loader-icon {
    animation: none;
  }
}


/* Lien « Voir la source » sur la fiche recette (recette importée). */
.menu-recipe-source {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 10px;
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
}

@media (hover: hover) {
  .menu-recipe-source:hover {
    color: var(--primary);
  }
}


/* ============================================================== */
/* Délices UI — pack « polish ambiant » (animations CSS pures,     */
/* thémées, coupées si prefers-reduced-motion).                    */
/* ============================================================== */
@media (prefers-reduced-motion: no-preference) {
  /* Cartes en fondu-montée décalé à l'arrivée (rejoué aussi au re-render
     AJAX d'une carte rerollée → la nouvelle carte fond joliment en place ;
     le stepper +/- met à jour le nombre en place, donc ne re-déclenche
     PAS l'animation). */
  .menu-card,
  .recipe-row {
    animation: ui-card-enter 0.42s cubic-bezier(0.22, 1, 0.36, 1) both;
  }
  .menu-stack > *:nth-child(2) { animation-delay: 0.04s; }
  .menu-stack > *:nth-child(3) { animation-delay: 0.08s; }
  .menu-stack > *:nth-child(4) { animation-delay: 0.12s; }
  .menu-stack > *:nth-child(5) { animation-delay: 0.16s; }
  .menu-stack > *:nth-child(n + 6) { animation-delay: 0.2s; }
  .recipes-list > *:nth-child(2) { animation-delay: 0.03s; }
  .recipes-list > *:nth-child(3) { animation-delay: 0.06s; }
  .recipes-list > *:nth-child(4) { animation-delay: 0.09s; }
  .recipes-list > *:nth-child(5) { animation-delay: 0.12s; }
  .recipes-list > *:nth-child(n + 6) { animation-delay: 0.15s; }

  /* Icône d'état vide qui lévite doucement (dé, panier, plat…). */
  .menu-empty-emoji {
    animation: ui-float 3.2s ease-in-out infinite;
  }

  /* Splash d'ouverture : le logo « respire » légèrement. */
  html[data-splash] .app-splash-logo {
    animation: ui-breathe 2.4s ease-in-out infinite;
  }

  /* Fiche recette : le panneau actif (Ingrédients/Consignes) fond en place
     au chargement et à chaque changement d'onglet. */
  .menu-recipe-pane:not([hidden]) {
    animation: ui-pane-fade 0.28s ease both;
  }
}

@keyframes ui-card-enter {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: none; }
}

@keyframes ui-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-7px); }
}

@keyframes ui-breathe {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.06); }
}

@keyframes ui-pane-fade {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}


/* ============================================================== */
/* Délices UI — pack 2 « le dé qui roule » : au clic sur            */
/* « Proposer un menu », le dé du CTA tournoie ~0,5 s avant le      */
/* POST (classe .is-rolling posée en JS sur .menu-hero-cta-emoji,   */
/* cf admin_common.js). Coupé si prefers-reduced-motion.           */
/* ============================================================== */
@media (prefers-reduced-motion: no-preference) {
  .menu-hero-cta-emoji.is-rolling .ico {
    animation: ui-dice-roll 0.25s cubic-bezier(0.45, 0.05, 0.3, 1);
  }
}

@keyframes ui-dice-roll {
  0% { transform: rotate(0deg) scale(1); }
  20% { transform: rotate(160deg) scale(1.2); }
  45% { transform: rotate(360deg) scale(0.94); }
  70% { transform: rotate(560deg) scale(1.12); }
  100% { transform: rotate(720deg) scale(1); }
}


/* ============================================================== */
/* Délices UI — pack 3 « célébration courses finies » : quand le   */
/* dernier article passe coché, une pluie de confettis thémés      */
/* (overlay .ui-celebrate injecté en JS, cf shopping_list_detail.js)*/
/* + un toast « Tout est coché ! ». Les pièces n'ont aucun style    */
/* inline : couleur / position / dérive viennent du :nth-child     */
/* (conforme CSP stricte). Coupé si prefers-reduced-motion (le JS   */
/* n'injecte alors rien, seul le toast reste).                      */
/* ============================================================== */
.ui-celebrate {
  position: fixed;
  inset: 0;
  z-index: 55;
  overflow: hidden;
  pointer-events: none;
}

.ui-celebrate-piece {
  position: absolute;
  top: -6vh;
  width: 9px;
  height: 14px;
  border-radius: 2px;
  opacity: 0;
  will-change: transform, opacity;
}

@media (prefers-reduced-motion: no-preference) {
  .ui-celebrate-piece {
    animation: ui-confetti-fall 1.5s cubic-bezier(0.3, 0.7, 0.5, 1) forwards;
  }
}

@keyframes ui-confetti-fall {
  0% { opacity: 0; transform: translate3d(0, 0, 0) rotate(0deg); }
  8% { opacity: 1; }
  100% { opacity: 0; transform: translate3d(var(--ui-drift, 0), 112vh, 0) rotate(560deg); }
}

/* Couleurs thémées en cycle (terracotta / vert / crème / mélange). */
.ui-celebrate-piece:nth-child(4n + 1) { background: var(--primary); }
.ui-celebrate-piece:nth-child(4n + 2) { background: var(--success); }
.ui-celebrate-piece:nth-child(4n + 3) { background: color-mix(in srgb, #ffffff 72%, var(--primary)); }
.ui-celebrate-piece:nth-child(4n) { background: color-mix(in srgb, var(--primary) 55%, var(--success)); }

/* Une pièce sur trois est ronde, pour casser la régularité. */
.ui-celebrate-piece:nth-child(3n) { width: 9px; height: 9px; border-radius: 50%; }

/* Position de départ, cadence et dérive horizontale par pièce. */
.ui-celebrate-piece:nth-child(1)  { left: 6%;  animation-delay: 0s;    animation-duration: 1.25s; --ui-drift: -14px; }
.ui-celebrate-piece:nth-child(2)  { left: 14%; animation-delay: 0.08s; animation-duration: 1.5s;  --ui-drift: 10px; }
.ui-celebrate-piece:nth-child(3)  { left: 22%; animation-delay: 0.02s; animation-duration: 1.15s; --ui-drift: -8px; }
.ui-celebrate-piece:nth-child(4)  { left: 30%; animation-delay: 0.14s; animation-duration: 1.4s;  --ui-drift: 16px; }
.ui-celebrate-piece:nth-child(5)  { left: 38%; animation-delay: 0.05s; animation-duration: 1.3s;  --ui-drift: -12px; }
.ui-celebrate-piece:nth-child(6)  { left: 46%; animation-delay: 0.18s; animation-duration: 1.55s; --ui-drift: 8px; }
.ui-celebrate-piece:nth-child(7)  { left: 54%; animation-delay: 0s;    animation-duration: 1.2s;  --ui-drift: 14px; }
.ui-celebrate-piece:nth-child(8)  { left: 62%; animation-delay: 0.12s; animation-duration: 1.45s; --ui-drift: -10px; }
.ui-celebrate-piece:nth-child(9)  { left: 70%; animation-delay: 0.06s; animation-duration: 1.32s; --ui-drift: 12px; }
.ui-celebrate-piece:nth-child(10) { left: 78%; animation-delay: 0.2s;  animation-duration: 1.5s;  --ui-drift: -16px; }
.ui-celebrate-piece:nth-child(11) { left: 86%; animation-delay: 0.03s; animation-duration: 1.18s; --ui-drift: 6px; }
.ui-celebrate-piece:nth-child(12) { left: 94%; animation-delay: 0.15s; animation-duration: 1.42s; --ui-drift: -6px; }
.ui-celebrate-piece:nth-child(13) { left: 10%; animation-delay: 0.24s; animation-duration: 1.6s;  --ui-drift: 18px; }
.ui-celebrate-piece:nth-child(14) { left: 50%; animation-delay: 0.1s;  animation-duration: 1.28s; --ui-drift: -18px; }
.ui-celebrate-piece:nth-child(15) { left: 34%; animation-delay: 0.22s; animation-duration: 1.38s; --ui-drift: 10px; }
.ui-celebrate-piece:nth-child(16) { left: 66%; animation-delay: 0.17s; animation-duration: 1.48s; --ui-drift: -12px; }


/* ============================================================== */
/* Délices UI — pack 4 « micro-feedback » : petits effets « le     */
/* temps d'une action ». Classes posées/retirées en JS (reroll,    */
/* stepper personnes, planifier, cochage). Coupés si               */
/* prefers-reduced-motion.                                          */
/* ============================================================== */
@media (prefers-reduced-motion: no-preference) {
  /* Stepper personnes : le nombre « pop » à chaque +/- (MAJ en place). */
  .menu-servings-value.is-bump {
    animation: ui-pop 0.32s cubic-bezier(0.34, 1.56, 0.64, 1);
  }

  /* Planifier : l'icône calendrier « pop » à la confirmation. */
  .ui-pop {
    animation: ui-pop 0.36s cubic-bezier(0.34, 1.56, 0.64, 1);
  }

  /* Cochage d'un article : pop de la case + barré qui balaie le nom. */
  body.page-shopping-list-detail .shopping-row.is-just-checked .shopping-check {
    animation: ui-check-pop 0.42s cubic-bezier(0.34, 1.56, 0.64, 1);
  }
  body.page-shopping-list-detail .shopping-row.is-just-checked .shopping-line-name {
    position: relative;
  }
  body.page-shopping-list-detail .shopping-row.is-just-checked .shopping-line-name::after {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    width: 100%;
    height: 2px;
    background: currentColor;
    transform-origin: left center;
    animation: ui-strike 0.42s ease forwards;
    pointer-events: none;
  }
}

@keyframes ui-spin {
  to { transform: rotate(360deg); }
}

@keyframes ui-pop {
  0% { transform: scale(1); }
  45% { transform: scale(1.4); }
  100% { transform: scale(1); }
}

@keyframes ui-check-pop {
  0% { transform: scale(1); }
  45% { transform: scale(1.32); }
  100% { transform: scale(1); }
}

@keyframes ui-strike {
  0% { transform: scaleX(0); opacity: 0.85; }
  70% { opacity: 0.85; }
  100% { transform: scaleX(1); opacity: 0; }
}


/* ============================================================== */
/* Délices UI — « repère-moi » : quand toutes les recettes du      */
/* filtre ont déjà été proposées, menu.random pose .menu-toolbar-  */
/* btn-attention sur le bouton « Mémoire » (recyclage) le temps de */
/* la page → quelques pulsations (halo terracotta + léger scale)   */
/* pour que l'utilisateur trouve le bouton à toucher. Coupé sous   */
/* prefers-reduced-motion (le message reste, lui).                 */
/* ============================================================== */
@media (prefers-reduced-motion: no-preference) {
  .menu-toolbar-btn-attention {
    animation: ui-attention 1.1s ease-in-out 3;
  }
}

@keyframes ui-attention {
  0% {
    transform: scale(1);
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--primary) 50%, transparent);
  }
  35% {
    transform: scale(1.07);
    box-shadow: 0 0 0 8px color-mix(in srgb, var(--primary) 0%, transparent);
  }
  100% {
    transform: scale(1);
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--primary) 0%, transparent);
  }
}

/* ============================================================== */
/* Liste des recettes — refonte boutons (icônes Lucide, 1 ligne)  */
/* ============================================================== */

/* La card en colonne (head + actions row), la grille du head devient
   simplement « thumb + info » (le toggle a déménagé dans les actions). */
.recipe-row-head {
  grid-template-columns: 72px 1fr;
}

/* Une seule rangée d'icônes en bas. Les 5 boutons se suivent (modifier,
   planifier, toggle menu, toggle courses, supprimer) — la poubelle est
   simplement en dernière position, sans margin-left:auto qui l'ancrait
   à l'extrême droite. */
.recipe-actions {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  justify-content: flex-start;
  flex-wrap: nowrap;
}

.recipe-action-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: var(--panel-sunken);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 10px;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.14s ease, color 0.14s ease, border-color 0.14s ease, transform 0.12s ease;
}

.recipe-action-icon .ico {
  width: 21px;
  height: 21px;
}

.recipe-action-icon:active {
  transform: scale(0.96);
}

/* Le form wrapper du Supprimer / du toggle Menu ne doit pas casser le
   layout flex (les <form> sont en flex item, comme les <a> / <button>). */
.recipe-action-delete-form,
.recipe-action-toggle-form {
  margin: 0;
  display: inline-flex;
}

.recipe-action-danger {
  color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 30%, var(--border));
}

/* Toggle Menu — vert par défaut (= « ajouter au menu »), rouge en .is-active
   (= « retirer du menu »). Pattern réutilisé pour le toggle Courses. */
.recipe-action-toggle-menu,
.recipe-action-toggle-courses {
  color: var(--success);
  border-color: color-mix(in srgb, var(--success) 40%, var(--border));
  background: color-mix(in srgb, var(--success) 10%, var(--panel-sunken));
}

/* Vague 7.10 — Toggles Menu/Courses actifs : MÊME couleur que le
   bouton de planification (`--primary` corail) au lieu du rouge danger,
   et drop-shadow PERCEPTIBLE (signalé revue UX : « pas la petite ombre
   comme sur le planning, on peut d'ailleurs mettre la même couleur que
   le planning quand c'est déjà coché »). Cohérence visuelle complète
   entre les 3 boutons d'état d'une card recette (planifié / au menu /
   en courses) — tous corail, tous avec drop-shadow équivalente. */
.recipe-action-toggle-menu.is-active,
.recipe-action-toggle-courses.is-active {
  color: var(--primary);
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 22%, var(--panel-sunken));
}

.recipe-action-toggle-menu.is-active .ico,
.recipe-action-toggle-courses.is-active .ico {
  /* Shadow plus appuyée (1.2px / 55%) que .recipe-action-plan-is-planned
     pour que ce soit vraiment visible — l'utilisateur avait signalé que
     la version 0.8px/40% précédente ne ressortait pas assez. */
  filter: drop-shadow(0 0 1.2px color-mix(in srgb, var(--primary) 55%, transparent));
}

/* Hover states scopés aux pointeurs SOUVRIS — sur tactile, :hover reste
   sticky après tap iOS/Android et la couleur du clic ne se relâche pas
   (bug remonté en revue). On garde le focus-visible (clavier) qui ne
   colle pas sur tactile. */
@media (hover: hover) {
  .recipe-action-icon:hover,
  .recipe-action-icon:focus-visible {
    background: color-mix(in srgb, var(--primary) 12%, var(--panel-sunken));
    border-color: var(--primary);
    color: var(--primary);
    outline: none;
  }

  .recipe-action-danger:hover,
  .recipe-action-danger:focus-visible {
    background: var(--danger);
    border-color: var(--danger);
    color: #ffffff;
  }

  .recipe-action-toggle-menu:hover,
  .recipe-action-toggle-menu:focus-visible,
  .recipe-action-toggle-courses:hover,
  .recipe-action-toggle-courses:focus-visible {
    background: var(--success);
    border-color: var(--success);
    color: #ffffff;
  }

  /* Vague 7.10 — Hover des toggles actifs : intensifie le fond primary
     au lieu de passer en danger (cohérence avec le nouvel état actif). */
  .recipe-action-toggle-menu.is-active:hover,
  .recipe-action-toggle-menu.is-active:focus-visible,
  .recipe-action-toggle-courses.is-active:hover,
  .recipe-action-toggle-courses.is-active:focus-visible {
    background: var(--primary);
    border-color: var(--primary);
    color: #ffffff;
  }
}

/* Petit label sous le titre de la modale Courses qui rappelle quelle
   recette on ajoute. Padding resserré pour rapprocher du « Liste cible ». */
.recipe-shopping-recipe-label {
  margin: 0 0 6px;
  font-size: 14px;
}

/* Mobile : on garde les 5 boutons sur la ligne, légèrement plus petits
   mais en gardant 40px de tap target (recommandation Apple/Google : 44).
   Les icônes restent lisibles (19px). */
@media (max-width: 480px) {
  .recipe-actions {
    gap: 5px;
  }
  .recipe-action-icon {
    width: 40px;
    height: 40px;
    border-radius: 9px;
  }
  .recipe-action-icon .ico {
    width: 19px;
    height: 19px;
  }
}

/* Très petits écrans (iPhone SE 320px) : on rogne encore pour tenir
   les 5 boutons sans débordement, mais tap target ≥ 36px. */
@media (max-width: 380px) {
  .recipe-actions {
    gap: 4px;
  }
  .recipe-action-icon {
    width: 36px;
    height: 36px;
    border-radius: 8px;
  }
  .recipe-action-icon .ico {
    width: 17px;
    height: 17px;
  }
}

/* ============================================================== */
/* Liste de courses (édition) — bloc « Recettes liées » repliable */
/* ============================================================== */

.shopping-linked-recipes {
  margin: 0 0 12px;
  padding: 0;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}

.shopping-linked-recipes-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  cursor: pointer;
  list-style: none;
  user-select: none;
  gap: 12px;
}

.shopping-linked-recipes-summary::-webkit-details-marker {
  display: none;
}

.shopping-linked-recipes-summary:hover {
  background: color-mix(in srgb, var(--primary) 6%, transparent);
}

.shopping-linked-recipes-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: var(--text);
}

.shopping-linked-recipes-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 7px;
  border-radius: 11px;
  background: color-mix(in srgb, var(--primary) 18%, var(--panel-sunken));
  color: var(--primary);
  font-size: 12px;
  font-weight: 700;
}

.shopping-linked-recipes-chevron {
  display: inline-flex;
  transition: transform 0.18s ease;
  color: var(--muted);
}

.shopping-linked-recipes-chevron .ico {
  width: 18px;
  height: 18px;
}

.shopping-linked-recipes[open] .shopping-linked-recipes-chevron {
  transform: rotate(180deg);
}

.shopping-linked-recipes-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 0 10px 12px;
}

.shopping-linked-recipes-empty {
  margin: 0;
  padding: 8px 4px;
  font-size: 13px;
  line-height: 1.5;
}

/* Bouton « + » à droite de « Recettes liées » dans le summary du bloc.
   Toujours visible (que le bloc soit plié ou déplié) → point d'entrée
   rapide vers le picker sans avoir à déplier d'abord. Le clic sur le
   bouton stoppe la propagation (cf shopping_add_recipes_dialog.js) pour
   ne pas toggler le <details>. Couleur **vert success** pour rester
   cohérent avec les toggles « Ajouter au menu » / « Ajouter aux courses »
   de /recipes (vert = action d'ajout). */
.shopping-linked-recipes-summary-add {
  color: var(--success);
  border-color: color-mix(in srgb, var(--success) 40%, var(--border));
  background: color-mix(in srgb, var(--success) 10%, var(--panel-sunken));
  width: 34px;
  height: 34px;
  border-radius: 9px;
}

.shopping-linked-recipes-summary-add .ico {
  width: 18px;
  height: 18px;
}

@media (hover: hover) {
  .shopping-linked-recipes-summary-add:hover,
  .shopping-linked-recipes-summary-add:focus-visible {
    background: var(--success);
    border-color: var(--success);
    color: #ffffff;
  }
}

.shopping-linked-recipes-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.shopping-linked-recipe-row {
  display: grid;
  grid-template-columns: 44px 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  background: var(--panel);
  border: 1px solid var(--border);
}

.shopping-linked-recipe-thumb-link {
  display: block;
  border-radius: 8px;
  overflow: hidden;
  transition: transform 0.12s ease;
}

.shopping-linked-recipe-thumb-link:hover {
  transform: scale(1.05);
}

.shopping-linked-recipe-thumb {
  width: 44px;
  height: 44px;
  border-radius: 8px;
  overflow: hidden;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  position: relative;
}

.shopping-linked-recipe-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.shopping-linked-recipe-thumb-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--panel-2) 0%, var(--panel-sunken) 100%);
}

.shopping-linked-recipe-thumb-fallback {
  opacity: 0.45;
}

.shopping-linked-recipe-thumb-fallback .ico {
  width: 20px;
  height: 20px;
}

.shopping-linked-recipe-name {
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  font-size: 14px;
  line-height: 1.3;
  word-break: break-word;
  min-width: 0;
}

.shopping-linked-recipe-name:hover {
  color: var(--primary);
}

.shopping-linked-recipe-unlink-form {
  margin: 0;
  display: inline-flex;
}

/* Bouton × rouge à droite de chaque recette liée — retire les ingrédients
   de la recette de la liste (best-effort par nom, items non cochés
   uniquement) ET le lien. Pattern danger plein au hover. */
.shopping-linked-recipe-unlink {
  color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 40%, var(--border));
  background: color-mix(in srgb, var(--danger) 10%, var(--panel-sunken));
}

@media (hover: hover) {
  .shopping-linked-recipe-unlink:hover,
  .shopping-linked-recipe-unlink:focus-visible {
    background: var(--danger);
    border-color: var(--danger);
    color: #ffffff;
  }
}

/* Ancien bouton + (re-add ingredients) retiré — conservé inerte ici au
   cas où des tests ou intégrations le référencent encore. */
.shopping-linked-recipe-add {
  color: var(--success);
  border-color: color-mix(in srgb, var(--success) 40%, var(--border));
  background: color-mix(in srgb, var(--success) 10%, var(--panel-sunken));
}

.shopping-linked-recipe-add:hover,
.shopping-linked-recipe-add:focus-visible {
  background: var(--success);
  border-color: var(--success);
  color: #ffffff;
}

/* ============================================================== */
/* Export-dialog — variante compacte (padding réduit + bouton     */
/* flottant en bas, icône courses). Appliquée via la classe       */
/* `.export-dialog-compact` aux 3 dialogs : toggle Courses sur    */
/* /recipes, picker « Ajouter des recettes » sur /shopping-lists. */
/* ============================================================== */

/* Le « body » regroupe les fieldsets target/mode du toggle Courses pour
   un padding cohérent (les fieldsets nus n'ont pas de cadre).

   Vague 7.9 bugfix — `flex: 1 1 auto; min-height: 0; overflow-y: auto`
   pour que le body soit la zone scrollable de la dialog. Sans ça, quand
   le contenu de la dialog dépasse la hauteur du viewport, le scroll
   passait à la page derrière au lieu de scroller le body de la dialog
   (signalé en revue UX : « ça scroll la page de derrière, je ne peux
   pas descendre pour choisir le type de repas »). Le header et le footer
   restent figés en haut/bas. */
.export-dialog-body {
  padding: 10px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* Évite que le scroll touch propage au body de la page derrière sur
     iOS Safari (qui ne respecte pas le scroll-lock natif de <dialog>). */
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

.export-dialog .export-target-fieldset,
.export-dialog .export-mode-fieldset {
  padding: 8px 10px;
}

/* Footer flottant : le bouton de soumission est large, success vif,
   icône `shopping-cart` à gauche du label — copie conforme du sticky
   bottom de /menu/ingredients (cf `.menu-ingredients-actions`). */
.export-dialog-footer-floating {
  padding: 10px 14px;
  background: var(--panel);
  border-top: 1px solid var(--border);
  box-shadow: 0 -6px 12px color-mix(in srgb, var(--shadow-color, rgba(0, 0, 0, 0.18)) 70%, transparent);
  position: sticky;
  bottom: 0;
}

.export-dialog-submit-floating {
  width: 100%;
  min-height: 46px;
  font-size: 15px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.export-dialog-submit-floating .ico {
  width: 18px;
  height: 18px;
}

@media (max-width: 540px) {
  .export-dialog-body,
  .export-dialog-footer-floating {
    padding-left: 10px;
    padding-right: 10px;
  }
}

/* Label discret « Recette : <name> » dans la modale Courses de /recipes —
   on évite la doublure du title de la modale, padding contenu. */
.recipe-shopping-recipe-label:empty {
  display: none;
}

/* ============================================================== */
/* /menu/ingredients & /menu/planning/ingredients — hero compact  */
/* + bouton flottant qui ouvre la dialog d'export (uniforme avec  */
/* les autres flows : /recipes Courses toggle, /shopping-lists    */
/* Ajouter des recettes).                                         */
/* ============================================================== */

/* Hero « Ingrédients à acheter » — réduction sensible des paddings
   (énormes sur mobile signalés en revue). */
.menu-ingredients-hero-compact {
  margin-bottom: 10px;
}

.menu-ingredients-hero-compact .menu-ingredients-hero-inner {
  padding: 12px 14px;
  border-radius: 14px;
}

.menu-ingredients-hero-compact .menu-ingredients-title {
  font-size: 20px;
  margin-bottom: 4px;
}

.menu-ingredients-hero-compact .menu-ingredients-subtitle {
  font-size: 13px;
}

/* Form devient plus serré : gap entre sections réduit. */
.menu-ingredients-form {
  gap: 12px;
}

/* Dialog d'export — réduction supplémentaire des paddings sur mobile
   (le user a signalé « écart énorme » entre les éléments). */
@media (max-width: 540px) {
  .menu-ingredients-hero-compact .menu-ingredients-hero-inner {
    padding: 10px 12px;
  }
  .menu-ingredients-hero-compact .menu-ingredients-title {
    font-size: 18px;
  }
  .menu-ingredients-hero-compact .menu-ingredients-subtitle {
    font-size: 12px;
  }
  .menu-planning-hero {
    padding: 8px 0 12px;
  }
  /* Tools / body / footer encore plus resserrés sous 540 */
  .export-dialog-compact .export-dialog-header {
    padding: 8px 10px;
  }
  .export-dialog-compact .export-dialog-body {
    padding: 8px 10px;
    gap: 8px;
  }
  .export-dialog-footer-floating {
    padding: 8px 10px;
  }
  .export-dialog-compact .export-target-fieldset,
  .export-dialog-compact .export-mode-fieldset {
    padding: 6px 8px;
  }
  /* Options « append / replace » resserrées pour ne pas faire monter
     la dialog en hauteur — un padding visuel sur chaque label suffit. */
  .export-dialog-compact .export-mode-option {
    padding: 6px 8px;
  }
}


/* ================================================================== */
/* Vague 7.9 — Refonte planning : `+` par jour + dialog 4 slots +     */
/* multi-recettes par créneau. L'ancien layout `menu-planning-slots-   */
/* grid` (midi/soir en 2 colonnes, 1 recette par slot) est remplacé    */
/* par une liste plate de lignes "Slot : Recette  Servings  🗑".       */
/* L'ajout passe par un seul `+` vert à droite du libellé du jour, qui */
/* ouvre la dialog `#planning-assign-dialog` (slot choisi à l'intérieur).*/
/* ================================================================== */

.menu-planning-day-head {
  /* Étend les règles existantes (.menu-planning-day-head ligne ~5228)
     pour caler le `+` vert à droite et le badge "Aujourd'hui" inline
     avec le libellé du jour. */
  flex-wrap: wrap;
  align-items: center;
}

.menu-planning-day-today-badge {
  font-size: 11px;
  padding: 2px 8px;
  margin-left: 8px;
  vertical-align: middle;
}

/* Bouton `+` vert à droite du libellé du jour. Hérite de .recipe-action-icon
   (44×44 desktop, 40×40 sm, 36×36 xs). Vert success comme tous les `+`
   de l'app (signalé en revue UX, « les + du planning doivent être verts
   comme le reste des + de l'app »). */
.menu-planning-day-add-btn {
  color: var(--success);
  border-color: color-mix(in srgb, var(--success) 40%, var(--border));
  background: color-mix(in srgb, var(--success) 10%, var(--panel-sunken));
}

@media (hover: hover) {
  .menu-planning-day-add-btn:hover,
  .menu-planning-day-add-btn:focus-visible {
    background: var(--success);
    border-color: var(--success);
    color: #ffffff;
  }
}

/* Liste des recettes planifiées du jour — une ligne par recette
   (multi-recettes par slot autorisé, ex. apéro avec focaccia + fougasse).
   Réinitialise le padding/style par défaut des <ul>. */
.menu-planning-day-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.menu-planning-day-row {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 10px;
  min-width: 0;
}

.menu-planning-day-slot {
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  font-size: 12px;
  letter-spacing: 0.5px;
  white-space: nowrap;
}

.menu-planning-day-recipe {
  font-size: 15px;
  color: var(--text);
  text-decoration: none;
  font-weight: 500;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.menu-planning-day-recipe:hover,
.menu-planning-day-recipe:focus-visible {
  color: var(--primary);
}

.menu-planning-day-recipe-muted {
  color: var(--muted);
  font-style: italic;
}

.menu-planning-day-servings {
  font-size: 13px;
  color: var(--muted);
  white-space: nowrap;
}

.menu-planning-day-clear-form {
  margin: 0;
  display: inline-flex;
  align-items: center;
}

/* Bouton poubelle plus compact dans cette liste (pas besoin du 44×44
   standard, on est dans une ligne dense). */
.menu-planning-day-clear-btn {
  width: 36px;
  height: 36px;
  border-radius: 8px;
}

.menu-planning-day-clear-btn .ico {
  width: 17px;
  height: 17px;
}

.menu-planning-day-empty {
  margin: 4px 0 0;
  padding: 8px 10px;
  font-size: 13px;
  color: var(--muted);
  background: var(--panel-sunken);
  border: 1px dashed var(--border);
  border-radius: 10px;
}

/* Sur tel : slot en label au-dessus du nom de recette pour gagner de
   la place horizontale (les noms longs ne sont pas écrasés). */
@media (max-width: 540px) {
  .menu-planning-day-row {
    grid-template-columns: 1fr auto auto;
  }
  .menu-planning-day-slot {
    grid-column: 1 / -1;
    margin-bottom: 2px;
  }
  .menu-planning-day-recipe {
    grid-column: 1;
  }
}


/* ================================================================== */
/* Vague 7.9 — Slots de planification (4 options : petit-déjeuner /    */
/* déjeuner / apéro / dîner). Pattern radio-chips réutilisé dans       */
/* `#planning-assign-dialog` (page /menu/planning) et                  */
/* `#planning-picker-dialog` (cross-page /menu + /recipes).            */
/* ================================================================== */

.planning-assign-slots {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
}

.planning-assign-slot-option {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 44px;
  padding: 8px 10px;
  cursor: pointer;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 10px;
  text-align: center;
  position: relative;
  font-size: 14px;
  color: var(--text);
  transition: border-color 120ms ease, background-color 120ms ease;
}

.planning-assign-slot-option input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.planning-assign-slot-option:has(input[type="radio"]:checked) {
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 14%, var(--panel-sunken));
  color: var(--primary);
  font-weight: 600;
}

@media (hover: hover) {
  .planning-assign-slot-option:hover {
    border-color: color-mix(in srgb, var(--primary) 40%, var(--border));
  }
}

@media (max-width: 380px) {
  /* Sur très petit écran, on bascule à 1 col pour ne pas tronquer
     « Petit-déjeuner ». */
  .planning-assign-slots {
    grid-template-columns: 1fr;
  }
}


/* ================================================================== */
/* Vague 7.9 — Picker planning (dialog cross-page) : navigation        */
/* semaine par flèches + grille de jours en boutons cliquables         */
/* (au lieu de radios cachés derrière des <label>). La grille est      */
/* rebuild en JS à chaque navigateWeek(), donc ces règles ciblent      */
/* aussi bien les chips serveur que ceux générés client.               */
/* ================================================================== */

.planning-picker-week-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

.planning-picker-week-nav .planning-picker-week-label {
  flex: 1;
  text-align: center;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}

.planning-picker-week-nav-btn {
  /* Hérite de .recipe-action-icon ; juste affiner le rendu visuel
     pour éviter qu'il ressemble à une action danger ou success. */
  color: var(--text);
  border-color: var(--border);
  background: var(--panel-sunken);
}

@media (hover: hover) {
  .planning-picker-week-nav-btn:hover,
  .planning-picker-week-nav-btn:focus-visible {
    background: color-mix(in srgb, var(--primary) 10%, var(--panel-sunken));
    border-color: var(--primary);
    color: var(--primary);
  }
}

/* Le picker historique utilisait des <label> autour de <input radio>.
   Vague 7.9 : `data-planning-picker-day` est un <button>, donc on
   redéfinit les états ici (le sélecteur :has(radio:checked) ne
   s'applique plus). */
.planning-picker-day-chip[data-planning-picker-day] {
  border: 1px solid var(--border);
  background: var(--panel-sunken);
  color: var(--text);
  cursor: pointer;
  transition: border-color 120ms ease, background-color 120ms ease;
}

.planning-picker-day-chip[data-planning-picker-day].is-selected {
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 14%, var(--panel-sunken));
  color: var(--primary);
}

@media (hover: hover) {
  .planning-picker-day-chip[data-planning-picker-day]:hover {
    border-color: color-mix(in srgb, var(--primary) 40%, var(--border));
  }
}


/* ================================================================== */
/* Vague 7.9 — Boost visuel de `is-planned` sur /recipes pour aligner  */
/* sur le rendu /menu (signalé en revue UX : « l'icône de planification*/
/* dans la liste des recettes doit être comme l'icône sur le menu     */
/* quand il y a planification, avec la petite shadow »). On garde le   */
/* drop-shadow déjà défini ligne ~6207 ET on renforce le contraste via */
/* un fond + une bordure primary plus marqués (pour que l'état soit    */
/* lisible même sur l'icône-seule 44×44 sans label texte).             */
/* ================================================================== */

.recipe-action-plan-is-planned {
  /* Réécrit les valeurs ligne ~6201 pour un rendu plus appuyé,
     comparable au bouton /menu (qui est plus large donc l'état "fond
     corail" est très visible). */
  background: color-mix(in srgb, var(--primary) 22%, var(--panel-sunken));
  border-color: var(--primary);
  color: var(--primary);
}

.recipe-action-plan-is-planned .ico {
  /* Drop-shadow légèrement plus marqué qu'avant (0.8px/40% au lieu de
     0.6px/30%) pour que l'effet de glow soit perceptible sur la petite
     icône 21×21 de la rangée d'actions /recipes. Reste discret — pas
     un « flou bizarre » comme l'ancienne version 1px/60%. */
  filter: drop-shadow(0 0 0.8px color-mix(in srgb, var(--primary) 40%, transparent));
}


/* ================================================================== */
/* Vague 7.9 — Listes de courses (index) : carte mobile retravaillée.  */
/*  - Nom de la liste cliquable (devient le lien d'ouverture, plus     */
/*    besoin du bouton "Ouvrir").                                      */
/*  - Bouton "Supprimer" remplacé par une poubelle rouge classique     */
/*    (cohérent avec le pattern du reste de l'app).                    */
/*  - Sur tel, la poubelle est placée sous le badge "Édition/Courses". */
/* ================================================================== */

.shopping-list-title-link {
  /* Le <a> qui enveloppe le titre — large surface de clic, pas de
     soulignement décoratif (le bloc fait office de bouton). */
  display: inline-block;
  color: inherit;
  text-decoration: none;
}

.shopping-list-title-link:hover .shopping-list-title,
.shopping-list-title-link:focus-visible .shopping-list-title {
  color: var(--primary);
}

.shopping-list-title-link:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 4px;
  border-radius: 4px;
}

/* Colonne droite du head : badges en haut, poubelle juste dessous.
   Sur grand écran comme sur tel, c'est aligné à droite. La rangée
   `.shopping-list-actions` historique a disparu — la poubelle vit
   maintenant dans `.shopping-list-head-actions` à côté du titre. */
.shopping-list-head-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
}

.shopping-list-delete-form {
  margin: 0;
}


/* ================================================================== */
/* Vague 7.9 — Desktop : labels texte à côté des icônes sur les pages  */
/* qui n'en avaient que des icônes (gain de clarté sur grand écran,    */
/* le mobile reste icon-only pour économiser la place — cf revue UX :  */
/* « sur ordinateur on peut afficher du texte en plus des icônes »).   */
/* Pattern : `.recipe-action-icon-label` est `display:none` par défaut */
/* et bascule à `inline` au-dessus du breakpoint MD (>= 760px).        */
/* ================================================================== */

.recipe-action-icon-label {
  display: none;
}

@media (min-width: 760px) {
  /* On élargit `.recipe-action-icon` pour qu'il accommode le texte —
     plus carré, devient pill horizontal. Le label suit le `.ico`
     avec un gap de 6px. */
  .recipe-action-icon:has(.recipe-action-icon-label) {
    width: auto;
    min-width: 44px;
    padding: 0 12px;
    gap: 6px;
  }
  .recipe-action-icon-label {
    display: inline;
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
  }
}


/* ================================================================== */
/* Vague 7.9 — Body scroll-lock quand une dialog modale est ouverte.   */
/* `<dialog>.showModal()` empêche le scroll au clavier mais sur iOS    */
/* Safari & certains Android, un scroll touch peut passer au body de  */
/* la page derrière. Le `:has()` natif modernise ça côté CSS pur.     */
/* ================================================================== */

html:has(dialog[open]),
body:has(dialog[open]) {
  overflow: hidden;
}


/* ================================================================== */
/* Vague 7.9 — Desktop : searchbar /recipes — réafficher les icônes à  */
/* gauche des labels (signalé en revue UX : « rajouter les icônes de   */
/* tel à gauche des textes 'rechercher' 'effacer' etc. »), et ne plus  */
/* ancrer les boutons à droite (« sur ordinateur il faut arrêter       */
/* d'ancrer les boutons à droite »). Le pattern .btn (display:         */
/* inline-flex; gap: 6px) gère naturellement icône + label côte à      */
/* côte une fois `.search-icon` ré-affichée.                           */
/* ================================================================== */

@media (min-width: 701px) {
  /* On override le `display: none` desktop par défaut (cf bloc top du
     fichier ligne ~479) pour réafficher les icônes à côté du label. */
  .search-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* Le label reste visible (default desktop) — on réaffirme juste pour
     la lisibilité du bloc. */
  .search-label {
    display: inline;
  }

  /* Boutons d'actions de la searchbar : alignement à gauche (au plus
     proche du champ de recherche) plutôt qu'à droite. Plus intuitif
     sur grand écran (signalé revue UX). */
  .search-actions {
    justify-content: flex-start;
  }
}


/* ================================================================== */
/* Vague 7.9 — Overlay plein écran « page figée » pendant l'unlink     */
/* d'une recette d'une liste de courses. Le mini spinner inline de la  */
/* 1re itération n'était pas assez visible (signalé revue UX : « le    */
/* carousel ne marche pas ») et le DOM swap n'actualisait pas le mode  */
/* édition (`.shopping-categories` n'existe qu'en mode locked). On     */
/* fige donc la page min 1.5 s avec un gros carousel central pendant   */
/* qu'on POST + reload — le backend a le temps de traiter et le        */
/* feedback est sans ambiguïté.                                        */
/* ================================================================== */

.shopping-freeze-overlay {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--panel) 70%, rgba(0, 0, 0, 0.55));
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  animation: ribouns-freeze-fade-in 180ms ease-out both;
}

.shopping-freeze-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  padding: 28px 36px;
  border-radius: 18px;
  background: var(--panel);
  border: 1px solid var(--border);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35);
  min-width: 220px;
  max-width: min(360px, calc(100vw - 32px));
}

/* Vague 7.10 — Le carousel orbit hérite des styles de .recipe-import-
   loader-orbit (cf bloc « Loader animé d'import recette ») dès qu'on
   clone le <template>. Pas de surcharge nécessaire — les icônes
   tournent en rond, taille fixe 108×108. On centre juste dans la carte. */

.shopping-freeze-spinner {
  width: 56px;
  height: 56px;
  border: 5px solid color-mix(in srgb, var(--primary) 25%, transparent);
  border-top-color: var(--primary);
  border-radius: 50%;
  /* Réutilise `btn-spin` (ligne ~6360) — keyframe déjà définie, on
     évite d'en dupliquer une autre. */
  animation: btn-spin 0.85s linear infinite;
}

.shopping-freeze-label {
  text-align: center;
  font-size: 14px;
  color: var(--text);
  font-weight: 500;
}

@keyframes ribouns-freeze-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}


/* ================================================================== */
/* Vague 7.10 — /recipes filtres (Durée + Type de plat).               */
/* L'ancien fork /menu/manual a été retiré (signalé revue UX : « les   */
/* popups étaient archi dégueu »). Nouveau design : bouton « Filtres » */
/* dans la searchbar (badge primary si actif) qui ouvre une dialog     */
/* .export-dialog (cohérence avec les autres avant-plans de l'app),    */
/* avec des chips bien espacés, header titre, footer Reset/Appliquer.  */
/* ================================================================== */

/* Bouton Filtres : badge primary affichant le nombre de filtres actifs. */
.recipes-filters-btn.is-active {
  color: var(--primary);
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 14%, var(--panel-sunken));
}

.recipes-filters-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  margin-left: 4px;
  border-radius: 999px;
  background: var(--primary);
  color: #ffffff;
  font-size: 11px;
  font-weight: 700;
  vertical-align: middle;
}

/* À 0 filtre actif, le badge est marqué [hidden] côté JS. Sans ça, le
   display:inline-flex ci-dessus écraserait le display:none de [hidden] et
   laisserait un badge vide (« boule orange ») ou un « 0 » résiduel. */
.recipes-filters-count[hidden],
.planning-assign-filters-count[hidden] {
  display: none;
}

/* Le dialog hérite de .export-dialog (sizing/padding uniformes). On
   pose juste les chips et la mise en page sections. */
.recipes-filters-dialog .export-dialog-body {
  /* Plus d'espacement entre sections (Durée vs Type de plat) pour la
     lisibilité — pattern « card resserrée » des autres dialogs ne
     convient pas ici, on veut respirer. */
  gap: 18px;
}

.recipes-filters-section {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.recipes-filters-section-title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}

.recipes-filters-section-title .ico {
  width: 18px;
  height: 18px;
  color: var(--muted);
}

.recipes-filters-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.recipes-filters-chip {
  display: inline-flex;
  align-items: center;
  position: relative;
  padding: 9px 14px;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 999px;
  cursor: pointer;
  user-select: none;
  font-size: 14px;
  color: var(--text);
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
  min-height: 38px;
}

.recipes-filters-chip input[type="checkbox"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.recipes-filters-chip-label {
  position: relative;
  z-index: 1;
}

.recipes-filters-chip:has(input[type="checkbox"]:checked) {
  background: var(--primary);
  border-color: var(--primary);
  color: #ffffff;
  font-weight: 600;
}

@media (hover: hover) {
  .recipes-filters-chip:hover {
    border-color: color-mix(in srgb, var(--primary) 50%, var(--border));
  }
  .recipes-filters-chip:has(input[type="checkbox"]:checked):hover {
    background: color-mix(in srgb, var(--primary) 88%, #000);
  }
}

/* Footer du dialog filtres : Apply à gauche (action principale), Reset
   à droite (action secondaire). Signalé revue UX : « Appli à gauche
   et reset à droite ». L'ordre dans le DOM reste Reset-puis-Apply (tab
   order naturel), on inverse uniquement à l'affichage via flex-row-
   reverse. */
.recipes-filters-footer {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-direction: row-reverse;
  /* Vague 9.5+++ — Bug fix : `.export-dialog-footer` parent a
     `flex-wrap: wrap`. On force nowrap pour garder les 2 boutons côte
     à côte. */
  flex-wrap: nowrap;
}

.recipes-filters-reset-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  /* Match la hauteur du bouton Apply (`.export-dialog-submit-floating
     { min-height: 46px }`) pour que les 2 boutons soient alignés
     visuellement, et pas Reset rikiki à côté d'un Apply 2× plus haut
     (signalé revue UX : « le bouton reset est encore tout petit,
     il fait 2px de haut »). */
  min-height: 46px;
}

.recipes-filters-footer .export-dialog-submit-floating {
  flex: 1 1 auto;
  /* Override le `width: 100%` du pattern de base (qui forçait le wrap
     dans le footer 2-boutons). */
  width: auto;
}

@media (max-width: 480px) {
  /* Sur tel : reset devient compact (icône seule), apply prend la place. */
  .recipes-filters-reset-btn span:not([aria-hidden]) {
    display: none;
  }
  .recipes-filters-reset-btn {
    /* Carré 46×46 pour matcher la hauteur du bouton Apply
       (.export-dialog-submit-floating min-height: 46px). */
    width: 46px;
    min-width: 46px;
    min-height: 46px;
    padding: 0;
    justify-content: center;
  }
}

/* Vague 9.5+++ — Réduction du padding de la dialog filtres pour gagner
   ~16-20 px verticaux (signalé revue UX : « on peut gagner de la place
   en haut et en bas si jamais sur le padding »). Ciblé uniquement sur
   `.recipes-filters-dialog` — les autres `.export-dialog` (assign,
   shopping, etc.) gardent leur padding standard. */
.recipes-filters-dialog .export-dialog-header {
  padding: 8px 12px;
}

.recipes-filters-dialog .export-dialog-body {
  padding: 8px 12px;
  gap: 14px;
}

.recipes-filters-dialog .export-dialog-footer-floating {
  padding: 8px 12px;
}

.recipes-filters-dialog .recipes-filters-section {
  gap: 8px;
}

/* Vague 9.5+++ — Override mobile : le pattern par défaut
   `.export-dialog-footer` à <= 540 px passe en `flex-direction:
   column-reverse` + `.export-dialog-footer .btn { width: 100% }` (le
   submitter prend toute la largeur, Reset wrap en dessous). C'est
   bien pour les dialogs 1-bouton, mais pour le footer 2-boutons
   filtres on veut Reset + Apply côte à côte aussi sur tel, avec
   Apply à GAUCHE et Reset à droite. Signalé revue UX deux fois :
   « le bouton reset est côte à côte sur ordi mais pas sur tel » puis
   « Appli à gauche et reset à droite ». */
@media (max-width: 540px) {
  .recipes-filters-footer.export-dialog-footer {
    /* row-reverse comme sur desktop → Apply à gauche, Reset à droite.
       (Avant : `flex-direction: row` qui annulait le row-reverse parent.) */
    flex-direction: row-reverse;
    align-items: center;
    flex-wrap: nowrap;
  }
  .recipes-filters-footer.export-dialog-footer .btn {
    width: auto;
  }
  /* Reset reste compact (icône seule, 44 px) — déjà géré par le bloc
     @media (max-width: 480px) plus haut. */
}


/* ================================================================== */
/* Vague 7.10 — Transitions de page entre vues (View Transitions API). */
/* Signalé revue UX : « un petit balayage léger quand on change de    */
/* fenêtre, surtout sur tel ». Utilise l'API View Transitions du W3C   */
/* en mode `navigation: auto` (cross-document) → l'animation est       */
/* gérée par le browser, pas de JS, pas de SPA, fallback silencieux    */
/* sur les browsers qui ne supportent pas.                             */
/*                                                                     */
/* Support : Chrome 126+, Safari 18+ ; Firefox = no-op (graceful).     */
/* Le user voit alors la navigation classique instantanée — pas de     */
/* dégradation visuelle, juste l'absence d'animation.                  */
/* ================================================================== */

@view-transition {
  navigation: auto;
}

/* On isole la topbar et la bottom-nav du root snapshot pour qu'elles
   restent stables visuellement pendant la transition (pas de slide
   sur les chrome elements — uniquement le contenu central bouge). Le
   `view-transition-name` doit être unique par page → safe ici puisque
   topbar/bottom-nav ne sont rendues qu'une fois dans le base.html. */
.topbar {
  view-transition-name: ribouns-topbar;
}

.bottom-nav {
  view-transition-name: ribouns-bottom-nav;
}

/* Le contenu principal (= tout le reste sous le root par défaut) reçoit
   l'animation fade + petit rise. Subtil pour éviter l'effet "lourd"
   quand le user enchaîne les navigations. Coupé sous prefers-reduced-
   motion (le user qui demande à réduire le mouvement n'a rien à voir). */
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root) {
    animation-name: ribouns-page-old;
    animation-duration: 160ms;
    animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
    animation-fill-mode: both;
  }

  ::view-transition-new(root) {
    animation-name: ribouns-page-new;
    animation-duration: 240ms;
    animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
    animation-fill-mode: both;
  }

  /* Topbar et bottom-nav font un simple fade pour rester rassurantes
     (pas de slide horizontal sur la chrome — sinon l'utilisateur se
     perd). */
  ::view-transition-old(ribouns-topbar),
  ::view-transition-new(ribouns-topbar),
  ::view-transition-old(ribouns-bottom-nav),
  ::view-transition-new(ribouns-bottom-nav) {
    animation-duration: 200ms;
    animation-timing-function: ease;
  }

  ::view-transition-old(ribouns-topbar),
  ::view-transition-old(ribouns-bottom-nav) {
    animation-name: ribouns-chrome-fade-out;
  }

  ::view-transition-new(ribouns-topbar),
  ::view-transition-new(ribouns-bottom-nav) {
    animation-name: ribouns-chrome-fade-in;
  }
}

@keyframes ribouns-page-old {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-6px); }
}

@keyframes ribouns-page-new {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes ribouns-chrome-fade-out {
  from { opacity: 1; }
  to   { opacity: 0.85; }
}

@keyframes ribouns-chrome-fade-in {
  from { opacity: 0.85; }
  to   { opacity: 1; }
}


/* ================================================================== */
/* Vague 7.10 — Animation de départ/arrivée d'une ligne shopping     */
/* quand on coche / décoche un article en mode locked (vue courses). */
/* Signalé revue UX : « l'ingrédient disparaît un peu violemment ».  */
/* Le pattern combine 3 phases :                                     */
/*   1. is-just-checked (existant) : pop de la case + strike du nom  */
/*   2. is-leaving (nouveau) : la ligne glisse de ~24px vers le bas  */
/*      et fade out + shrink léger pendant 320 ms                    */
/*   3. is-arriving (nouveau) : à l'arrivée dans le bloc « Articles  */
/*      cochés » (ou retour au magasin si décoche), petit fade-in    */
/*      de 220 ms pour signaler que la ligne a atterri               */
/* Coupé sous prefers-reduced-motion (le user qui demande à réduire  */
/* le mouvement aura le DOM swap instantané, comme avant 7.10).      */
/* ================================================================== */

@media (prefers-reduced-motion: no-preference) {
  body.page-shopping-list-detail .shopping-row.is-leaving {
    animation: shopping-row-leave 320ms cubic-bezier(0.4, 0, 0.2, 1) both;
    pointer-events: none;
  }

  body.page-shopping-list-detail .shopping-row.is-arriving {
    animation: shopping-row-arrive 220ms cubic-bezier(0, 0, 0.2, 1) both;
  }
}

@keyframes shopping-row-leave {
  0% {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
  40% {
    opacity: 0.6;
  }
  100% {
    opacity: 0;
    transform: translateY(24px) scale(0.96);
  }
}

@keyframes shopping-row-arrive {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}


/* ================================================================== */
/* Vague 9.5+ — Picker recette enrichi dans le dialog d'assignation    */
/* planning (search + filtres durée/type, façon /recipes). Remplace    */
/* l'ancien <select> tout simple qui devenait inutilisable dès 30+    */
/* recettes. Filtrage 100% client via menu_planning_assign_dialog.js. */
/* ================================================================== */

/* Vague 9.5+++ — Bug fix containment fieldset : avant, le <fieldset>
   avait `display: flex; flex-direction: column` directement, et la
   liste avec `max-height: 38vh` débordait visuellement sous le bord
   inférieur du fieldset (les fieldsets en flex ont des bugs de
   containment connus dans tous les browsers). Maintenant le fieldset
   reste un `block` normal et c'est `.planning-assign-recipe-content`
   (wrapper interne dans le template) qui gère le flex column. */
.planning-assign-recipe-picker {
  display: block;
  /* Override `min-width: min-content` par défaut des fieldsets, qui
     empêche le fieldset de shrink correctement sur petit écran. */
  min-width: 0;
}

.planning-assign-recipe-content {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
}

/* Vague 9.5++ — Toolbar refactor : layout horizontal (search prend
   l'espace restant, bouton Filtres à droite). Sur tel le label du
   bouton se cache pour laisser le bouton en icône seule. Pattern
   identique à la searchbar de /recipes. */
.planning-assign-recipe-tools {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
}

.planning-assign-recipe-tools .planning-assign-recipe-search-field {
  flex: 1 1 auto;
  min-width: 0;
}

.planning-assign-filters-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  min-height: 42px;
}

.planning-assign-filters-btn.is-active {
  color: var(--primary);
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 14%, var(--panel-sunken));
}

.planning-assign-filters-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--primary);
  color: #ffffff;
  font-size: 11px;
  font-weight: 700;
}

@media (max-width: 480px) {
  .planning-assign-filters-btn-label {
    display: none;
  }
  .planning-assign-filters-btn {
    width: 44px;
    min-width: 44px;
    padding: 0;
    justify-content: center;
  }
}

/* Champ de recherche : input + icône à gauche, pattern réutilisé de
   .menu-manual-search-field (cf bloc plus haut). */
.planning-assign-recipe-search-field {
  position: relative;
  display: flex;
  align-items: center;
}

.planning-assign-recipe-search-icon {
  position: absolute;
  left: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  pointer-events: none;
}

.planning-assign-recipe-search-icon .ico {
  width: 16px;
  height: 16px;
}

.planning-assign-recipe-search-input {
  width: 100%;
  padding: 10px 12px 10px 34px;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 14px;
  color: var(--text);
}

.planning-assign-recipe-search-input:focus {
  outline: none;
  border-color: var(--primary);
}

/* Vague 9.5++ — Les anciens <details> inline filter blocks
   `.planning-assign-recipe-filters`, `.planning-assign-filter-*` ont
   été retirés. Les filtres durée+type vivent désormais dans une dialog
   dédiée `#planning-assign-filters-dialog` qui réutilise les classes
   `.recipes-filters-section`, `.recipes-filters-chips`,
   `.recipes-filters-chip` du picker /recipes. Cohérence visuelle et
   pas de débordement sur tel.

   Liste des recettes : scrollable, radio sélection unique. */
.planning-assign-recipe-list {
  list-style: none;
  margin: 0;
  padding: 0;
  flex: 1 1 auto;
  min-height: 80px;
  max-height: 38vh;
  overflow-y: auto;
  background: var(--panel-sunken);
  border: 1px solid var(--border);
  border-radius: 10px;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

.planning-assign-recipe-item {
  border-bottom: 1px solid var(--border);
}

.planning-assign-recipe-item:last-child {
  border-bottom: none;
}

.planning-assign-recipe-item[hidden] {
  display: none;
}

.planning-assign-recipe-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  cursor: pointer;
  min-height: 44px;
  transition: background 120ms ease;
}

.planning-assign-recipe-row input[type="radio"] {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  accent-color: var(--primary);
  cursor: pointer;
}

.planning-assign-recipe-content {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1 1 auto;
}

.planning-assign-recipe-name {
  font-size: 14px;
  color: var(--text);
  font-weight: 500;
  word-break: break-word;
}

.planning-assign-recipe-meta {
  font-size: 12px;
  color: var(--muted);
}

@media (hover: hover) {
  .planning-assign-recipe-row:hover {
    background: var(--hover-bg);
  }
}

/* Row sélectionnée : fond corail discret pour confirmer le choix. */
.planning-assign-recipe-item:has(input[type="radio"]:checked) .planning-assign-recipe-row {
  background: color-mix(in srgb, var(--primary) 14%, var(--panel-sunken));
}

.planning-assign-recipe-empty,
.planning-assign-recipe-no-match {
  margin: 12px 0 0;
  padding: 12px;
  text-align: center;
  font-size: 13px;
  background: var(--panel-sunken);
  border: 1px dashed var(--border);
  border-radius: 10px;
}

@media (max-width: 480px) {
  .planning-assign-recipe-list {
    max-height: 32vh;
  }
}

/* /menu/ingredients — rows en lecture seule (décision 2026-06 : plus de
   sélection par ingrédient, on importe tout). Le label n'est plus un
   contrôle cliquable → on neutralise curseur main + survol. */
.menu-ingredient-label-static {
  cursor: default;
}
.menu-ingredient-label-static:hover {
  background: transparent;
}

/* ============================================================== */
/* Form recette — éditeur de consignes en blocs (1 étape = 1 bloc) */
/* Chaque étape : numéro à gauche + zone de texte editable + bouton */
/* supprimer. Un « + » discret entre deux blocs insère une étape.   */
/* Cf static/js/recipe_steps_editor.js.                             */
/* ============================================================== */

.steps-editor {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 4px;
}

.step-block {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.step-block:focus-within {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 18%, transparent);
}

/* Numéro d'étape — pastille ronde primary, alignée en haut du bloc. */
.step-block-num {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  margin-top: 2px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: color-mix(in srgb, var(--primary) 16%, transparent);
  color: var(--primary);
  font-weight: 700;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  user-select: none;
}

.step-block-text {
  flex: 1 1 auto;
  min-height: 28px;
  padding: 4px 6px;
  border-radius: 8px;
  line-height: 1.5;
  color: var(--text);
  outline: none;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.step-block-text:empty::before {
  content: attr(data-placeholder);
  color: var(--muted);
  pointer-events: none;
}

/* Bouton supprimer l'étape — compact, aligné en haut. */
.step-block-remove {
  flex: 0 0 auto;
  margin-top: 0;
  padding: 6px 8px;
  min-height: 0;
  line-height: 0;
}

/* Rangée « + » entre deux blocs : discrète, se révèle au survol /
   focus de la zone éditeur pour ne pas surcharger visuellement. */
.step-insert {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 14px;
  position: relative;
}

/* Trait + bouton « + » TOUJOURS visibles (desktop ET mobile). Sur tel il
   n'y a pas de survol, donc on n'attend plus le hover pour les révéler —
   ils restent affichés en permanence (couleur sobre au repos, primary au
   survol/focus sur ordi). */
.step-insert::before {
  content: "";
  position: absolute;
  left: 38px;
  right: 12px;
  top: 50%;
  height: 1px;
  background: var(--border);
}

.step-insert-btn {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--panel);
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.step-insert-btn:hover,
.step-insert-btn:focus-visible {
  color: var(--primary);
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 12%, var(--panel));
  outline: none;
}

.step-insert-btn .ico {
  width: 14px;
  height: 14px;
}

/* Bouton « Ajouter une étape » en bas de l'éditeur. */
.steps-add {
  margin-top: 8px;
}

.steps-add-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Mobile : pastille + bouton un peu plus compacts. */
@media (max-width: 480px) {
  .step-block {
    gap: 8px;
    padding: 7px;
  }
  .step-block-num {
    width: 24px;
    height: 24px;
    font-size: 12px;
  }
}

/* --------------------------------------------------------------------------- */
/* Partage de recettes (vague 13) — page d'envoi, boîte de réception, landing. */
/* --------------------------------------------------------------------------- */

/* Lien « Partager cette recette » sous la ligne d'actions de la fiche. */
.menu-recipe-share-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 12px;
  font-size: 14px;
  font-weight: 600;
  color: var(--muted);
  text-decoration: none;
}
.menu-recipe-share-link:hover {
  color: var(--primary);
}
.menu-recipe-share-link .ico {
  width: 16px;
  height: 16px;
}

/* Page « Partager une recette ». */
.share-form {
  margin: 14px 0;
}
.share-label {
  display: block;
  font-weight: 600;
  margin-bottom: 6px;
}
.share-row {
  display: flex;
  gap: 8px;
  align-items: stretch;
}
.share-row input {
  flex: 1 1 auto;
  min-width: 0;
}
.share-row .btn {
  flex: 0 0 auto;
  white-space: nowrap;
}
.share-hint {
  margin-top: 6px;
  font-size: 13px;
}
.share-sep {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 18px 0;
  color: var(--muted);
  font-size: 13px;
}
.share-sep::before,
.share-sep::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--border);
}
.share-link-box {
  margin-top: 14px;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel-2);
}

/* Boîte de réception « Recettes reçues ». */
.share-inbox {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 14px;
}
.share-inbox-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel-2);
}
.share-inbox-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.share-inbox-name {
  font-weight: 700;
}
.share-inbox-from {
  font-size: 13px;
  color: var(--muted);
}
.share-inbox-actions {
  display: flex;
  gap: 8px;
  flex: 0 0 auto;
}

/* Landing publique d'un lien de partage. */
.share-landing {
  text-align: center;
}
.share-landing-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  margin: 0 auto 8px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--primary) 15%, transparent);
  color: var(--primary);
}
.share-landing-icon .ico {
  width: 28px;
  height: 28px;
}
.share-landing-recipe {
  font-size: 18px;
  font-weight: 700;
  margin: 4px 0 14px;
}
.share-landing-cta {
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
}

/* Badge compteur + pastille de notification (boîte « Recettes reçues »). */
.share-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  margin-left: auto;
  border-radius: 9px;
  background: var(--primary);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
}
.nav-label .share-badge {
  margin-left: 4px;
}
.bottom-nav-more-summary,
.nav-more-summary {
  position: relative;
}
.share-dot {
  position: absolute;
  top: 2px;
  right: 6px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--primary);
  box-shadow: 0 0 0 2px var(--panel-2);
  pointer-events: none;
}

/* --------------------------------------------------------------------------- */
/* Régime & allergies (vague 13.x) — section du form recette.                  */
/* --------------------------------------------------------------------------- */
.recipe-diet-suggest {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
  padding: 10px 12px;
  border: 1px solid color-mix(in srgb, var(--primary) 40%, var(--border));
  border-radius: 12px;
  background: color-mix(in srgb, var(--primary) 8%, transparent);
}
.recipe-diet-suggest.is-applied {
  display: none;
}
.recipe-diet-suggest-text {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
}
.recipe-diet-suggest-text .ico {
  width: 16px;
  height: 16px;
  color: var(--primary);
}

.recipe-diet-group {
  border: none;
  margin: 0 0 12px;
  padding: 0;
  min-width: 0;
}
.recipe-diet-group-title {
  padding: 0;
  margin-bottom: 8px;
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.recipe-diet-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.recipe-diet-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--panel-2);
  cursor: pointer;
  font-size: 14px;
  user-select: none;
  transition: border-color .12s, background .12s;
}
/* Annule le `input { width:100% }` global (sinon la case déborde le chip). */
.recipe-diet-chip input {
  width: auto;
  margin: 0;
  accent-color: var(--primary);
}
.recipe-diet-chip:has(input:checked) {
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 14%, transparent);
  font-weight: 600;
}
.recipe-diet-hint {
  margin-top: 4px;
  font-size: 13px;
}

/* Filtres /recipes — accordéon (sections repliables + compteur d'actifs). */
.recipes-filters-section-summary {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  list-style: none;
  padding: 2px 0;
}
.recipes-filters-section-summary::-webkit-details-marker {
  display: none;
}
.recipes-filters-section-summary .recipes-filters-section-title {
  flex: 1 1 auto;
  min-width: 0;
}
.recipes-filters-section-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 6px;
  border-radius: 9px;
  background: var(--primary);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
}
.recipes-filters-section-chevron {
  display: inline-flex;
  color: var(--muted);
  transition: transform .15s ease;
}
.recipes-filters-section-chevron .ico {
  width: 18px;
  height: 18px;
}
.recipes-filters-section[open] .recipes-filters-section-chevron {
  transform: rotate(180deg);
}

/* Badges régime/allergies sur la fiche recette (vert = compatible). */
.menu-recipe-diet-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}
.menu-recipe-diet-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  color: var(--success);
  background: color-mix(in srgb, var(--success) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--success) 35%, transparent);
}
.menu-recipe-diet-badge .ico {
  width: 13px;
  height: 13px;
}

/* Bloc régime/allergies de la fiche : replié par défaut (summary + compteur). */
.menu-recipe-diet {
  margin-top: 8px;
}
.menu-recipe-diet-summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  list-style: none;
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  color: var(--success);
  background: color-mix(in srgb, var(--success) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--success) 30%, transparent);
}
.menu-recipe-diet-summary::-webkit-details-marker {
  display: none;
}
.menu-recipe-diet-summary .ico {
  width: 13px;
  height: 13px;
}
.menu-recipe-diet-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  height: 16px;
  padding: 0 5px;
  border-radius: 8px;
  background: var(--success);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
}
.menu-recipe-diet-chevron {
  transition: transform .15s ease;
}
.menu-recipe-diet[open] .menu-recipe-diet-chevron {
  transform: rotate(180deg);
}
.menu-recipe-diet[open] .menu-recipe-diet-summary {
  margin-bottom: 8px;
}

/* #8 — la dialog filtres /recipes n'a pas de wrapper .export-dialog-form :
   on en fait directement un conteneur flex-column pour que .export-dialog-body
   (flex:1 + overflow-y:auto) devienne la zone scrollable quand l'accordéon est
   déplié (sinon le contenu débordait, clippé par overflow:hidden).
   ⚠️ Scopé à [open] : sinon `display:flex` écrase le `display:none` natif d'un
   <dialog> fermé → la dialog s'afficherait en plein milieu de la page. */
.recipes-filters-dialog[open] {
  display: flex;
  flex-direction: column;
}

/* Animation d'entrée d'un panneau de recette (Ingrédients/Consignes) : swipe
   = glissement dans le sens du doigt, tap = fondu. Coupée si l'utilisateur
   préfère moins d'animations. */
@media (prefers-reduced-motion: no-preference) {
  [data-recipe-pane].is-pane-enter-next { animation: recipe-pane-from-right .22s ease; }
  [data-recipe-pane].is-pane-enter-prev { animation: recipe-pane-from-left .22s ease; }
  [data-recipe-pane].is-pane-enter-fade { animation: recipe-pane-fade .16s ease; }
}
@keyframes recipe-pane-from-right {
  from { opacity: 0; transform: translateX(22px); }
  to { opacity: 1; transform: none; }
}
@keyframes recipe-pane-from-left {
  from { opacity: 0; transform: translateX(-22px); }
  to { opacity: 1; transform: none; }
}
@keyframes recipe-pane-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}
