/* Backoffice Imprimeca — CSS statique, volontairement hors Vite (zone admin
   séparée, pas de build nécessaire), mais qui reprend la vraie DA du site
   public (demande du 29/08/2026) : mêmes tokens que frontend/css/tokens.css,
   mêmes polices auto-hébergées (Fredoka/Plus Jakarta Sans, cf. /public/fonts
   — copiées depuis node_modules/@fontsource sous des noms stables, pas les
   fichiers hashés de Vite qui changent à chaque build public), mêmes formes
   (blobs, pilules, dégradés de marque). */

@font-face {
  font-family: "Fredoka"; font-style: normal; font-display: swap; font-weight: 500;
  src: url("/fonts/fredoka-latin-500-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Fredoka"; font-style: normal; font-display: swap; font-weight: 600;
  src: url("/fonts/fredoka-latin-600-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Fredoka"; font-style: normal; font-display: swap; font-weight: 700;
  src: url("/fonts/fredoka-latin-700-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Plus Jakarta Sans"; font-style: normal; font-display: swap; font-weight: 400;
  src: url("/fonts/plus-jakarta-sans-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Plus Jakarta Sans"; font-style: normal; font-display: swap; font-weight: 500;
  src: url("/fonts/plus-jakarta-sans-latin-500-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Plus Jakarta Sans"; font-style: normal; font-display: swap; font-weight: 600;
  src: url("/fonts/plus-jakarta-sans-latin-600-normal.woff2") format("woff2");
}

:root {
  --paper: #f1eef3;
  --paper-alt: #e9e4ee;
  --surface: #ffffff;
  --rule: #e2dbe8;
  --ink: #2b2733;
  --ink-soft: #635d70;
  --ink-faint: #a39bb0;
  --accent: #ec8f66;
  --accent-deep: #c96f47;
  --sage: #7d9c8c;
  --sage-soft: #e4ede9;
  --blush: #f7dfe0;
  --danger: #c0392b;
  --danger-soft: #f6dedb;
  --shadow: rgba(43, 39, 51, 0.08);
  --shadow-strong: rgba(43, 39, 51, 0.18);
  --font-body: "Plus Jakarta Sans", "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --font-display: "Fredoka", "Quicksand", "Segoe UI", sans-serif;
  --radius-s: 14px;
  --radius-m: 20px;
  --radius-l: 28px;
  --radius-pill: 16px;
  --radius-blob: 42% 58% 60% 40% / 45% 45% 55% 55%;
  --ease-snap: cubic-bezier(0.22, 1, 0.36, 1);
  /* Refonte du 23/09/2026 : gabarit et densité. */
  --sidebar-w: 236px;
  --rail-w: 72px;
  --tabbar-h: 62px;
  --gutter: 28px;
  /* Hauteur de l'en-tête de page collé, mesurée par admin.js : tout ce qui
     colle sous lui (onglets, en-têtes de tableau) s'y aligne. */
  --sticky-top: 0px;
  --card-shadow: 0 1px 2px rgba(43, 39, 51, 0.05), 0 6px 18px rgba(43, 39, 51, 0.06);
  --focus-ring: 0 0 0 3px rgba(236, 143, 102, 0.35);
}

* { box-sizing: border-box; }
body.admin-body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--paper);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}
h1, h2, .admin-h1, .admin-h2 { text-wrap: balance; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Passage d'une page à l'autre (23/09/2026) : fondu natif du navigateur
   entre deux pages ordinaires — aucune navigation AJAX. La barre latérale
   porte son propre nom de transition : elle ne clignote pas au changement
   de page, seul le contenu glisse. Un navigateur qui ne connaît pas la
   règle navigue simplement comme avant. */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: 90ms ease-out both admin-vt-out; }
::view-transition-new(root) { animation: 160ms var(--ease-snap) both admin-vt-in; }
@keyframes admin-vt-out { to { opacity: 0; } }
@keyframes admin-vt-in { from { opacity: 0; transform: translateY(6px); } }
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}

/* ─── Mise en page tableau de bord ──────────────────────────────────── */
.admin-shell { display: flex; min-height: 100vh; min-height: 100dvh; }
.admin-sidebar {
  width: var(--sidebar-w); flex-shrink: 0;
  background: var(--ink); color: var(--paper);
  display: flex; flex-direction: column;
  padding: 14px 0 12px;
  /* Reste plaquée au viewport pendant que la page défile. C'est la liste
     des liens, et elle seule, qui défile si l'écran est trop bas : le logo,
     la recherche et le pied (mode de paiement) restent toujours visibles. */
  position: sticky; top: 0; height: 100vh; height: 100dvh; overflow: hidden;
  view-transition-name: admin-sidebar;
}
/* Halos de couleur en transparence faible, même traitement que le panneau
   promo de /sur-mesure (.quote-configurator-promo) — la seule touche
   "éditoriale" du site qu'on reprend telle quelle sur fond sombre. */
.admin-sidebar::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 0;
  background:
    radial-gradient(circle at 15% 8%, rgba(236, 143, 102, 0.28), transparent 50%),
    radial-gradient(circle at 90% 85%, rgba(125, 156, 140, 0.22), transparent 55%);
}
.admin-sidebar > * { position: relative; z-index: 1; }

.admin-brand { display: flex; align-items: center; gap: 10px; padding: 2px 18px 12px; color: inherit; text-decoration: none; }
.admin-brand-mark {
  flex-shrink: 0; width: 32px; height: 32px; border-radius: 10px;
  background: var(--paper); display: flex; align-items: center; justify-content: center;
}
.admin-brand-mark svg { width: 22px; height: 22px; }
.admin-brand-word { font-family: var(--font-display); font-weight: 600; font-size: 1.1rem; line-height: 1.2; }
.admin-brand-word span { display: block; font-size: 0.72rem; font-weight: 400; opacity: 0.7; font-family: var(--font-body); }

/* Recherche rapide (palette Ctrl+K, 23/09/2026) : le bouton rappelle le
   raccourci, sans lequel personne ne le découvre. */
.admin-search-btn {
  display: flex; align-items: center; gap: 8px;
  margin: 0 12px 10px; padding: 7px 10px;
  border-radius: 12px; border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(255, 255, 255, 0.07); color: rgba(241, 238, 243, 0.68);
  font: inherit; font-size: 0.82rem; cursor: pointer; text-align: left;
  transition: background 0.2s ease, color 0.2s ease;
}
.admin-search-btn:hover { background: rgba(255, 255, 255, 0.12); color: var(--paper); }
.admin-search-btn .admin-icon { width: 15px; height: 15px; }
.admin-search-btn-label { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.admin-search-btn kbd { background: rgba(255, 255, 255, 0.1); border-color: rgba(255, 255, 255, 0.12); color: rgba(241, 238, 243, 0.7); }

/* Pictogrammes au trait de la navigation (23/09/2026). */
.admin-icon {
  width: 18px; height: 18px; flex-shrink: 0;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
kbd {
  font-family: var(--font-body); font-size: 0.68rem; font-weight: 600; line-height: 1.4;
  padding: 1px 6px; border-radius: 6px;
  border: 1px solid var(--rule); background: var(--paper); color: var(--ink-soft);
}

/* La liste seule défile quand l'écran est trop bas pour tout montrer. */
.admin-nav {
  display: flex; flex-direction: column; flex: 1; gap: 1px; padding: 0 10px;
  min-height: 0; overflow-y: auto; scrollbar-width: none;
}
.admin-nav::-webkit-scrollbar { display: none; }
.admin-nav a {
  /* `display: flex` explicite : dans une section repliable les liens ne
     sont pas enfants directs du flex de .admin-nav (cf. 18/09/2026, deux
     entrées s'étaient retrouvées côte à côte). */
  display: flex; align-items: center; gap: 10px;
  color: rgba(241, 238, 243, 0.72); text-decoration: none;
  padding: 7px 10px; font-size: 0.88rem; font-weight: 500;
  border-radius: 11px;
  transition: color 0.15s ease, background 0.15s ease;
}
.admin-nav a .admin-icon { opacity: 0.85; }
.admin-nav-label { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Pastille de compteur (23/09/2026) : ce qui attend une action. Elle ne
   s'affiche qu'au-dessus de zéro — un « 0 » permanent ne se lit plus. */
.admin-nav-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 6px; border-radius: 10px;
  background: var(--accent); color: #fff;
  font-size: 0.72rem; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums; flex-shrink: 0;
}
.admin-nav-count[hidden] { display: none; }
.admin-nav a.is-active .admin-nav-count { background: var(--ink); color: var(--paper); }
/* Intitulé de section de la sidebar (16/09/2026), devenu la poignée de son
   accordéon le 18/09/2026 : toujours aussi discret — il structure la liste
   sans concurrencer les entrées — mais désormais cliquable. */
.admin-nav-section { display: flex; flex-direction: column; gap: 2px; }
.admin-nav-section-items { display: flex; flex-direction: column; gap: 2px; }
.admin-nav-section.is-collapsed > .admin-nav-section-items { display: none; }
.admin-nav-group {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; padding: 12px 10px 4px;
  font-family: inherit;
  font-size: 0.66rem; font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; text-align: left;
  color: rgba(241, 238, 243, 0.4);
  background: none; border: 0;
  user-select: none; cursor: pointer;
  transition: color 0.2s ease;
}
.admin-nav-group:hover { color: rgba(241, 238, 243, 0.75); }
.admin-nav-group:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
.admin-nav-chevron { width: 12px; height: 12px; flex-shrink: 0; transition: transform 0.2s ease; }
.admin-nav-section:not(.is-collapsed) > .admin-nav-group .admin-nav-chevron { transform: rotate(180deg); }
/* Une section repliée qui contient la page courante ne doit pas se taire :
   une pastille rappelle qu'on est dedans. */
.admin-nav-section.is-collapsed > .admin-nav-group.has-active::after,
.admin-nav-section.is-collapsed > .admin-nav-group.has-count::after {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent); flex-shrink: 0; margin-left: auto;
}
.admin-nav a:hover { color: var(--paper); background: rgba(255,255,255,0.07); }
.admin-nav a.is-active { color: var(--ink); background: var(--accent); font-weight: 600; }
.admin-nav a.is-active .admin-icon { opacity: 1; }
.admin-sidebar-footer { padding: 10px 12px 0; margin: 8px 10px 0; border-top: 1px solid rgba(255,255,255,0.12); }
.admin-user-row { display: flex; align-items: center; gap: 8px; }
.admin-user-row form { margin: 0; }
.admin-user { flex: 1; min-width: 0; font-size: 0.76rem; opacity: 0.7; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.admin-logout-btn {
  display: grid; place-items: center; width: 32px; height: 32px; padding: 0;
  border: 0; border-radius: 10px; cursor: pointer;
  background: rgba(255, 255, 255, 0.07); color: var(--paper);
  transition: background 0.2s ease;
}
.admin-logout-btn:hover { background: var(--danger); }
.admin-logout-btn .admin-icon { width: 16px; height: 16px; }
/* Pastille du mode de paiement : ne sert qu'au rail replié (plus bas), où le
   switch complet n'a pas la place. */
.admin-mode-chip { display: none; }
/* Bandeau « mode TEST » : téléphone seulement, cf. requête média mobile. */
.admin-test-ribbon { display: none; }
/* Barre d'onglets du téléphone et sa feuille « Plus » : cachées ailleurs. */
.admin-tabbar { display: none; }

/* `min-width: 0` indispensable (18/09/2026) : sans lui un enfant de flex
   garde `min-width: auto` et refuse de descendre sous la largeur minimale
   de son contenu — le tableau des produits poussait alors .admin-main à
   965 px dans une fenêtre de 1000, et c'est la page entière qui défilait
   horizontalement.
   Plus de plafond à 1 140 px (23/09/2026) : sur un écran de 1 440 px il
   laissait un tiers de la largeur vide, et c'est ce qui faisait déborder en
   hauteur ce qui aurait tenu en largeur. */
.admin-main { flex: 1; min-width: 0; padding: 20px var(--gutter) 32px; max-width: 1640px; }

.admin-h1 { font-family: var(--font-display); font-weight: 600; letter-spacing: -0.01em; font-size: 1.45rem; line-height: 1.2; margin: 0 0 16px; }
.admin-h2 { font-family: var(--font-display); font-weight: 600; letter-spacing: -0.01em; font-size: 1.05rem; margin: 0 0 12px; }
/* En-tête de page collé (23/09/2026) : titre et actions de la page restent
   à portée pendant qu'on descend dans une liste — plus besoin de remonter
   pour « Nouveau produit ». Il déborde dans la gouttière de .admin-main pour
   que son fond couvre toute la largeur quand le contenu glisse dessous. */
.admin-page-header {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px;
  position: sticky; top: 0; z-index: 30;
  margin: -20px calc(-1 * var(--gutter)) 16px;
  padding: 16px var(--gutter) 12px;
  background: color-mix(in srgb, var(--paper) 90%, transparent);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
}
.admin-page-header.is-stuck { box-shadow: 0 1px 0 var(--rule), 0 8px 18px -12px var(--shadow-strong); }
.admin-page-header .admin-h1 { margin-bottom: 0; }
.admin-page-title { display: flex; align-items: center; gap: 12px; min-width: 0; flex-wrap: wrap; }
.admin-page-sub { color: var(--ink-soft); font-size: 0.85rem; }
/* Regroupe plusieurs boutons côte à côte dans l'en-tête (ex. liste produits :
   "Ajouter par IA" + "Nouveau produit") sans style inline au cas par cas. */
.admin-page-header-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.admin-page-header-actions form { margin: 0; }
.admin-section {
  background: var(--surface); border-radius: var(--radius-m); padding: 18px 20px; margin-bottom: 16px;
  box-shadow: var(--card-shadow); position: relative; overflow: hidden; overflow: clip;
}
/* Liseré dégradé en tête de carte — même motif que .p-card::before côté
   boutique, discret ici (2px) pour ne pas concurrencer le contenu. */
.admin-section::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: linear-gradient(90deg, var(--accent), var(--sage));
}
.admin-muted { color: var(--ink-soft); font-size: 0.9rem; }

/* ─── Lien "retour" (fiche facture/commande/devis/produit) ───────────
   Même composant que .back-link côté site public (frontend/css/app.css) :
   pastille + chevron SVG plutôt que "&larr; Texte" en lien nu. Classe
   distincte de .admin-link-btn, qui reste le style texte-souligné utilisé
   pour les actions de ligne de tableau (Détails/Activer/Supprimer). */
.admin-back-link {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px 7px 10px; border-radius: var(--radius-pill);
  border: 1.5px solid var(--rule); color: var(--ink-soft);
  font-size: 0.85rem; font-weight: 600; text-decoration: none;
  transition: border-color 0.2s ease, color 0.2s ease, background 0.2s ease;
}
.admin-back-link svg { width: 13px; height: 13px; flex-shrink: 0; }
.admin-back-link:hover, .admin-back-link:focus-visible { border-color: var(--ink); color: var(--ink); background: var(--paper); }

/* ─── Stat cards du tableau de bord ─────────────────────────────────── */
.admin-stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(170px, 100%), 1fr)); gap: 12px; }
.admin-stat-card {
  background: var(--surface); border-radius: var(--radius-m); padding: 14px 16px;
  text-decoration: none; color: var(--ink); box-shadow: var(--card-shadow);
  display: block; position: relative; overflow: hidden;
  transition: transform 0.2s var(--ease-snap), box-shadow 0.2s var(--ease-snap);
}
.admin-stat-card::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: linear-gradient(90deg, var(--accent), var(--sage));
}
a.admin-stat-card:hover { transform: translateY(-2px); box-shadow: 0 16px 34px var(--shadow-strong); }
.admin-stat-value { font-family: var(--font-display); font-size: 1.7rem; line-height: 1.15; font-weight: 700; color: var(--accent-deep); font-variant-numeric: tabular-nums; }
.admin-stat-label { font-weight: 600; margin-top: 2px; font-size: 0.9rem; }
.admin-stat-sub { color: var(--ink-soft); font-size: 0.8rem; margin-top: 1px; }

/* ─── Tableaux ───────────────────────────────────────────────────────── */
/* Le tableau est SA PROPRE zone de défilement horizontal, à toute largeur
   (18/09/2026). Auparavant ce comportement n'existait qu'en dessous de
   780 px : entre 780 et ~1200 px, rien ne rattrapait, et c'était la PAGE
   entière qui défilait — la barre latérale restant collée pendant que le
   contenu glissait dessous, on croyait voir des lignes décalées (capture
   de l'exploitant). Mesuré avant correction : fenêtre de 1000 px, page de
   1197 px de large.

   `display: block` fait de la boîte externe la zone défilante ; les
   lignes et cellules gardent leur mise en page tabulaire interne. Pas de
   `white-space: nowrap` ici, contrairement au bloc mobile plus bas : sur
   un grand écran les cellules doivent continuer de se replier, sinon un
   tableau qui tenait sans défiler se met à défiler pour rien (vérifié en
   1440 et 1600 px, rendu inchangé). */
.admin-table {
  width: 100%; border-collapse: collapse; background: var(--surface);
  border-radius: var(--radius-m); box-shadow: var(--card-shadow);
  display: block; overflow-x: auto; -webkit-overflow-scrolling: touch;
  /* Fondu des deux bords : sans lui les colonnes hors champ se coupent net
     contre le bord de la carte, sans signe qu'il reste à faire glisser.
     Piloté par admin.js (.is-scroll-start/.is-scroll-end), qui tourne déjà
     à toutes les largeurs. */
  mask-image: linear-gradient(to right, transparent 0%, #000 8%, #000 92%, transparent 100%);
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 8%, #000 92%, transparent 100%);
}
.admin-table.is-scroll-start {
  mask-image: linear-gradient(to right, #000 92%, transparent 100%);
  -webkit-mask-image: linear-gradient(to right, #000 92%, transparent 100%);
}
.admin-table.is-scroll-end {
  mask-image: linear-gradient(to right, transparent 0%, #000 8%, #000 100%);
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 8%, #000 100%);
}
.admin-table.is-scroll-start.is-scroll-end {
  /* Tout tient déjà dans la largeur : rien à faire glisser, pas de fondu. */
  mask-image: none; -webkit-mask-image: none;
}
.admin-table th, .admin-table td { text-align: left; padding: 9px 14px; border-bottom: 1px solid var(--rule); font-size: 0.88rem; vertical-align: middle; }
.admin-table th { background: var(--paper-alt); font-family: var(--font-display); font-weight: 600; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--ink-soft); white-space: nowrap; }
.admin-table tr:last-child td { border-bottom: none; }
.admin-table tr:hover td { background: var(--paper); }
.admin-table a { color: var(--accent-deep); text-decoration: none; font-weight: 600; }
/* Cellule d'actions : surtout PAS `display: flex` sur le <td> lui-même
   (corrigé le 18/09/2026). Un <td> passé en flex quitte la mise en page
   tabulaire : il cesse de s'étirer à la hauteur de sa ligne — mesuré à 55 px
   dans une ligne de 71 — et comme sa bordure basse et son fond s'arrêtent
   là, la colonne Actions apparaissait comme un bloc blanc détaché, posé à
   cheval sur le filet de séparation (capture de l'exploitant). Les boutons
   s'alignent donc en ligne, ce qui laisse la cellule être une cellule. */
.admin-table-actions { white-space: nowrap; }
.admin-table-actions > * { display: inline-block; vertical-align: middle; margin: 0; }
.admin-table-actions > * + * { margin-left: 10px; }

/* ─── Liste produits (09/09/2026, nettoyage) ─────────────────────────── */
.admin-table-title {
  color: var(--accent-deep); text-decoration: none; font-weight: 600;
  /* Hauteur de ligne réservée pour DEUX lignes (13/09/2026) : un titre
     tenant sur une seule ligne (ex. « Tirelire maison à peindre ») rendait
     sa ligne du tableau visiblement plus basse que les lignes voisines à
     titre sur 2 lignes -- signalé comme un « décalage » alors qu'aucune
     colonne ne bouge (vérifié par mesure de position, colonnes alignées au
     pixel) : c'est la hauteur de ligne qui varie et rompt le rythme visuel.
     `display:inline-block` nécessaire pour qu'un `<a>` (inline) respecte
     min-height. */
  display: inline-block; min-height: 3.2em;
}
/* Puce discrète signalant qu'un aperçu image apparaît au survol (JS,
   .admin-title-preview-tip plus bas) -- seulement quand le produit a au
   moins une photo (attribut posé côté vue). */
.admin-table-title[data-preview-img]::after { content: " 🖼"; opacity: 0.45; font-size: 0.85em; }
.admin-table-price { font-family: var(--font-display); font-weight: 700; white-space: nowrap; }
.admin-table-etsy { display: flex; align-items: center; gap: 8px; }
.admin-table-etsy form { margin: 0; }
.admin-table-empty { text-align: center; color: var(--ink-soft); padding: 28px 16px !important; }

/* Boutons d'action de la liste produits en icône (09/09/2026, demande
   utilisateur — les libellés texte empilés dans les colonnes Etsy/Actions
   alourdissaient chaque ligne). Rond compact façon .product-photo-btn (déjà
   ce langage visuel dans la fiche produit), libellé porté par
   `title`/`aria-label` plutôt qu'affiché. */
.admin-icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0; border: none; border-radius: 50%;
  background: var(--paper-alt); color: var(--ink-soft); cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease, transform 0.15s var(--ease-snap);
}
.admin-icon-btn svg { width: 15px; height: 15px; }
.admin-icon-btn:hover:not(:disabled) { background: var(--accent); color: #fff; transform: translateY(-1px); }
.admin-icon-btn:disabled { opacity: 0.35; cursor: default; }
.admin-icon-btn-danger:hover:not(:disabled) { background: var(--danger); color: #fff; }
/* Teinte "actif" au repos (avant survol) pour le bouton Activer/Désactiver
   -- seul indice visuel de l'état courant du produit, l'icône elle-même ne
   change pas de forme entre les deux sens. */
.admin-icon-btn-active { background: var(--sage-soft); color: #4f6b5e; }

/* Bulle d'aperçu au survol du titre : positionnée en `fixed` par le script
   de la page (calcul sur getBoundingClientRect), pas ancrée en CSS pur sur
   la cellule -- .admin-table pose overflow:hidden pour ses coins arrondis,
   qui aurait rogné une bulle en position absolue dépassant en bas du
   tableau (dernières lignes de la liste). */
.admin-title-preview-tip {
  position: fixed; z-index: 50; width: 150px; height: 150px;
  border-radius: var(--radius-m); overflow: hidden; background: var(--paper-alt);
  box-shadow: 0 18px 40px var(--shadow-strong);
  opacity: 0; visibility: hidden; transform: translateY(-4px);
  transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;
  pointer-events: none;
}
.admin-title-preview-tip.is-visible { opacity: 1; visibility: visible; transform: translateY(0); }
.admin-title-preview-tip img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Pastille de couleur dans la colonne "Valeur" des options (30/08/2026) :
   un hex brut en texte ("#7d9c8c") n'aide pas à visualiser la couleur réelle. */
.admin-color-swatch {
  display: inline-block; width: 22px; height: 22px; border-radius: 50%;
  vertical-align: middle; box-shadow: 0 0 0 2px var(--surface), 0 0 0 3.5px var(--rule);
}

.admin-badge {
  display: inline-block; font-family: var(--font-display); font-weight: 600;
  padding: 4px 12px; border-radius: var(--radius-pill);
  background: var(--sage-soft); color: #4f6b5e; font-size: 0.76rem;
}
.admin-badge-ok { background: var(--sage-soft); color: #4f6b5e; }
.admin-badge-muted { background: var(--paper-alt); color: var(--ink-faint); }
/* Manquait (bug, corrigé 09/09/2026) : utilisée par la liste produits pour
   les échecs (Etsy, génération IA) mais jamais définie -- un échec
   s'affichait avec la couleur par défaut de .admin-badge, indiscernable
   d'un badge "ok" (même vert sauge). */
.admin-badge-warn { background: var(--danger-soft); color: var(--danger); }

/* Travail en cours (18/09/2026) : synchronisation Etsy déposée en file et
   exécutée en tâche de fond. Distincte du vert « envoyée » et du rouge
   « erreur » — une pastille d'attente qui emprunterait l'une des deux
   annoncerait un résultat qui n'existe pas encore. Même défaut que celui
   corrigé le 09/09 sur .admin-badge-warn, qui n'était jamais définie.
   Le battement dit que quelque chose avance, sans réclamer l'attention ;
   il se tait pour qui a demandé moins d'animations. */
.admin-badge-info { background: var(--blush); color: var(--accent-deep); }
.admin-badge-info { animation: admin-badge-pulse 1.8s ease-in-out infinite; }
@keyframes admin-badge-pulse { 50% { opacity: 0.55; } }
@media (prefers-reduced-motion: reduce) {
  .admin-badge-info { animation: none; }
}

/* Carte générique (30/08/2026) : même habillage que .admin-section, sous un
   nom plus court utilisé par les pages "détail" (demande pro) qui n'ont pas
   de <h2> de section à côté du contenu. */
.admin-card {
  background: var(--surface); border-radius: var(--radius-m); padding: 18px 20px; margin-bottom: 16px;
  box-shadow: var(--card-shadow); position: relative; overflow: hidden; overflow: clip;
}
.admin-card::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: linear-gradient(90deg, var(--accent), var(--sage));
}

/* Bandeau d'information ponctuel (paramètre `?notice=`/`?erreur=` en query
   string après une action) -- même palette que .admin-flash, nom distinct
   car posé hors formulaire, en tête de fiche. */
.admin-notice { padding: 11px 18px; border-radius: var(--radius-s); margin-bottom: 16px; font-size: 0.9rem; font-weight: 500; background: var(--sage-soft); color: #4f6b5e; }
.admin-notice-error { background: var(--danger-soft); color: var(--danger); }

/* Historique d'une commande : simple liste chronologique, sans puce native
   (déjà la date en gras comme repère visuel). */
.admin-timeline { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; }
.admin-timeline li { font-size: 0.9rem; padding-left: 14px; border-left: 2px solid var(--rule); }

.admin-btn-danger { background: var(--danger); border-color: var(--danger); color: #fff; box-shadow: 0 8px 20px rgba(192, 57, 43, 0.3); }
.admin-btn-danger:hover { background: #9c2d20; border-color: #9c2d20; color: #fff; }

/* Filtres en contrôle segmenté (23/09/2026) : une seule pilule compacte
   au lieu de boutons flottants séparés, qui prenaient une ligne entière
   par groupe de filtres. */
.admin-filter-bar { display: flex; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; align-items: center; }
.admin-filter-bar:has(> a) {
  display: inline-flex; gap: 2px; padding: 3px; border-radius: 12px;
  background: var(--paper-alt); max-width: 100%; overflow-x: auto; scrollbar-width: none;
}
.admin-filter-bar a {
  padding: 5px 12px; border-radius: 9px; background: transparent;
  color: var(--ink-soft); text-decoration: none; font-size: 0.82rem; font-weight: 600;
  white-space: nowrap;
  transition: background 0.15s ease, color 0.15s ease;
}
.admin-filter-bar a:hover { color: var(--ink); }
.admin-filter-bar a.is-active { background: var(--surface); color: var(--ink); box-shadow: 0 1px 3px var(--shadow-strong); }
/* Rangée qui porte plusieurs groupes de filtres + un compteur + une
   recherche, sur UNE ligne (liste des produits, commandes…). */
.admin-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.admin-toolbar .admin-filter-bar { margin-bottom: 0; }
.admin-toolbar-spacer { flex: 1; }
.admin-count { color: var(--ink-soft); font-size: 0.82rem; font-variant-numeric: tabular-nums; white-space: nowrap; }
.admin-search {
  position: relative; display: flex; align-items: center; min-width: 0;
}
.admin-search .admin-icon { position: absolute; left: 10px; width: 15px; height: 15px; color: var(--ink-faint); pointer-events: none; }
.admin-main .admin-search input {
  width: 240px; max-width: 100%; padding: 7px 12px 7px 32px; font-size: 0.86rem; border-radius: 12px;
}

/* Sélecteur de vue tableau/galerie (18/09/2026) : posé au bout de la rangée
   de filtres, poussé à droite pour ne pas se confondre avec eux — ce n'est
   pas un filtre, il ne change pas QUELS produits s'affichent. */
.admin-view-switch { display: inline-flex; gap: 2px; padding: 3px; border-radius: 12px; background: var(--paper-alt); }
.admin-view-switch a {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px; border-radius: 9px;
  font-size: 0.82rem; font-weight: 600; text-decoration: none;
  color: var(--ink-soft);
}
.admin-view-switch a svg { width: 14px; height: 14px; }
.admin-view-switch a.is-active { background: var(--surface); color: var(--ink); box-shadow: 0 1px 3px var(--shadow-strong); }

/* Galerie des produits (18/09/2026). `minmax(0, 1fr)` et non `1fr` : un
   titre long imposerait sinon sa largeur minimale à toute la colonne et
   ferait déborder la grille (piège déjà rencontré sur la boutique). */
.admin-gallery {
  display: grid; gap: 18px;
  grid-template-columns: repeat(auto-fill, minmax(min(210px, 100%), 1fr));
  margin-bottom: 18px;
}
.admin-gallery-card {
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius-m); overflow: hidden;
  box-shadow: 0 10px 26px var(--shadow);
}
/* Un produit hors ligne se reconnaît sans lire son badge : la photo pâlit.
   La carte, elle, garde son contraste — les commandes doivent rester
   lisibles, c'est justement sur ces produits qu'on va cliquer. */
.admin-gallery-card.is-inactive .admin-gallery-art { opacity: 0.55; filter: saturate(0.6); }
.admin-gallery-art {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 1 / 1; background: var(--paper);
  overflow: hidden; text-decoration: none;
}
.admin-gallery-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.admin-gallery-empty { font-size: 0.8rem; color: var(--ink-faint); font-weight: 600; }
.admin-gallery-body { display: flex; flex-direction: column; gap: 8px; padding: 12px 14px 14px; flex: 1; }
.admin-gallery-title {
  color: var(--ink); text-decoration: none; font-weight: 600; font-size: 0.92rem;
  line-height: 1.35;
}
.admin-gallery-title:hover { color: var(--accent-deep); }
.admin-gallery-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* `margin-top: auto` : les cartes d'une même rangée font déjà la même
   hauteur (grille), mais sans ça la rangée de boutons remontait sous les
   titres courts et redescendait sous les titres sur deux lignes — l'œil
   lisait des cartes mal alignées. */
.admin-gallery-actions {
  display: flex; gap: 8px; margin-top: auto;
  padding-top: 10px; border-top: 1px solid var(--rule);
}
.admin-gallery-actions form { margin: 0; }

/* ─── Formulaires ────────────────────────────────────────────────────── */
.admin-form { display: flex; flex-direction: column; gap: 12px; background: var(--surface); border-radius: var(--radius-m); padding: 18px 20px; box-shadow: var(--card-shadow); position: relative; overflow: hidden; }
.admin-form::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: linear-gradient(90deg, var(--accent), var(--sage));
}
.admin-form-row { display: flex; gap: 14px; flex-wrap: wrap; }
.admin-form-row label { flex: 1; min-width: 160px; }
/* Champs de saisie : scopés à .admin-main (toute la zone de contenu) et non
   à .admin-form, pour s'appliquer aussi aux <label>/<input> posés à même
   .admin-section (ex. fiche produit, dont le <form> racine est une grille
   product-form-grid, pas .admin-form) — sinon ils retombent en style
   navigateur brut, minuscule et sans bordure (régression du 29/08/2026). Un
   seul sélecteur générique plutôt qu'une liste de types à maintenir à la
   main, pour qu'un futur type="email"/"date"/"search" n'atterrisse plus
   jamais à côté des autres. */
.admin-main label { display: flex; flex-direction: column; gap: 4px; font-size: 0.8rem; font-weight: 600; color: var(--ink-soft); }
/* Une case à cocher ou un bouton radio se lit sur UNE ligne avec son libellé
   (23/09/2026). La colonne ci-dessus, pensée pour « libellé au-dessus du
   champ », empilait la case seule au centre de sa ligne et le texte en
   dessous — vu sur la fiche produit (« Tient en enveloppe ») et sur chaque
   interrupteur .admin-switch, qui porte pourtant son propre `display:flex`
   mais perdait la direction face à la spécificité de `.admin-main label`. */
.admin-main label:has(> input[type=checkbox]),
.admin-main label:has(> input[type=radio]),
.admin-main .admin-switch { flex-direction: row; align-items: center; }
.admin-main input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=color]),
.admin-main select, .admin-main textarea {
  width: 100%;
}
.admin-main input:not([type=checkbox]):not([type=radio]),
.admin-main select, .admin-main textarea {
  font-family: inherit; font-size: 0.9rem; color: var(--ink);
  background: var(--surface);
  border: 1.5px solid var(--rule); border-radius: 11px; padding: 7px 11px;
  box-sizing: border-box; min-height: 36px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.admin-main textarea { line-height: 1.45; resize: vertical; }
.admin-main input:hover:not(:focus):not([type=checkbox]):not([type=radio]):not([disabled]),
.admin-main select:hover:not(:focus), .admin-main textarea:hover:not(:focus) { border-color: #cfc5d8; }
.admin-main input:focus, .admin-main select:focus, .admin-main textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: var(--focus-ring);
}
.admin-main input[type=checkbox], .admin-main input[type=radio] { accent-color: var(--accent); width: 16px; height: 16px; margin: 0; flex-shrink: 0; }
/* Repli pour un <input type="color"> hors .admin-form-inline (qui a sa
   propre règle plus bas, identique) -- sans lui, la règle générique
   ci-dessus l'aurait quand même étiré à 100% via son :not() moins
   spécifique (bug constaté le 30/08/2026, cf. capture mobile). */
.admin-main input[type=color] {
  width: 46px; height: 40px; padding: 3px; min-width: 0; box-sizing: border-box;
}
.admin-checkbox { flex-direction: row !important; align-items: center; gap: 8px !important; }
.admin-checkbox input[type=checkbox] { width: auto; flex-shrink: 0; }

/* Saisie par tags (occasions, 30/08/2026) : un conteneur qui a l'air d'un
   champ de saisie normal (même bordure/radius que les inputs ci-dessus),
   avec des pastilles retirables et un vrai <input> sans bordure propre à la
   fin — l'input générique récupère quand même bordure/largeur 100% via le
   sélecteur ci-dessus, d'où les !important pour l'en sortir. */
.admin-tag-input {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  border: 1.5px solid var(--rule); border-radius: var(--radius-s); padding: 6px 8px;
  background: var(--surface);
}
.admin-tag-input:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--sage-soft); }
.admin-tag-input input {
  flex: 1 1 auto !important; width: auto !important; min-width: 140px;
  border: none !important; padding: 4px 2px !important; box-shadow: none !important; background: transparent !important;
}
.admin-tag-input input:focus { box-shadow: none !important; }
.admin-tag {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  font-size: 0.8rem; font-weight: 600; color: #4f6b5e; background: var(--sage-soft);
  padding: 4px 6px 4px 12px; border-radius: var(--radius-pill);
}
.admin-tag button {
  width: 16px; height: 16px; border-radius: 50%; border: none; cursor: pointer; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(79, 107, 94, 0.25); color: #4f6b5e; font-size: 0.78rem; line-height: 1;
}
.admin-tag button:hover { background: var(--danger); color: #fff; }
.admin-form-actions { display: flex; justify-content: flex-end; }
/* Formulaire compact sur une ligne (statut de commande, e-mail de test...) :
   les champs gardent une largeur raisonnable au lieu de s'étirer sur toute
   la largeur du panneau — sinon un simple <select> de statut se retrouve
   large comme la page, à côté d'un bouton, ce qui est le contraire de
   « compact ». S'applique même sans la classe .admin-form (cf. formulaires
   à une seule ligne qui n'ont pas besoin du fond/padding de carte). */
.admin-form-inline {
  display: flex; flex-direction: row; align-items: center; flex-wrap: wrap; gap: 10px;
  background: none; box-shadow: none; padding: 0;
}
.admin-form-inline::before { content: none; }
.admin-form-inline input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=color]),
.admin-form-inline select {
  width: auto; min-width: 180px;
  font-family: inherit; font-size: 0.95rem; color: var(--ink);
  background: var(--surface);
  border: 1.5px solid var(--rule); border-radius: var(--radius-s); padding: 9px 12px;
  box-sizing: border-box;
}
.admin-form-inline input:focus, .admin-form-inline select:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--sage-soft);
}
/* Un <input type="color"> hérite mal du style texte générique ci-dessus (le
   padding/min-width l'étire en fine barre plutôt qu'un vrai sélecteur) : sa
   propre règle, compacte, façon bouton-swatch. Les champs numériques n'ont
   pas besoin des 180px des textes non plus (prix en centimes, jamais long). */
.admin-form-inline input[type=color] {
  width: 46px; height: 40px; padding: 3px; min-width: 0;
  border: 1.5px solid var(--rule); border-radius: var(--radius-s);
  background: var(--surface); cursor: pointer; box-sizing: border-box;
}
.admin-form-inline input[type=number] { min-width: 0; width: 140px; }
.admin-fieldset { border: 1.5px dashed var(--rule); border-radius: var(--radius-s); padding: 12px; }
.admin-fieldset legend { font-size: 0.8rem; color: var(--ink-soft); padding: 0 6px; }

.admin-btn {
  font-family: var(--font-display); font-size: 0.86rem; font-weight: 600; line-height: 1.2; cursor: pointer;
  border: 1.5px solid var(--ink); background: transparent; color: var(--ink);
  border-radius: 12px; padding: 8px 15px; text-decoration: none;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; white-space: nowrap;
  transition: transform 0.15s var(--ease-snap), background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}
.admin-btn[hidden] { display: none; }
.admin-btn:hover { background: var(--ink); color: var(--paper); }
.admin-btn:active:not(:disabled) { transform: scale(0.97); }
.admin-btn:disabled { opacity: 0.45; cursor: default; pointer-events: none; }
.admin-btn .admin-icon { width: 16px; height: 16px; }
/* Bouton discret (actions secondaires d'un en-tête). */
.admin-btn-ghost { border-color: transparent; background: var(--surface); box-shadow: var(--card-shadow); }
.admin-btn-ghost:hover { background: var(--ink); }
.admin-btn-sm { padding: 5px 11px; font-size: 0.8rem; border-radius: 10px; }
.admin-btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; box-shadow: 0 6px 16px rgba(236, 143, 102, 0.3); }
.admin-btn-primary:hover { background: var(--accent-deep); border-color: var(--accent-deep); color: #fff; }
.admin-btn-block { width: 100%; text-align: center; }
.admin-link-btn { background: none; border: none; color: var(--accent-deep); font-weight: 600; cursor: pointer; padding: 0; font-size: 0.85rem; text-decoration: underline; }
.admin-link-btn-danger { color: var(--danger); }

/* Un code promo se relit caractère par caractère (on le dicte, on le recopie
   d'un carton) : chasse fixe, et pas de ligature entre le 0 et le O. */
.admin-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.92em;
  letter-spacing: 0.04em;
  background: var(--paper-alt, #f3f0f5);
  border-radius: 4px;
  padding: 2px 7px;
}

.admin-flash { padding: 11px 18px; border-radius: var(--radius-s); margin-bottom: 16px; font-size: 0.9rem; font-weight: 500; }
.admin-flash-ok { background: var(--sage-soft); color: #4f6b5e; }
.admin-flash-error { background: var(--danger-soft); color: var(--danger); }
.admin-flash-warn { background: var(--blush); color: var(--danger); }

.admin-total { font-weight: 700; text-align: right; font-size: 1.05rem; }
.admin-quote-description { white-space: pre-wrap; background: var(--paper); border-radius: var(--radius-s); padding: 12px 14px; }
.admin-attachment-list { list-style: none; padding: 0; display: flex; flex-direction: column; gap: 8px; }

/* ─── Fiche produit (create/edit) ────────────────────────────────────
   Colonne principale (infos, options, photos, modèle 3D, gravure, zone) +
   volet latéral étroit (tarif, statut, bouton Enregistrer) qui reste
   épinglé (sticky) pendant qu'on descend dans la colonne principale.
   Avant le 07/09/2026, c'était l'inverse — le volet portait presque tout
   le contenu visuel (photos, visionneuse 3D, pointeur de zone) écrasé sur
   320px, et la colonne principale s'arrêtait net après Options, d'où une
   page "très mal proportionnée" sur grand écran (signalé par capture). */
.product-form-grid { display: grid; grid-template-columns: 1fr 280px; gap: 24px; align-items: start; }
.product-form-main { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
.product-form-side { display: flex; flex-direction: column; gap: 20px; position: sticky; top: 20px; }
.product-form-side .admin-form-actions { justify-content: stretch; }

.product-price-input { display: flex; align-items: center; gap: 8px; }
.product-price-input input { width: 100%; }
.product-price-input span { color: var(--ink-soft); font-weight: 700; font-family: var(--font-display); }

.admin-toggle-group { display: flex; flex-direction: column; gap: 8px; }
.admin-toggle-group .admin-muted { font-size: 0.82rem; }

/* Interrupteur à bascule (gravure texte, 30/08/2026) : une vraie pastille
   coulissante plutôt qu'une case à cocher nue — .admin-checkbox reste pour
   les listes d'options ordinaires (catalogue, actif...). */
.admin-switch { display: flex; align-items: center; gap: 12px; cursor: pointer; font-weight: 600; }
.admin-switch input {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.admin-switch-track {
  position: relative; flex-shrink: 0; width: 42px; height: 24px;
  border-radius: 999px; background: var(--rule); transition: background 0.2s ease;
}
.admin-switch-thumb {
  position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); transition: transform 0.2s ease;
}
.admin-switch input:checked + .admin-switch-track { background: var(--accent); }
.admin-switch input:checked + .admin-switch-track .admin-switch-thumb { transform: translateX(18px); }
.admin-switch input:focus-visible + .admin-switch-track { outline: 2px solid var(--accent); outline-offset: 2px; }
.admin-switch-label { font-size: 0.92rem; }

.product-dropzone {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  text-align: center; padding: 24px 14px; border-radius: var(--radius-m);
  border: 1.5px dashed var(--rule); color: var(--ink-soft); cursor: pointer;
  background: var(--paper);
  transition: border-color 0.2s ease, background 0.2s ease, color 0.2s ease;
}
.product-dropzone svg { width: 26px; height: 26px; flex-shrink: 0; color: var(--accent); }
.product-dropzone p { margin: 0; font-size: 0.85rem; line-height: 1.5; }
.product-dropzone p span { display: block; font-size: 0.78rem; opacity: 0.8; }
.product-dropzone:hover, .product-dropzone.is-dragover { border-color: var(--accent); background: var(--blush); color: var(--ink); }

.product-photo-grid { display: flex; flex-wrap: wrap; gap: 12px 18px; margin-top: 14px; }
.product-photo-grid:empty { margin-top: 0; }
/* Cadre organique (radius-blob), même traitement que .p-card-art côté
   boutique — les vignettes produit du backoffice n'ont plus rien d'un
   input file générique. */
.product-photo-card { position: relative; width: 88px; height: 88px; border-radius: var(--radius-blob); overflow: hidden; box-shadow: 0 6px 16px var(--shadow); }
.product-photo-card img { width: 100%; height: 100%; object-fit: cover; display: block; }
.product-photo-remove {
  position: absolute; top: 4px; right: 4px;
  width: 20px; height: 20px; border-radius: 50%; border: none; cursor: pointer;
  background: rgba(43, 39, 51, 0.72); color: #fff; font-size: 0.9rem; line-height: 1;
  display: flex; align-items: center; justify-content: center; padding: 0;
}
.product-photo-remove:hover { background: var(--danger); }
/* Photos déjà en ligne (07/09/2026, revu après retour utilisateur) : la
   suppression et le réordonnancement vivent dans une barre SOUS la
   vignette, pas en médaillons posés dessus — le cadre organique
   (--radius-blob) est rogné très fort à certains coins par son
   `overflow:hidden`, ce qui rendait des boutons en coin invisibles (y
   compris l'ancien bouton de suppression une fois deux autres ajoutés à
   côté). `.product-photo-remove` ci-dessus reste utilisé tel quel pour les
   vignettes en attente d'envoi (nouvelles photos pas encore enregistrées,
   cf. renderPreviews côté JS) — seules les photos déjà en ligne changent ici. */
/* La barre d'outils est plus large que la vignette (4 à 5 boutons de 24px
   contre 88px de photo) : une largeur figée à 88px la laissait déborder de
   part et d'autre, au point que les boutons de deux photos voisines se
   touchaient et paraissaient former une seule barre. L'item prend donc la
   largeur de son contenu, sans jamais passer sous celle de la vignette.
   (18/09/2026) */
.product-photo-item { display: flex; flex-direction: column; align-items: center; gap: 6px; width: max-content; min-width: 88px; }
.product-photo-toolbar { display: flex; gap: 4px; }
.product-photo-btn {
  width: 24px; height: 24px; border-radius: 50%; border: none; cursor: pointer;
  background: rgba(43, 39, 51, 0.72); color: #fff; font-size: 0.7rem; line-height: 1;
  display: flex; align-items: center; justify-content: center; padding: 0;
}
.product-photo-btn:hover:not(:disabled) { background: var(--accent); }
.product-photo-btn:disabled { opacity: 0.35; cursor: default; }
.product-photo-btn-danger:hover:not(:disabled) { background: var(--danger); }
.product-photo-btn svg { display: block; }

/* ─── Recadrage d'une photo (17/09/2026, cf. form.php) ─────────────────
   Modal fixé, posé sous <body> par le JS. Le cadre est un carré ; par-dessus
   la photo, un masque au galet (--radius-blob) assombrit ce que la vignette
   de boutique (.p-card-art, même forme) ne montrera pas. */
body.photo-crop-open { overflow: hidden; }
.photo-crop-modal { position: fixed; inset: 0; z-index: 100; display: flex; align-items: center; justify-content: center; padding: 16px; }
.photo-crop-modal[hidden] { display: none; }
.photo-crop-backdrop { position: absolute; inset: 0; background: rgba(43, 39, 51, 0.55); }
.photo-crop-dialog {
  position: relative; width: min(520px, 100%); max-height: calc(100vh - 32px); overflow: auto;
  background: var(--surface); border-radius: var(--radius-m); padding: 22px 26px 24px;
  box-shadow: 0 24px 60px var(--shadow-strong);
}
.photo-crop-dialog .admin-h2 { margin-top: 0; }
.photo-crop-help { margin: 0 0 14px; font-size: 0.85rem; line-height: 1.5; }
.photo-crop-stage {
  position: relative; width: 100%; aspect-ratio: 1; overflow: hidden; border-radius: var(--radius-s);
  background: #ffffff; cursor: grab; touch-action: none; user-select: none;
}
.photo-crop-stage:active { cursor: grabbing; }
/* Fond transparent : damier, comme dans n'importe quel éditeur d'image. */
.photo-crop-stage.is-transparent {
  background-color: #fff;
  background-image: linear-gradient(45deg, #e2dbe8 25%, transparent 25%, transparent 75%, #e2dbe8 75%),
                    linear-gradient(45deg, #e2dbe8 25%, transparent 25%, transparent 75%, #e2dbe8 75%);
  background-size: 16px 16px; background-position: 0 0, 8px 8px;
}
.photo-crop-stage img { position: absolute; top: 0; left: 0; max-width: none; transform-origin: 0 0; pointer-events: none; }
.photo-crop-mask {
  position: absolute; inset: 0; border-radius: var(--radius-blob); pointer-events: none;
  box-shadow: 0 0 0 999px rgba(43, 39, 51, 0.5), inset 0 0 0 1.5px rgba(255, 255, 255, 0.85);
}
.photo-crop-controls { display: flex; flex-direction: column; gap: 12px; margin-top: 14px; }
.photo-crop-zoom { display: flex; align-items: center; gap: 12px; font-size: 0.85rem; color: var(--ink-soft); }
.photo-crop-zoom input { flex: 1; accent-color: var(--accent); }
.photo-crop-bg { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 0.85rem; }
.photo-crop-swatch {
  display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px 5px 6px; cursor: pointer;
  border: 1.5px solid var(--rule); border-radius: var(--radius-pill); background: var(--paper);
  font: inherit; font-size: 0.8rem; color: var(--ink);
}
.photo-crop-swatch i { width: 16px; height: 16px; border-radius: 50%; border: 1px solid var(--rule); background: #fff; }
.photo-crop-swatch i.is-checker {
  background-image: linear-gradient(45deg, #c9c2d3 25%, transparent 25%, transparent 75%, #c9c2d3 75%),
                    linear-gradient(45deg, #c9c2d3 25%, transparent 25%, transparent 75%, #c9c2d3 75%);
  background-size: 8px 8px; background-position: 0 0, 4px 4px;
}
.photo-crop-swatch.is-active { border-color: var(--ink); background: var(--surface); }
.photo-crop-swatch[hidden] { display: none; }
.photo-crop-actions { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; }
.photo-crop-actions .admin-btn { padding: 8px 16px; font-size: 0.85rem; }
.photo-crop-status { margin: 0; min-height: 1.2em; font-size: 0.82rem; }

.product-model-dims { font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; margin: 0 0 8px; }

/* Conteneur du viewer three.js (bundle chargé à la demande, cf. admin-3d-viewer.js
   et le script de fin de page) — fond sombre façon plateau d'impression,
   même logique que .quote-configurator-promo côté boutique. */
.product-model-viewer {
  width: 100%; height: 220px; border-radius: var(--radius-m); overflow: hidden;
  background: linear-gradient(160deg, #2f2b3b, var(--ink)); margin-bottom: 12px; position: relative;
}
.product-model-viewer.is-loading::after {
  content: 'Chargement…'; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: var(--paper); font-size: 0.85rem; opacity: 0.75;
}
.product-model-viewer.is-error { display: flex; align-items: center; justify-content: center; color: var(--paper); font-size: 0.85rem; text-align: center; padding: 0 16px; }

@media (max-width: 900px) {
  .product-form-grid { grid-template-columns: 1fr; }
  .product-form-side { position: static; }
}

/* ─── Écrans d'authentification (login / enrôlement) ──────────────────
   Même halo de marque sur fond sombre que .quote-configurator-promo côté
   boutique (le panneau promo le plus reconnaissable du site) : la carte
   de connexion flotte dessus, comme une pièce d'accueil plutôt qu'un
   formulaire technique. */
/* `body.admin-body` (élément+classe) fixe déjà `background`, plus spécifique
   qu'une simple `.admin-auth-body` : sans le préfixe `body.` ici, le dégradé
   sombre ne l'emportait jamais et l'écran restait en fond papier clair
   (régression constatée le 29/08/2026). */
body.admin-auth-body {
  display: flex; align-items: center; justify-content: center; min-height: 100vh;
  padding: 24px;
  background:
    radial-gradient(circle at 18% 15%, rgba(236, 143, 102, 0.32), transparent 55%),
    radial-gradient(circle at 85% 85%, rgba(125, 156, 140, 0.26), transparent 55%),
    linear-gradient(160deg, #2f2b3b, var(--ink));
}
.admin-auth-card {
  background: var(--surface); border-radius: var(--radius-l); padding: 44px 38px;
  max-width: 420px; width: 100%; box-shadow: 0 26px 54px var(--shadow-strong); text-align: center;
}
.admin-auth-mark { width: 48px; height: 48px; border-radius: 14px; background: var(--paper); display: flex; align-items: center; justify-content: center; margin: 0 auto 18px; }
.admin-auth-mark svg { width: 32px; height: 32px; }
.admin-auth-title { font-family: var(--font-display); font-weight: 600; font-size: 1.4rem; margin: 0 0 8px; }
.admin-auth-subtitle { color: var(--ink-soft); margin: 0 0 22px; }
.admin-auth-text { font-size: 0.9rem; color: var(--ink-soft); text-align: left; margin-bottom: 20px; }
.admin-auth-status { min-height: 20px; font-size: 0.85rem; margin-bottom: 14px; }
.admin-auth-status.is-error { color: var(--danger); }
.admin-auth-status.is-success { color: var(--sage); }

/* ─── Rail d'icônes (780-1199 px, 23/09/2026) ─────────────────────────
   Entre le téléphone et le grand écran, la barre latérale complète mangeait
   un quart de la largeur. Elle se replie en rail : pictogrammes seuls,
   libellé en infobulle (`title`), pastilles en coin. Les sections restent
   séparées par un filet mais ne se replient plus — un pli dans un rail
   cacherait des pages sans rien pour le dire. */
@media (min-width: 780px) and (max-width: 1199px) {
  .admin-sidebar { width: var(--rail-w); padding: 12px 0 10px; }
  .admin-brand { justify-content: center; padding: 2px 0 10px; }
  .admin-brand-word, .admin-search-btn-label, .admin-search-btn kbd,
  .admin-nav-group, .admin-nav-label, .admin-sidebar-footer .admin-mode-switch, .admin-user { display: none; }
  .admin-search-btn { justify-content: center; margin: 0 14px 8px; padding: 9px 0; }
  .admin-nav { padding: 0 12px; gap: 2px; }
  .admin-nav-section { border-top: 1px solid rgba(255, 255, 255, 0.1); margin-top: 4px; padding-top: 4px; }
  .admin-nav-section.is-collapsed > .admin-nav-section-items { display: flex; }
  .admin-nav a { justify-content: center; padding: 9px 0; position: relative; }
  .admin-nav a .admin-icon { width: 20px; height: 20px; }
  .admin-nav a .admin-nav-count {
    position: absolute; top: 2px; right: 2px;
    min-width: 17px; height: 17px; padding: 0 4px; font-size: 0.64rem;
    box-shadow: 0 0 0 2px var(--ink);
  }
  .admin-sidebar-footer { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 10px 0 0; }
  .admin-mode-chip {
    display: block; padding: 3px 8px; border-radius: 8px;
    font-size: 0.66rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; text-decoration: none;
    background: var(--accent); color: var(--ink);
  }
  body.admin-mode-live .admin-mode-chip { background: #e0554a; color: #fff; }
  .admin-user-row { justify-content: center; }
  :root { --gutter: 22px; }
}

/* ─── Téléphone (< 780 px, refonte du 23/09/2026) ─────────────────────
   Avant : la barre latérale devenait un rang de seize onglets qui
   défilaient à l'horizontale, dont trois visibles. Désormais une barre
   d'onglets fixe en bas, au pouce — Accueil, Commandes, Produits,
   Fabrication — et « Plus » ouvre une feuille avec tout le reste, la
   recherche et le mode de paiement (choix confirmé avec l'exploitant). */
@media (max-width: 779px) {
  :root { --gutter: 16px; }
  .admin-shell { flex-direction: column; }
  .admin-sidebar { display: none; }
  .admin-main {
    padding: 12px var(--gutter) calc(var(--tabbar-h) + 24px + env(safe-area-inset-bottom));
  }
  .admin-page-header { margin-top: -12px; padding-top: calc(12px + env(safe-area-inset-top)); padding-bottom: 10px; }
  .admin-h1 { font-size: 1.3rem; }

  .admin-tabbar {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 80;
    height: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
    padding: 0 4px env(safe-area-inset-bottom);
    background: var(--ink); box-shadow: 0 -6px 20px rgba(0, 0, 0, 0.12);
    view-transition-name: admin-tabbar;
  }
  .admin-tab {
    flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    padding: 0; border: 0; background: none; cursor: pointer; font-family: inherit;
    color: rgba(241, 238, 243, 0.6); text-decoration: none;
    font-size: 0.68rem; font-weight: 600;
  }
  .admin-tab .admin-icon { width: 22px; height: 22px; }
  .admin-tab.is-active { color: var(--accent); }
  .admin-tab-icon { position: relative; display: inline-flex; }
  .admin-tab-icon .admin-nav-count {
    position: absolute; top: -6px; left: 14px;
    min-width: 17px; height: 17px; padding: 0 4px; font-size: 0.64rem;
    box-shadow: 0 0 0 2px var(--ink);
  }
  .admin-test-ribbon {
    display: block; position: fixed; z-index: 81; left: 50%; transform: translateX(-50%);
    bottom: calc(var(--tabbar-h) + 8px + env(safe-area-inset-bottom));
    padding: 4px 12px; border-radius: 999px;
    background: var(--accent); color: var(--ink); text-decoration: none;
    font-size: 0.7rem; font-weight: 700; letter-spacing: 0.04em;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18);
  }

  /* Défilement du tableau à toute largeur (18/09/2026) ; sur un téléphone
     une cellule qui se replie écrase le titre sur trois lignes — les
     tableaux qui ne passent pas en cartes (plus bas) restent d'un tenant. */
  .admin-table th, .admin-table td { white-space: nowrap; }

  .admin-section, .admin-card, .admin-form { padding: 14px; }
  .admin-page-header { align-items: flex-start; }
  .admin-page-header-actions .admin-btn { padding: 7px 12px; }
}

/* Mode « Ajouter par IA » (07/09/2026) : page de progression et indication
   de taille max sous un champ fichier. */
.admin-field-hint { color: var(--ink-soft); font-size: 0.85rem; margin: 4px 0 14px; }
.admin-spinner {
  width: 28px; height: 28px; margin-top: 10px;
  border: 3px solid var(--accent, #ec8f66); border-top-color: transparent;
  border-radius: 50%; animation: admin-spin 0.8s linear infinite;
}
@keyframes admin-spin { to { transform: rotate(360deg); } }

/* Page Marque (07/09/2026) : grille de cartes téléchargeables, une par item
   de charte graphique (symbole/logo/favicon/bannière). */
.brand-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 18px;
}
.brand-item.brand-wide { grid-column: 1 / -1; }
.brand-item {
  background: var(--surface); border-radius: var(--radius-m); padding: 18px;
  box-shadow: 0 10px 26px var(--shadow); display: flex; flex-direction: column; gap: 10px;
}
.brand-preview {
  border-radius: var(--radius-s); background: var(--paper-alt);
  display: flex; align-items: center; justify-content: center; padding: 18px; min-height: 110px;
}
.brand-preview.brand-preview-dark { background: var(--ink); }
.brand-preview img { max-width: 100%; max-height: 90px; object-fit: contain; }
.brand-item h3 { margin: 0; font-family: var(--font-display); font-weight: 600; font-size: 1rem; }
.brand-item-downloads { display: flex; gap: 8px; flex-wrap: wrap; margin-top: auto; }
.brand-item-downloads a {
  padding: 6px 14px; border-radius: var(--radius-pill); background: var(--paper-alt); color: var(--ink);
  font-size: 0.85rem; font-weight: 500; text-decoration: none;
}
.brand-item-downloads a:hover { background: var(--accent); color: #fff; }

/* ─── Réglages : onglets ─────────────────────────────────────────────── */
.admin-tabs { display: flex; gap: 8px; margin-bottom: 22px; flex-wrap: wrap; border-bottom: 1px solid var(--rule); }
.admin-tab-btn {
  padding: 10px 18px; border: none; background: none; cursor: pointer;
  font: inherit; font-weight: 500; color: var(--ink-soft);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.admin-tab-btn:hover { color: var(--ink); }
.admin-tab-btn.is-active { color: var(--accent-deep); border-bottom-color: var(--accent); font-weight: 600; }
.admin-tab-panel[hidden] { display: none; }
.brand-tabs a { display:inline-block; text-decoration:none; }
.brand-plan { max-width:1000px; line-height:1.62; }
.brand-plan p:last-child, .brand-plan ul:last-child, .brand-plan ol:last-child { margin-bottom:0; }
.brand-plan li { margin:8px 0; }
.brand-plan-lead { border-top:4px solid var(--accent); background:linear-gradient(135deg,var(--surface),var(--paper-alt)); }
.brand-plan-kicker { margin:0 0 8px; color:var(--accent-deep); font-size:.76rem; font-weight:700; letter-spacing:.08em; text-transform:uppercase; }
.brand-plan-promise { max-width:740px; margin:14px 0; font-family:var(--font-display); font-size:1.45rem; font-weight:600; line-height:1.3; }
.brand-plan-grid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:18px; max-width:1000px; }
.brand-pillars { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:14px; margin:18px 0; }
.brand-pillars article { padding:18px; border:1px solid var(--rule); border-radius:var(--radius-m); background:var(--paper-alt); }
.brand-pillars article > span { color:var(--accent-deep); font-family:var(--font-display); font-weight:700; }
.brand-pillars h3 { margin:8px 0 6px; font-family:var(--font-display); font-size:1rem; }
.brand-pillars p { margin:0; color:var(--ink-soft); font-size:.9rem; }
.brand-check-grid { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:12px; }
.brand-check-grid div { padding:14px; border-left:3px solid var(--accent); background:var(--paper-alt); border-radius:0 var(--radius-s) var(--radius-s) 0; }
.brand-check-grid strong, .brand-check-grid span { display:block; }
.brand-check-grid span { margin-top:5px; color:var(--ink-soft); font-size:.87rem; line-height:1.45; }
.brand-funnel { display:grid; grid-template-columns:repeat(5,minmax(0,1fr)); gap:10px; padding:0; list-style:none; counter-reset:funnel; }
.brand-funnel li { position:relative; margin:0; padding:38px 12px 14px; border-radius:var(--radius-s); background:var(--paper-alt); counter-increment:funnel; }
.brand-funnel li::before { content:counter(funnel); position:absolute; top:10px; left:12px; color:var(--accent-deep); font-family:var(--font-display); font-weight:700; }
.brand-funnel strong, .brand-funnel span { display:block; }
.brand-funnel span { margin-top:5px; color:var(--ink-soft); font-size:.82rem; line-height:1.4; }
.brand-launch-gate { border:1px solid color-mix(in srgb,var(--accent) 55%,var(--rule)); background:color-mix(in srgb,var(--accent) 8%,var(--surface)); }

.brand-roadmap-summary { display:grid; grid-template-columns:1.3fr repeat(4,1fr); gap:10px; margin-bottom:16px; }
.brand-roadmap-summary > div { display:flex; flex-direction:column; padding:14px 16px; border:1px solid var(--rule); border-radius:var(--radius-s); background:var(--surface); }
.brand-roadmap-summary strong { font-family:var(--font-display); font-size:1.3rem; }
.brand-roadmap-summary span { color:var(--ink-soft); font-size:.78rem; }
.brand-roadmap-total { background:var(--ink) !important; color:var(--paper); }
.brand-roadmap-total span { color:rgba(255,255,255,.68); }
.brand-priority-legend { display:flex; flex-wrap:wrap; gap:8px 18px; margin:0 0 22px; color:var(--ink-soft); font-size:.8rem; }
.brand-priority-legend span { display:flex; align-items:center; gap:6px; }
.brand-priority-progress { display:flex; flex-wrap:wrap; gap:8px; margin:-8px 0 22px; }
.brand-priority-progress > span { display:flex; align-items:center; gap:7px; padding:7px 10px; border:1px solid var(--rule); border-radius:var(--radius-pill); color:var(--ink-soft); font-size:.76rem; background:var(--surface); }
.brand-priority-progress strong { color:var(--ink); }
.brand-priority, .brand-priority-legend b { display:inline-flex; align-items:center; justify-content:center; min-width:32px; padding:3px 7px; border-radius:var(--radius-pill); font-size:.7rem; font-weight:700; text-decoration:none; }
.brand-priority-progress b { display:inline-flex; align-items:center; justify-content:center; min-width:32px; padding:3px 7px; border-radius:var(--radius-pill); font-size:.7rem; }
.priority-P0 { background:#ffe2df; color:#a7342b; }
.priority-P1 { background:#ffe9d3; color:#8b4f13; }
.priority-P2 { background:#e4edf8; color:#315d8c; }
.priority-P3 { background:#e9e6ed; color:#62596a; }
.brand-todo-group { max-width:1000px; }
.brand-todo { position:relative; display:grid; grid-template-columns:minmax(0,1.7fr) minmax(270px,.8fr); gap:22px; padding:20px 0; border-top:1px solid var(--rule); }
.brand-todo::before { content:""; position:absolute; left:-24px; top:20px; bottom:20px; width:3px; border-radius:3px; background:var(--rule); }
.brand-todo.status-in_progress::before { background:#dd8a37; }
.brand-todo.status-review::before { background:#4e7faf; }
.brand-todo.status-verified::before { background:#4c8b66; }
.brand-todo-heading { display:flex; align-items:flex-start; gap:9px; }
.brand-todo-heading strong { line-height:1.35; }
.brand-todo-copy > p { margin:8px 0 13px; color:var(--ink-soft); line-height:1.5; }
.brand-todo-copy dl { display:grid; gap:7px; margin:0; }
.brand-todo-copy dl div { display:grid; grid-template-columns:76px minmax(0,1fr); gap:8px; font-size:.82rem; line-height:1.42; }
.brand-todo-copy dt { color:var(--accent-deep); font-weight:700; }
.brand-todo-copy dd { margin:0; color:var(--ink-soft); }
.brand-todo-controls { display:grid; grid-template-columns:1fr 1fr; gap:10px; align-content:start; }
.brand-todo-controls label { display:flex; flex-direction:column; gap:4px; color:var(--ink-soft); font-size:.72rem; font-weight:600; }
.brand-todo-controls input, .brand-todo-controls select { width:100%; min-height:38px; padding:8px 10px; border:1px solid var(--rule); border-radius:var(--radius-s); background:var(--surface); color:var(--ink); font:inherit; font-size:.84rem; }
.brand-todo-controls input:focus, .brand-todo-controls select:focus { outline:2px solid var(--accent); outline-offset:1px; }
.brand-todo-evidence { grid-column:1 / -1; }
.brand-todo-controls .admin-btn { justify-self:end; grid-column:1 / -1; }
.brand-todo-verified-at { position:absolute; right:0; bottom:3px; color:#4c8b66; font-size:.7rem; }
@media (max-width:900px) {
  .brand-pillars, .brand-check-grid { grid-template-columns:1fr; }
  .brand-funnel { grid-template-columns:repeat(2,minmax(0,1fr)); }
  .brand-todo { grid-template-columns:1fr; }
  .brand-todo::before { left:-18px; }
}
@media (max-width:650px) {
  .brand-plan-grid { grid-template-columns:1fr; gap:0; }
  .brand-roadmap-summary { grid-template-columns:repeat(2,1fr); }
  .brand-roadmap-total { grid-column:1 / -1; }
  .brand-funnel { grid-template-columns:1fr; }
  .brand-todo-controls { grid-template-columns:1fr; }
  .brand-todo-evidence, .brand-todo-controls .admin-btn { grid-column:auto; }
  .brand-todo-controls .admin-btn { justify-self:stretch; }
  .brand-todo-copy dl div { grid-template-columns:1fr; gap:2px; }
}

/* ─── Sidebar : switch rapide mode paiement (test/live) ──────────────── */
.admin-mode-switch { margin-bottom: 14px; }
.admin-mode-switch-label { display: block; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; opacity: 0.55; margin-bottom: 6px; }
.admin-mode-switch-track { display: flex; gap: 4px; background: rgba(255,255,255,0.08); border-radius: var(--radius-pill); padding: 3px; }
.admin-mode-switch-track form { flex: 1; display: flex; margin: 0; }
.admin-mode-switch-opt {
  flex: 1; border: none; background: none; cursor: pointer; font: inherit; font-size: 0.78rem; font-weight: 600;
  padding: 6px 10px; border-radius: var(--radius-pill); color: var(--paper); opacity: 0.55;
  transition: opacity 0.2s ease, background 0.2s ease;
}
.admin-mode-switch-opt:hover:not(:disabled) { opacity: 0.9; }
.admin-mode-switch-opt.is-active { opacity: 1; background: var(--accent); color: var(--ink); }
.admin-mode-switch-opt.is-live.is-active { background: #e0554a; color: #fff; }
.admin-mode-switch-opt:disabled { cursor: default; }
.admin-mode-switch-opt:disabled:not(.is-active) { opacity: 0.25; }

/* ─── Recherche de catégorie Etsy (Réglages, 18/09/2026) ─────────────────
   Remplace un <select> de 3 000+ options. Le conteneur est positionné pour
   que la liste de propositions se pose par-dessus la suite du formulaire
   au lieu de le pousser vers le bas à chaque frappe. */
.admin-taxo { position: relative; display: block; }
.admin-taxo input[type="search"] { width: 100%; }
.admin-taxo-results {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 20;
  display: flex; flex-direction: column; max-height: 260px; overflow-y: auto;
  background: var(--paper); border: 1px solid var(--rule); border-radius: var(--radius-m);
  box-shadow: 0 12px 28px rgba(0,0,0,0.13);
}
.admin-taxo-option {
  border: none; background: none; cursor: pointer; font: inherit; font-size: 0.85rem;
  text-align: left; padding: 8px 12px; color: var(--ink);
}
.admin-taxo-option:hover, .admin-taxo-option:focus-visible { background: var(--paper-alt); }
.admin-taxo-option + .admin-taxo-option { border-top: 1px solid var(--rule); }
.admin-taxo-empty { padding: 8px 12px; font-size: 0.85rem; color: var(--ink-soft); }
.admin-etsy-lists-age form { display: inline; margin: 0; }

/* ─── Fenêtres du site : modale de confirmation et bandeaux (18/09/2026) ───
   Remplacent `confirm()` et `alert()`, qui ouvraient une boîte grise du
   navigateur impossible à habiller. Le support est un <dialog> natif, pour
   le piège de focus et la fermeture par Échap — l'élément HTML prévu pour
   ça, pas une fenêtre du navigateur. */
.admin-dialog {
  border: none; padding: 0; background: transparent; color: var(--ink);
  max-width: none; max-height: none; width: 100%; height: 100%;
  /* Le <dialog> sert de fond plein écran et centre son panneau ;
     ::backdrop reste peint en dessous pour l'assombrissement. */
  display: none; place-items: center;
}
.admin-dialog[open] { display: grid; }
.admin-dialog::backdrop { background: rgba(26, 22, 32, 0.55); backdrop-filter: blur(2px); }
.admin-dialog-panel {
  width: min(440px, calc(100vw - 32px));
  background: var(--paper); border-radius: var(--radius-l);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.28);
  padding: 26px;
  animation: admin-dialog-in 0.22s var(--ease-snap);
}
.admin-dialog-title {
  font-family: var(--font-display); font-size: 1.15rem; font-weight: 600; margin: 0;
}
.admin-dialog-text {
  margin: 10px 0 0; font-size: 0.92rem; line-height: 1.5; color: var(--ink-soft);
}
.admin-dialog-actions {
  display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; margin-top: 22px;
}
.admin-dialog-confirm.is-danger {
  background: var(--danger); border-color: var(--danger); color: #fff;
}
.admin-dialog-confirm.is-danger:hover { background: #9c2d20; border-color: #9c2d20; }
.admin-dialog.is-danger .admin-dialog-title { color: var(--danger); }
@keyframes admin-dialog-in {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to { opacity: 1; transform: none; }
}

/* Sous 520 px, la modale devient une feuille ancrée en bas — même convention
   que les popovers du site public. */
@media (max-width: 520px) {
  .admin-dialog[open] { place-items: end stretch; }
  .admin-dialog-panel {
    width: auto; border-radius: var(--radius-l) var(--radius-l) 0 0;
    padding-bottom: calc(26px + env(safe-area-inset-bottom));
  }
  .admin-dialog-actions .admin-btn { flex: 1; text-align: center; }
}

.admin-toasts {
  position: fixed; top: 16px; right: 16px; z-index: 9999;
  display: flex; flex-direction: column; gap: 8px; align-items: flex-end;
  pointer-events: none;
}
.admin-toast {
  pointer-events: auto; cursor: pointer;
  max-width: min(380px, calc(100vw - 32px));
  padding: 12px 18px; border-radius: var(--radius-m);
  font-size: 0.88rem; font-weight: 500; line-height: 1.4;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.22);
  animation: admin-toast-in 0.22s var(--ease-snap);
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.admin-toast.is-error { background: var(--danger); color: #fff; }
.admin-toast.is-ok { background: var(--sage); color: #2f4438; }
.admin-toast.is-leaving { opacity: 0; transform: translateX(12px); }
@keyframes admin-toast-in {
  from { opacity: 0; transform: translateX(16px); }
  to { opacity: 1; transform: none; }
}
@media (max-width: 520px) {
  .admin-toasts { top: auto; bottom: calc(16px + env(safe-area-inset-bottom)); left: 16px; right: 16px; align-items: stretch; }
  .admin-toast { max-width: none; }
}
@media (prefers-reduced-motion: reduce) {
  .admin-toast, .admin-dialog-panel { animation: none; transition: none; }
}

/* ── Fabrication > Impression (21/09/2026) ─────────────────────────────────
   Page à onglets calquée sur celle d'IntraAkynet (cf. views/admin/impression.php).
   Les onglets eux-mêmes réutilisent .admin-tabs/.admin-tab-panel des Réglages :
   rien n'est redéfini ici. Préfixe `imp-` pour tout ce qui est propre à la page. */

.imp-intro { max-width: 68ch; margin: 0 0 18px; }
.admin-empty { text-align: center; padding: 40px 20px; }

/* ── Bibliothèque ───────────────────────────────────────────────────────── */
.imp-library {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(212px, 100%), 1fr));
  gap: 18px;
  /* L'ombre des cartes du bas n'est pas rognée par la boîte de défilement. */
  padding-bottom: 6px;
}
.imp-lib-card {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius-m);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-width: 0; /* sinon un titre long fait déborder la grille */
  box-shadow: 0 6px 18px var(--shadow);
  transition: transform 0.2s var(--ease-snap), box-shadow 0.2s ease, border-color 0.2s ease;
}
.imp-lib-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 16px 34px var(--shadow-strong);
  border-color: var(--accent);
}
.imp-lib-card.is-inactive { opacity: 0.58; }

.imp-lib-art {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--paper-alt);
  overflow: hidden;
}
/* L'image est sortie du flux. En flux, sa hauteur naturelle constitue la
   contribution de contenu minimale de la boîte et l'emporte sur
   `aspect-ratio` : les vignettes carrées du catalogue donnaient des cartes de
   442 px dont une seule rangée tenait à l'écran. */
.imp-lib-art img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; display: block;
}
.imp-lib-noart {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--font-display); color: var(--ink-faint); font-size: 1.4rem;
}
/* Pastille propre à la page, et non `.admin-badge-info` : celle-ci pulse en
   boucle (elle signale UN élément qui demande une action). Sur une grille de
   24 pièces, vingt pastilles clignotantes à la fois. Fond sombre translucide :
   la version claire était illisible sur une photo d'ambiance. */
.imp-lib-badge {
  position: absolute; top: 9px; left: 9px;
  background: rgba(43, 39, 51, 0.74);
  color: #fff;
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  font-size: 0.68rem; font-weight: 600; letter-spacing: 0.02em;
  backdrop-filter: blur(4px);
}

.imp-lib-body {
  padding: 13px 15px 15px;
  display: flex; flex-direction: column; gap: 5px;
  min-width: 0;
  flex: 1; /* le corps occupe la carte : c'est lui qui pousse le bouton en bas */
}
.imp-lib-title {
  font-family: var(--font-display);
  font-size: 0.95rem;
  line-height: 1.32;
  margin: 0;
  /* Deux lignes maximum : au-delà, les cartes de la grille se décalent. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.imp-lib-meta { margin: 0; font-size: 0.78rem; }
.imp-lib-dims {
  margin: 0; font-size: 0.74rem;
  font-variant-numeric: tabular-nums; /* les dimensions s'alignent d'une carte à l'autre */
  margin-bottom: 8px;
}
/* `auto`, et non une marge fixe : un titre tient sur une ou deux lignes selon
   la pièce, et une marge fixe laissait les boutons d'une même rangée à trois
   hauteurs différentes — c'est ce qui donnait à la grille son air bâclé. */
button.imp-lib-place {
  margin-top: auto;
  width: 100%; text-align: center;
  padding: 9px 14px; font-size: 0.84rem;
}
/* Au repos le bouton reste neutre : 24 boutons orange pleins faisaient un mur
   de couleur où plus rien ne ressortait. Il prend l'accent quand la carte est
   survolée ou qu'il reçoit le clavier — l'action reste évidente, une à la fois. */
button.imp-lib-place {
  background: var(--paper-alt);
  border-color: transparent;
  color: var(--ink);
  box-shadow: none;
}
.imp-lib-card:hover button.imp-lib-place,
button.imp-lib-place:hover,
button.imp-lib-place:focus-visible {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

/* ── Bobines de filament ────────────────────────────────────────────────── */
/* Une bobine se reconnaît à sa couleur, pas à son numéro de tiroir : la
   pastille porte la teinte réelle de la machine, le texte ne fait que la
   nommer. Deux colonnes : quatre bacs tiennent en deux lignes dans le volet. */
.imp-filaments {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 7px;
}
.imp-filament {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 9px;
  border: 1.5px solid var(--rule);
  border-radius: var(--radius-s);
  background: var(--surface);
  cursor: pointer;
  font: inherit; text-align: left;
  min-width: 0;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.imp-filament:hover:not(:disabled) { border-color: var(--accent); }
.imp-filament.is-active { border-color: var(--accent); background: var(--blush); }
.imp-filament-dot {
  width: 17px; height: 17px; flex: none;
  border-radius: 50%;
  background: var(--paper-alt);
  /* Cerne intérieur : une bobine blanche ou très claire disparaîtrait
     autrement sur le fond de la carte. */
  box-shadow: inset 0 0 0 1px rgba(43, 39, 51, 0.22);
}
.imp-filament-txt { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.imp-filament-name {
  font-size: 0.8rem; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.imp-filament-sub { font-size: 0.68rem; color: var(--ink-faint); }
/* Bac vide : inerte, et qui le dit. La machine refuserait le plateau de toute
   façon — autant le voir avant le lancement qu'après le tranchage. */
.imp-filament.is-empty { opacity: 0.5; cursor: not-allowed; }
.imp-filament.is-empty .imp-filament-dot {
  background: repeating-linear-gradient(45deg, var(--paper-alt) 0 3px, var(--rule) 3px 6px);
}

/* ── Préréglage d'impression ────────────────────────────────────────────── */
.imp-preset { display: grid; gap: 8px; margin-bottom: 14px; }
.imp-preset-opt {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 10px 12px;
  border: 1.5px solid var(--rule);
  border-radius: var(--radius-s);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.imp-preset-opt:hover { border-color: var(--accent); }
/* `:has()` plutôt qu'une classe posée en JS : l'état coché est déjà porté par
   le bouton radio, le dupliquer dans le DOM inviterait les deux à diverger. */
.imp-preset-opt:has(input:checked) { border-color: var(--accent); background: var(--blush); }
.imp-preset-opt input { margin-top: 3px; accent-color: var(--accent); flex: none; }
.imp-preset-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.imp-preset-name { font-size: 0.85rem; font-weight: 600; }
.imp-preset-desc { font-size: 0.72rem; color: var(--ink-faint); line-height: 1.35; }

/* Trois groupes de choix se suivent : un intitulé les sépare, sinon ils se
   lisent comme une seule liste de six options. */
.imp-choix-titre {
  font-size: 0.72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--ink-faint);
  margin: 4px 0 7px;
}
.imp-choix-titre.is-inert { opacity: 0.45; }
/* Les groupes secondaires portent une description plus courte : moins d'air. */
.imp-preset-compact .imp-preset-opt { padding: 8px 11px; }
.imp-preset-compact .imp-preset-desc { font-size: 0.7rem; }
/* Grisé, pas masqué : l'arbitrage n'est lu que par le prompt du modèle, donc
   il ne décide de rien sans analyse. Un bloc qui disparaît fait douter de
   l'avoir rêvé ; un bloc grisé dit qu'il attend autre chose. */
.imp-preset.is-inert { opacity: 0.45; }
.imp-preset.is-inert .imp-preset-opt { cursor: not-allowed; border-color: var(--rule); background: none; }
/* Le modèle employé, en petit, à côté du nom de l'option. */
.imp-preset-tag {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.66rem; font-weight: 500;
  color: var(--ink-faint);
  background: var(--paper-alt);
  padding: 1px 6px; border-radius: var(--radius-pill);
  margin-left: 5px;
}

/* Ce que l'IA a décidé, après coup. */
.imp-ailog {
  margin-top: 12px; padding: 10px 12px;
  border-radius: var(--radius-s);
  background: var(--paper-alt);
}
.imp-ailog-title {
  font-size: 0.72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--ink-faint); margin-bottom: 6px;
}
/* Du texte suivi, et non une chasse fixe : le modèle rend une explication en
   français, pas un journal machine. */
.imp-ailog-body {
  margin: 0; font-size: 0.76rem; line-height: 1.5;
  max-height: 180px; overflow-y: auto;
}
.imp-ailog-changed {
  margin: 8px 0 0; font-size: 0.68rem; line-height: 1.4;
  color: var(--ink-faint);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  word-break: break-word;
  max-height: 84px; overflow-y: auto;
}
.imp-ailog-title span { font-weight: 500; text-transform: none; letter-spacing: 0; }

/* ── Plateau ────────────────────────────────────────────────────────────── */
.imp-plate-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px; /* minmax(0,…) : sinon le viewer pousse la grille */
  gap: 20px;
  align-items: start;
}
.imp-plate-stage { min-width: 0; }
.imp-plate-viewer {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius-m);
  min-height: 460px;
  display: grid;
  place-items: center;
  overflow: hidden;
}
.imp-plate-canvas { position: absolute; inset: 0; }
.imp-plate-empty { text-align: center; padding: 24px; }
.imp-plate-empty p { margin: 4px 0; }
.imp-plate-caption { margin: 10px 2px 0; font-size: 0.85rem; }

.imp-detail {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius-m);
  padding: 16px;
  min-width: 0;
  position: sticky;
  top: 16px;
}
.imp-detail-head { display: flex; align-items: flex-start; gap: 10px; }
.imp-detail-head .admin-h2 { margin: 0; flex: 1; min-width: 0; font-size: 1.05rem; word-break: break-word; }
.imp-detail-dims {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px; margin: 14px 0 0;
}
.imp-detail-dims div { background: var(--paper); border-radius: var(--radius-s); padding: 8px; text-align: center; }
.imp-detail-dims dt { font-size: 0.7rem; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.04em; }
.imp-detail-dims dd { margin: 2px 0 0; font-weight: 600; font-size: 0.86rem; }

/* ── Composeur dans le volet de détail ──────────────────────────────────── */
.imp-compose { margin-top: 18px; border-top: 1px solid var(--rule); padding-top: 14px; }
.imp-compose-tabs { display: flex; gap: 6px; margin-bottom: 14px; }
.imp-compose-tab {
  flex: 1; padding: 8px 10px; border: 1px solid var(--rule); background: var(--paper);
  border-radius: var(--radius-pill); font: inherit; font-size: 0.82rem; cursor: pointer; color: var(--ink-soft);
}
.imp-compose-tab.is-active { background: var(--ink); color: #fff; border-color: var(--ink); }
.imp-compose-note { font-size: 0.78rem; margin: 10px 0 0; }
.imp-compose-error { margin: 10px 0; }

.imp-field { margin-bottom: 14px; }
.imp-field-label {
  display: block; font-size: 0.72rem; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--ink-soft); margin-bottom: 6px; font-weight: 600;
}
.imp-field-note { font-size: 0.8rem; margin: 0 0 14px; }
.imp-field input[type="text"], .imp-field input[type="range"] {
  width: 100%; box-sizing: border-box;
}
.imp-field input[type="text"] {
  padding: 9px 12px; border: 1.5px solid var(--rule);
  border-radius: var(--radius-pill); font: inherit; font-size: 0.88rem;
}
.imp-choices { display: flex; flex-wrap: wrap; gap: 6px; }
.imp-choice {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 11px; border: 1px solid var(--rule); border-radius: var(--radius-pill);
  font-size: 0.8rem; cursor: pointer; background: var(--surface);
}
.imp-choice.is-active { border-color: var(--accent); background: var(--blush); }
.imp-choice input { margin: 0; }

.imp-dropzone {
  display: grid; place-items: center; text-align: center;
  padding: 22px 14px; border: 1.5px dashed var(--rule); border-radius: var(--radius-m);
  background: var(--paper); cursor: pointer; font-size: 0.85rem; color: var(--ink-soft);
}
.imp-dropzone:hover, .imp-dropzone:focus-visible { border-color: var(--accent); }
.imp-dropzone-sm { padding: 14px 10px; font-size: 0.8rem; }

.imp-order {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  padding: 9px 11px; margin-bottom: 6px; background: var(--paper);
  border: 1px solid var(--rule); border-radius: var(--radius-s);
  font: inherit; font-size: 0.82rem; cursor: pointer;
}
.imp-order:hover { border-color: var(--accent); }
.imp-order-ref { font-weight: 600; }
.imp-order-date { flex: 1; min-width: 0; font-size: 0.75rem; }

/* ── Atelier ────────────────────────────────────────────────────────────── */
.imp-atelier { max-width: 640px; display: flex; flex-direction: column; gap: 14px; }
.imp-atelier .admin-h2 { margin: 0; }
.imp-atelier-modes { display: flex; gap: 8px; flex-wrap: wrap; }
.imp-atelier-mode.is-active { background: var(--ink); color: #fff; border-color: var(--ink); }
.imp-atelier textarea {
  width: 100%; box-sizing: border-box; padding: 10px 12px;
  border: 1.5px solid var(--rule); border-radius: var(--radius-s); font: inherit; font-size: 0.9rem;
}
.imp-atelier-height { display: flex; align-items: center; gap: 8px; font-size: 0.86rem; color: var(--ink-soft); }
.imp-atelier-height input { width: 90px; padding: 7px 10px; border: 1.5px solid var(--rule); border-radius: var(--radius-pill); font: inherit; }

/* ── File d'impression ──────────────────────────────────────────────────── */
.imp-printer { display: flex; flex-direction: column; gap: 10px; }
.imp-printer-state { margin: 0; font-family: var(--font-display); font-size: 1.1rem; text-transform: capitalize; }
.imp-printer-state.is-off { color: var(--ink-faint); }
/* Impression appartenant à IntraAkynet : la machine est prise, mais rien de ce
   travail n'est lisible ni pilotable depuis le backoffice marchand. */
.imp-printer-state.is-foreign { color: var(--ink-faint); text-transform: none; }
.imp-commands.is-inert { opacity: 0.5; }
.imp-commands.is-inert button { cursor: not-allowed; }

/* Tableau des impressions du site : quatre colonnes et des libellés courts.
   `.admin-table` est en `display:block` pour porter son propre défilement —
   ses lignes se dimensionnent alors sur leur CONTENU, laissant un pan de carte
   vide à droite, et son fondu de bord estompe la première colonne alors qu'il
   n'y a rien à faire glisser. Ici le tableau redevient un vrai tableau, et
   c'est l'enveloppe qui défilerait au besoin. */
.imp-queue-table { display: table; overflow: visible; mask-image: none; -webkit-mask-image: none; }
.imp-queue-table th:first-child, .imp-queue-table td:first-child { width: 45%; }
.imp-queue-wrap { overflow-x: auto; }
.imp-printer-file { margin: 0; font-size: 0.82rem; color: var(--ink-soft); word-break: break-all; }
.imp-progress { height: 8px; background: var(--paper-alt); border-radius: 999px; overflow: hidden; }
.imp-progress span { display: block; height: 100%; background: var(--accent); transition: width 0.4s var(--ease-snap); }
.imp-printer-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(90px, 1fr)); gap: 8px; margin: 0;
}
.imp-printer-stats dt { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-soft); }
.imp-printer-stats dd { margin: 2px 0 0; font-weight: 600; font-size: 0.88rem; }
.imp-queue-heading { margin-top: 26px; }
.imp-sub { font-family: var(--font-display); font-size: 0.95rem; margin: 18px 0 8px; }
/* Le tableau déborde plutôt que d'écraser ses colonnes sur petit écran. */
.admin-table-wrap { overflow-x: auto; }

/* ── Timelapse ──────────────────────────────────────────────────────────── */
.imp-tl-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr)); gap: 14px;
}
.imp-tl { margin: 0; background: var(--surface); border: 1px solid var(--rule); border-radius: var(--radius-m); overflow: hidden; min-width: 0; }
.imp-tl img, .imp-tl-player, .imp-tl-noart {
  display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: cover; background: var(--paper-alt);
}
.imp-tl img { cursor: pointer; }
.imp-tl figcaption { padding: 9px 11px; font-size: 0.78rem; word-break: break-all; }

/* ── Écrans étroits ─────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  .imp-plate-layout { grid-template-columns: minmax(0, 1fr); }
  .imp-detail { position: static; }
  .imp-plate-viewer { min-height: 320px; }
}

/* ── Lancement et commandes machine (21/09/2026) ───────────────────────────
   Ajouts de l'ouverture en écriture du pont : le bouton de lancement dans le
   volet de détail du plateau, et les trois commandes de l'onglet File. */
.imp-launch {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--rule);
}
.imp-launch-note { font-size: 0.76rem; margin: 8px 0 0; }
.imp-launch-state { font-size: 0.8rem; margin: 8px 0 0; font-weight: 600; color: var(--ink); }
.imp-launch .admin-notice { margin-top: 10px; }

.imp-commands { display: flex; flex-wrap: wrap; gap: 8px; margin: 14px 0 0; }
/* L'annulation ne doit pas se cliquer par inadvertance à côté des deux autres. */
.imp-commands [data-imp-command="cancel"] { margin-left: auto; }
@media (max-width: 560px) {
  .imp-commands [data-imp-command="cancel"] { margin-left: 0; width: 100%; }
}

/* ── Plateau réel de la CC2 (21/09/2026) ───────────────────────────────────
   Le viewer occupe toute la boîte ; la légende et l'avertissement vivent
   sous elle, jamais par-dessus — le coin condamné ne doit rien avoir devant. */
.imp-plate-canvas { position: absolute; inset: 0; }
.imp-plate-canvas canvas { display: block; width: 100%; height: 100%; }
/* Le message « plateau vide » ne doit pas capter l'orbite quand il reste. */
.imp-plate-empty { position: relative; z-index: 1; pointer-events: none; }
.imp-plate-legend { margin: 8px 2px 0; font-size: 0.78rem; max-width: 62ch; }
.imp-plate-warn { margin: 10px 0 0; }

/* ── Plateau multi-pièces (21/09/2026) ─────────────────────────────────────
   Colonne de droite : liste des pièces, volet de la pièce sélectionnée, puis
   le lancement — qui porte TOUT le plateau, d'où sa place hors du volet. */
.imp-toolbar {
  display: flex; flex-wrap: wrap; gap: 10px; justify-content: space-between;
  margin-bottom: 12px;
}
.imp-tool-group { display: flex; flex-wrap: wrap; gap: 6px; }
.imp-tool.is-active { background: var(--ink); color: #fff; border-color: var(--ink); }
/* Le mode « poser à plat » attend un clic sur une facette : le curseur le dit. */
.imp-plate-viewer.is-layflat { cursor: crosshair; }

.imp-side { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.imp-panel {
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius-m); padding: 14px; min-width: 0;
}
.imp-panel-head { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 10px; }
.imp-panel-head .admin-h2 { margin: 0; flex: 1; min-width: 0; font-size: 1rem; word-break: break-word; }
.imp-panel-actions { display: flex; gap: 6px; flex-shrink: 0; }
.imp-count {
  display: inline-block; min-width: 20px; padding: 1px 7px; margin-left: 4px;
  background: var(--paper-alt); border-radius: 999px; font-size: 0.78rem; font-weight: 600;
}

.imp-objects { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.imp-objects-empty { font-size: 0.85rem; padding: 4px 2px; }
.imp-object {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  padding: 7px 9px; background: var(--paper); border: 1px solid transparent;
  border-radius: var(--radius-s); font: inherit; font-size: 0.82rem; cursor: pointer;
}
.imp-object:hover { border-color: var(--rule); }
.imp-object.is-active { border-color: var(--accent); background: var(--blush); }
.imp-object-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.imp-object-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.imp-object-dims { font-size: 0.72rem; flex-shrink: 0; }

.imp-field-group { margin-top: 14px; }
.imp-field-group-title {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--ink-soft); font-weight: 600; margin-bottom: 6px;
}
.imp-axes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.imp-axes label {
  display: flex; align-items: center; gap: 4px; font-size: 0.74rem; color: var(--ink-soft);
}
.imp-axes input {
  width: 100%; min-width: 0; padding: 6px 8px; border: 1.5px solid var(--rule);
  border-radius: var(--radius-s); font: inherit; font-size: 0.82rem;
}
.imp-axes input[readonly] { background: var(--paper-alt); color: var(--ink-faint); }

.imp-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-left: auto; }
.imp-chip {
  padding: 4px 9px; border: 1px solid var(--rule); border-radius: var(--radius-pill);
  background: var(--surface); font: inherit; font-size: 0.76rem; cursor: pointer;
}
.imp-chip:hover { border-color: var(--accent); }
.imp-chip.is-active { border-color: var(--accent); background: var(--blush); }
.imp-lock { display: inline-flex; align-items: center; gap: 4px; font-size: 0.72rem; text-transform: none; letter-spacing: 0; }
[data-imp-filaments] { margin-left: 0; }

.imp-plate-warn ul { margin: 6px 0 0; padding-left: 18px; }
.imp-plate-warn li { margin: 2px 0; }

/* ── Occupation de l'espace du Plateau (21/09/2026) ────────────────────────
   Reprise après constat à l'écran : le plateau flottait dans un cadre trop
   grand et la colonne de droite était vide aux trois quarts. Le cadrage 3D
   est corrigé côté JS (`cadrer()`) ; ici on règle la boîte qui l'accueille. */

/* Le visualiseur prend la hauteur réellement disponible plutôt qu'un minimum
   arbitraire : `min()` le borne sur les petits écrans, `dvh` suit la barre
   d'adresse mobile. */
.imp-plate-viewer {
  min-height: 0;
  height: min(68dvh, 680px);
}

/* La colonne de droite était figée à 340px, trop étroite pour ses champs sur
   grand écran et trop large sur un portable. */
.imp-plate-layout { grid-template-columns: minmax(0, 1fr) clamp(300px, 26vw, 390px); }

/* Les panneaux se resserrent : sur un plateau vide, trois encadrés espacés
   pour deux lignes de texte donnaient une colonne à moitié vide. */
.imp-side { gap: 10px; }
.imp-panel { padding: 12px 13px; }
.imp-panel-head { margin-bottom: 8px; }
.imp-field-group { margin-top: 11px; }
.imp-launch { padding: 12px 13px; }
.imp-launch-note { font-size: 0.74rem; margin-top: 7px; }

/* Plateau vide : le bloc de lancement n'a pas à occuper la place d'un volet
   de détail absent. */
.imp-objects-empty { padding: 2px 2px 4px; }

@media (min-width: 1500px) {
  /* Au-delà, la colonne cesse de grandir et c'est le plateau qui profite de
     la largeur — c'est lui qu'on regarde. */
  .imp-plate-layout { grid-template-columns: minmax(0, 1fr) 390px; }
}

@media (max-width: 900px) {
  .imp-plate-viewer { height: min(52dvh, 460px); }
}

/* Le cadre prend le rapport de ce qu'il montre (21/09/2026, 2e passe).
   Une hauteur fixe de 680 px laissait forcément du vide : le plateau est une
   dalle carrée vue à ~35°, sa projection fait environ 0,6 fois sa largeur.
   Le cadre suit donc la largeur de la colonne, et `cadrer()` le remplit. */
.imp-plate-viewer { height: auto; aspect-ratio: 16 / 10; }
@media (max-width: 900px) { .imp-plate-viewer { height: auto; aspect-ratio: 4 / 3; } }

/* ── Page Impression : tout tient dans le viewport (21/09/2026, 3e passe) ──
   Reprise après retour utilisateur : « faut pas qu'il y ait du scroll ».

   `.admin-main` est plafonnée à 1140 px et laisse la page défiler — ce qui
   convient aux listes du backoffice, pas à un plateau 3D qu'on manipule : on
   ne doit pas avoir à scroller pour voir la pièce qu'on est en train de
   déplacer. Cette page seule passe donc en hauteur de viewport, et c'est le
   CONTENU des onglets qui défile, jamais la page.

   Ciblée par `:has()` plutôt que par une classe sur <body> : le gabarit admin
   n'expose pas de crochet pour ça, et un sélecteur suffit. Sur un navigateur
   sans `:has()`, rien ne s'applique et la page défile comme avant — dégradation
   propre, pas de casse. */
.admin-main:has([data-imp-viewer]) {
  max-width: none;
  height: 100dvh;
  padding: 24px 30px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-sizing: border-box;
}
/* L'en-tête et les onglets gardent leur taille ; seul le panneau s'étire. */
.admin-main:has([data-imp-viewer]) > .admin-page-header,
.admin-main:has([data-imp-viewer]) > .admin-tabs { flex-shrink: 0; }
.admin-main:has([data-imp-viewer]) > .admin-page-header { margin-bottom: 14px; }
.admin-main:has([data-imp-viewer]) > .admin-tabs { margin-bottom: 14px; }

/* Les onglets à contenu long (Bibliothèque, File, Timelapse) défilent
   dans leur propre boîte. */
.admin-main:has([data-imp-viewer]) > .admin-tab-panel:not([hidden]) {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}
/* Le Plateau, lui, ne défile pas du tout : il se répartit en hauteur.
   `:not([hidden])` est indispensable : cette règle est plus spécifique que
   `.admin-tab-panel[hidden] { display: none }`, et sans elle son `display:flex`
   gagne — le Plateau restait affiché sous l'onglet réellement sélectionné. */
.admin-main:has([data-imp-viewer]) > .admin-tab-panel[data-tab="plateau"]:not([hidden]) {
  overflow: hidden;
  display: flex;
}
.admin-main:has([data-imp-viewer]) .imp-plate-layout {
  flex: 1;
  min-height: 0;
  align-items: stretch;
}
.admin-main:has([data-imp-viewer]) .imp-plate-stage {
  display: flex;
  flex-direction: column;
  min-height: 0;
}
/* Le visualiseur prend ce qui reste. `aspect-ratio` sauté ici : la hauteur
   vient de la place disponible, plus d'une proportion devinée. */
.admin-main:has([data-imp-viewer]) .imp-plate-viewer {
  flex: 1;
  min-height: 0;
  height: auto;
  aspect-ratio: auto;
}
/* La colonne de droite porte son propre ascenseur : c'est elle qui déborde
   quand une pièce est sélectionnée, pas la page. */
.admin-main:has([data-imp-viewer]) .imp-side {
  overflow-y: auto;
  min-height: 0;
  padding-right: 4px;
}
/* Légende et avertissements restent visibles sous le plateau sans pousser. */
.admin-main:has([data-imp-viewer]) .imp-plate-legend { flex-shrink: 0; }
.admin-main:has([data-imp-viewer]) .imp-plate-warn { flex-shrink: 0; max-height: 22vh; overflow-y: auto; }

/* Sous 900 px la colonne passe sous le plateau : la hauteur de viewport n'a
   plus de sens, on rend le défilement à la page. */
@media (max-width: 900px) {
  .admin-main:has([data-imp-viewer]) {
    height: auto;
    overflow: visible;
  }
  .admin-main:has([data-imp-viewer]) > .admin-tab-panel:not([hidden]) { overflow: visible; }
  .admin-main:has([data-imp-viewer]) .imp-plate-viewer { height: min(52dvh, 460px); flex: none; }
  .admin-main:has([data-imp-viewer]) .imp-side { overflow: visible; }
}

/* ── Statistiques (22/09/2026) ─────────────────────────────────────────── */
.stats-periodes { display: flex; gap: 6px; flex-wrap: wrap; }
.stats-periodes .admin-tab-btn { padding: 8px 14px; border-radius: var(--radius-pill); border: 1.5px solid var(--rule); }
.stats-periodes .admin-tab-btn.is-active { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.stats-kpis { margin-bottom: 18px; }
.stats-kpis .admin-stat-card { cursor: default; }
.stats-kpis .admin-stat-card:hover { transform: none; box-shadow: none; }
.admin-stat-sub.is-up { color: var(--sage); font-weight: 600; }
.admin-stat-sub.is-down { color: var(--danger); font-weight: 600; }
.stats-chart { width: 100%; height: 160px; display: block; margin: 6px 0 18px; }
.stats-chart rect:hover { opacity: 0.75; }
.stats-chart-label { font-size: 11px; fill: var(--ink-faint); font-family: var(--font-body); }
.stats-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; }
@media (max-width: 900px) { .stats-cols { grid-template-columns: minmax(0, 1fr); } }
.stats-h3 { font-family: var(--font-display); font-size: 1.05rem; margin: 18px 0 10px; }
.stats-table { display: table; overflow: visible; box-shadow: none; border: 1px solid var(--rule); }
.stats-table th, .stats-table td { padding: 8px 12px; font-size: 0.9rem; }
.stats-table .num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.stats-note { margin-top: 10px; font-size: 0.85rem; }
.stats-note code, .stats-table code { font-size: 0.85em; }
.stats-funnel { display: grid; gap: 8px; margin: 12px 0; }
.stats-funnel-step { position: relative; min-height: 40px; display: flex; align-items: center; }
.stats-funnel-bar { position: absolute; left: 0; top: 0; bottom: 0; background: var(--sage-soft); border-radius: var(--radius-s); }
.stats-funnel-text { position: relative; padding: 8px 14px; display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap; }
.stats-funnel-text strong { font-family: var(--font-display); font-size: 1.15rem; }
.stats-funnel-rate { color: var(--ink-soft); font-size: 0.85rem; }
.stats-conversion { margin-top: 6px; }
.stats-conversion strong { color: var(--accent-deep); }

/* ═══════════════════════════════════════════════════════════════════════
   Refonte du 23/09/2026 — composants communs
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Tableaux : enveloppe posée par admin.js ─────────────────────────────
   `.admin-table` en `display:block` (18/09/2026) portait son propre
   défilement, mais ses lignes se dimensionnaient alors sur leur CONTENU :
   le tableau des options de la fiche produit s'arrêtait à 611 px dans une
   carte de 720, en-tête gris compris. admin.js enveloppe chaque tableau
   dans `.admin-tablebox`, qui porte la carte et le défilement ; le tableau
   redevient un vrai tableau, pleine largeur. Sans JS, rien ne change.
   Le défilement horizontal n'est armé que si le tableau déborde vraiment
   (`.is-overflowing`) : sans lui l'enveloppe laisse passer le `sticky` des
   en-têtes de colonne, qui restent alors visibles en descendant la liste. */
.admin-tablebox {
  background: var(--surface); border-radius: var(--radius-m); box-shadow: var(--card-shadow);
  margin-bottom: 16px; min-width: 0;
}
.admin-tablebox.is-overflowing { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.admin-tablebox > .admin-table {
  display: table; overflow: visible; box-shadow: none; background: transparent; border-radius: 0; margin: 0;
  -webkit-mask-image: none; mask-image: none;
}
.admin-tablebox:not(.is-overflowing) > .admin-table > thead th { position: sticky; top: var(--sticky-top); z-index: 5; }
.admin-tablebox > .admin-table > thead th:first-child { border-top-left-radius: var(--radius-m); }
.admin-tablebox > .admin-table > thead th:last-child { border-top-right-radius: var(--radius-m); }
.admin-section .admin-tablebox, .admin-card .admin-tablebox { box-shadow: none; border: 1px solid var(--rule); }
.admin-table tr.is-busy td { opacity: 0.45; transition: opacity 0.15s ease; }
.admin-table tr.is-leaving td { opacity: 0; transition: opacity 0.2s ease; }
.admin-table-cell-actions { white-space: nowrap; text-align: right; }
.admin-table-cell-actions > * { display: inline-block; vertical-align: middle; margin: 0; }
.admin-table-cell-actions > * + * { margin-left: 6px; }
.admin-table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Tableaux en cartes sur téléphone : admin.js recopie l'intitulé de chaque
   colonne dans `data-label`, la carte le rappelle devant chaque valeur. La
   première cellule sert de titre. Une colonne sans intitulé (actions) passe
   en pied de carte. `data-no-cards` sur le tableau garde le défilement. */
@media (max-width: 779px) {
  .admin-tablebox.is-cards { background: none; box-shadow: none; border: 0; overflow: visible; }
  .is-cards > .admin-table, .is-cards > .admin-table > tbody { display: block; }
  .is-cards > .admin-table > thead { display: none; }
  .is-cards > .admin-table > tbody > tr {
    display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px;
    background: var(--surface); border-radius: 16px; box-shadow: var(--card-shadow);
    padding: 12px 14px; margin-bottom: 10px; position: relative;
  }
  .is-cards > .admin-table > tbody > tr > td {
    display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
    flex: 1 1 100%; padding: 2px 0; border: 0; white-space: normal; background: none !important;
    font-size: 0.86rem; min-width: 0;
  }
  .is-cards > .admin-table > tbody > tr > td::before {
    content: attr(data-label); flex-shrink: 0;
    font-size: 0.7rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--ink-faint);
  }
  .is-cards > .admin-table > tbody > tr > td[data-label=""]::before,
  .is-cards > .admin-table > tbody > tr > td:first-child::before { display: none; }
  .is-cards > .admin-table > tbody > tr > td:first-child { font-size: 0.95rem; font-weight: 600; padding-bottom: 4px; }
  .is-cards > .admin-table > tbody > tr > td[data-label=""] { justify-content: flex-end; flex: 1 1 100%; border-top: 1px solid var(--rule); padding-top: 8px; margin-top: 4px; }
  .is-cards > .admin-table > tbody > tr > td[colspan] { justify-content: center; }
  .is-cards > .admin-table > tbody > tr > td[colspan]::before { display: none; }
}

/* ── Aide repliée derrière un « ? » ──────────────────────────────────────
   Les longues explications (fiche produit, réglages) faisaient la moitié
   de la hauteur des pages. Elles restent à un survol ou un toucher : la
   bulle est posée par admin.js, en `fixed`, recalée dans l'écran. */
.admin-hint {
  display: inline-grid; place-items: center; vertical-align: middle;
  width: 17px; height: 17px; padding: 0; margin-left: 4px; flex-shrink: 0;
  border: 0; border-radius: 50%; cursor: help;
  background: var(--paper-alt); color: var(--ink-soft);
  font: 700 0.68rem/1 var(--font-body);
  transition: background 0.15s ease, color 0.15s ease;
}
.admin-hint:hover, .admin-hint:focus-visible, .admin-hint[aria-expanded="true"] { background: var(--ink); color: var(--paper); }
.admin-hint-bubble {
  position: fixed; z-index: 1000; max-width: min(340px, calc(100vw - 24px));
  padding: 10px 13px; border-radius: 12px;
  background: var(--ink); color: var(--paper);
  font-size: 0.8rem; font-weight: 400; line-height: 1.45; text-transform: none; letter-spacing: 0;
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.25);
  pointer-events: none; opacity: 0; transform: translateY(4px);
  transition: opacity 0.12s ease, transform 0.12s ease;
}
.admin-hint-bubble.is-visible { opacity: 1; transform: none; }
.admin-hint-bubble strong { color: #fff; }
.admin-hint-bubble a { color: var(--accent); }

/* ── Palette de recherche (Ctrl+K ou /) ─────────────────────────────── */
.admin-palette, .admin-sheet {
  border: 0; padding: 0; margin: 0; background: transparent; color: var(--ink);
  width: 100%; height: 100%; max-width: none; max-height: none; display: none;
}
.admin-palette[open] { display: flex; justify-content: center; align-items: flex-start; padding: 12vh 12px 12px; }
.admin-palette::backdrop, .admin-sheet::backdrop { background: rgba(26, 22, 32, 0.45); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); }
.admin-palette-panel {
  width: min(640px, 100%); background: var(--surface); border-radius: 18px; overflow: hidden;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.3);
  animation: admin-dialog-in 0.16s var(--ease-snap);
}
.admin-palette-field { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--rule); }
.admin-palette-field .admin-icon { color: var(--ink-faint); }
.admin-palette-field input {
  flex: 1; min-width: 0; border: 0; outline: 0; background: none; padding: 4px 0;
  font: 500 1.02rem var(--font-body); color: var(--ink);
}
.admin-palette-field input::-webkit-search-cancel-button { display: none; }
.admin-palette-list { list-style: none; margin: 0; padding: 6px; max-height: min(430px, 56vh); overflow-y: auto; }
.admin-palette-heading { padding: 10px 10px 4px; font-size: 0.66rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); }
.admin-palette-item {
  display: flex; align-items: center; gap: 12px; padding: 8px 10px; border-radius: 11px;
  cursor: pointer; color: var(--ink); text-decoration: none;
}
.admin-palette-item.is-active { background: var(--blush); }
.admin-palette-thumb {
  width: 34px; height: 34px; border-radius: 9px; flex-shrink: 0; object-fit: cover;
  background: var(--paper-alt); display: grid; place-items: center; color: var(--ink-soft);
}
.admin-palette-thumb .admin-icon { width: 16px; height: 16px; }
.admin-palette-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.admin-palette-title { font-weight: 600; font-size: 0.9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.admin-palette-sub { font-size: 0.75rem; color: var(--ink-soft); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.admin-palette-empty { padding: 18px 12px; text-align: center; color: var(--ink-soft); font-size: 0.86rem; }
.admin-palette-help { margin: 0; padding: 8px 16px; border-top: 1px solid var(--rule); font-size: 0.72rem; color: var(--ink-faint); display: flex; gap: 4px; align-items: center; flex-wrap: wrap; }
@media (max-width: 779px) {
  .admin-palette[open] { padding: 8px; }
  .admin-palette-help { display: none; }
  .admin-palette-field kbd { display: none; }
}

/* ── Feuille « Plus » du téléphone ───────────────────────────────────── */
.admin-sheet[open] { display: flex; align-items: flex-end; }
.admin-sheet-panel {
  width: 100%; max-height: 90dvh; overflow-y: auto; overscroll-behavior: contain;
  background: var(--paper); border-radius: 24px 24px 0 0;
  padding: 6px 16px calc(16px + env(safe-area-inset-bottom));
  animation: admin-sheet-in 0.26s var(--ease-snap);
}
@keyframes admin-sheet-in { from { transform: translateY(40px); opacity: 0; } }
.sheet-handle { display: block; width: 40px; height: 5px; border-radius: 3px; background: var(--rule); margin: 6px auto 12px; }
.admin-search-btn-wide {
  width: 100%; margin: 0 0 4px; padding: 11px 14px; font-size: 0.9rem;
  background: var(--surface); border: 1px solid var(--rule); color: var(--ink-soft);
}
.admin-search-btn-wide:hover { background: var(--surface); color: var(--ink); }
.admin-sheet-group { margin: 14px 4px 6px; font-size: 0.66rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-faint); }
.admin-sheet-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.admin-sheet-link {
  display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center;
  padding: 12px 4px 10px; border-radius: 14px; background: var(--surface); box-shadow: var(--card-shadow);
  color: var(--ink); text-decoration: none; font-size: 0.76rem; font-weight: 600; line-height: 1.2;
}
.admin-sheet-link .admin-icon { width: 22px; height: 22px; color: var(--accent-deep); }
.admin-sheet-link.is-active { background: var(--ink); color: var(--paper); }
.admin-sheet-link.is-active .admin-icon { color: var(--accent); }
.admin-sheet-link .admin-nav-count { position: absolute; top: -6px; left: 14px; min-width: 17px; height: 17px; padding: 0 4px; font-size: 0.64rem; }
.admin-sheet-footer { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--rule); display: flex; flex-direction: column; gap: 12px; }
.admin-sheet .admin-mode-switch { margin: 0; }
.admin-sheet .admin-mode-switch-label { color: var(--ink-soft); opacity: 1; }
.admin-sheet .admin-mode-switch-track { background: var(--paper-alt); }
.admin-sheet .admin-mode-switch-opt { color: var(--ink); }
.admin-sheet .admin-user { color: var(--ink-soft); opacity: 1; font-size: 0.82rem; }
body.admin-sheet-open { overflow: hidden; }

/* ── Actions sans rechargement (data-async) ──────────────────────────── */
form.is-busy button, button.is-busy { cursor: progress; }
.is-busy .admin-icon-btn, .admin-icon-btn.is-busy { opacity: 0.5; }
.admin-flash-inline { display: none; }

/* Squelette de chargement (contenu tiré après l'affichage de la page). */
.admin-skeleton {
  display: block; height: 0.9em; border-radius: 6px;
  background: linear-gradient(90deg, var(--paper-alt) 25%, var(--paper) 50%, var(--paper-alt) 75%);
  background-size: 200% 100%; animation: admin-shimmer 1.2s linear infinite;
}
@keyframes admin-shimmer { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .admin-skeleton { animation: none; } }

/* Toasts : ceux qui portent une erreur restent plus longtemps et se
   ferment d'un clic ; ils remplacent les bandeaux `?notice=` qui
   poussaient toute la page vers le bas. */
.admin-toast { display: flex; align-items: flex-start; gap: 10px; }
.admin-toast::after { content: "×"; margin-left: auto; opacity: 0.6; font-size: 1.1em; line-height: 1; }
.admin-toast.is-warn { background: var(--ink); color: var(--paper); }
@media (max-width: 779px) {
  .admin-toasts { bottom: calc(var(--tabbar-h) + 14px + env(safe-area-inset-bottom)); }
}

/* Carte-bloc sans liseré (grilles denses). */
.admin-panel {
  background: var(--surface); border-radius: var(--radius-m); box-shadow: var(--card-shadow);
  padding: 14px 16px; min-width: 0;
}
.admin-panel-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.admin-panel-head .admin-h2 { margin: 0; font-size: 1rem; }
.admin-panel-head a { font-size: 0.8rem; font-weight: 600; color: var(--accent-deep); text-decoration: none; white-space: nowrap; }
.admin-empty-state { text-align: center; color: var(--ink-soft); padding: 28px 16px; font-size: 0.9rem; }
.admin-empty-state strong { display: block; color: var(--ink); font-family: var(--font-display); font-size: 1.05rem; margin-bottom: 4px; }

/* La page Impression garde sa propre mise en page plein écran (21/09) :
   son en-tête n'a pas à coller, rien ne défile sous lui. */
.admin-main:has([data-imp-viewer]) > .admin-page-header {
  position: static; margin: 0 0 12px; padding: 0; background: none;
  -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: none;
}

/* ── Tableau de bord « cockpit » (23/09/2026) ───────────────────────────── */
.dash-title {
  display: flex; align-items: baseline; gap: 10px; margin: 0 0 8px;
  font-family: var(--font-display); font-size: 0.95rem; font-weight: 600; color: var(--ink-soft);
}
.dash-allgood { font-family: var(--font-body); font-size: 0.8rem; font-weight: 600; color: #4f6b5e; }
.dash-todo { margin-bottom: 16px; }
.dash-todo-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr)); gap: 10px; }
.dash-tile {
  display: flex; align-items: center; gap: 12px; min-width: 0;
  padding: 12px 14px; border-radius: var(--radius-m);
  background: var(--surface); box-shadow: var(--card-shadow);
  color: var(--ink); text-decoration: none;
  transition: transform 0.15s var(--ease-snap), box-shadow 0.15s ease;
}
.dash-tile:hover { transform: translateY(-2px); box-shadow: 0 12px 26px var(--shadow-strong); }
.dash-tile-n {
  display: grid; place-items: center; flex-shrink: 0;
  min-width: 42px; height: 42px; padding: 0 8px; border-radius: 13px;
  font-family: var(--font-display); font-size: 1.3rem; font-weight: 700; font-variant-numeric: tabular-nums;
  background: var(--accent); color: #fff;
}
.dash-tile.is-clear .dash-tile-n { background: var(--sage-soft); color: #4f6b5e; font-size: 1rem; }
.dash-tile.is-clear { box-shadow: none; background: color-mix(in srgb, var(--surface) 60%, transparent); }
.dash-tile-txt { display: flex; flex-direction: column; min-width: 0; }
.dash-tile-label { font-weight: 600; font-size: 0.88rem; line-height: 1.25; }
.dash-tile.is-clear .dash-tile-label { color: var(--ink-soft); }
.dash-tile-sub { font-size: 0.74rem; color: var(--ink-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.dash-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 16px; }
.dash-kpi { display: flex; flex-direction: column; }
.dash-kpi .admin-panel-head { margin-bottom: 4px; }
.dash-kpi .admin-h2 { font-size: 0.86rem; color: var(--ink-soft); }
.dash-kpi-row { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.dash-kpi-value { font-family: var(--font-display); font-size: 1.75rem; font-weight: 700; line-height: 1.15; font-variant-numeric: tabular-nums; }
.dash-kpi-unit { font-size: 0.8rem; color: var(--ink-soft); }
.dash-kpi-sub { margin: 2px 0 0; font-size: 0.8rem; color: var(--ink-soft); }
.dash-kpi-sub a { color: var(--accent-deep); font-weight: 600; text-decoration: none; }
.dash-kpi-foot { margin: auto 0 0; padding-top: 6px; font-size: 0.7rem; color: var(--ink-faint); }
.dash-delta { font-size: 0.78rem; font-weight: 700; padding: 1px 7px; border-radius: 999px; }
.dash-delta.is-up { background: var(--sage-soft); color: #4f6b5e; }
.dash-delta.is-down { background: var(--danger-soft); color: var(--danger); }
.dash-spark { display: block; width: 100%; height: 44px; margin-top: 8px; }
.dash-spark-area { fill: rgba(236, 143, 102, 0.16); }
.dash-spark-line { fill: none; stroke: var(--accent); stroke-width: 2; vector-effect: non-scaling-stroke; stroke-linejoin: round; }
.dash-meter { height: 7px; border-radius: 999px; background: var(--paper-alt); overflow: hidden; margin: 10px 0 6px; }
.dash-meter > span { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--accent), var(--sage)); transition: width 0.4s var(--ease-snap); }
.dash-printer-state { margin: 2px 0 0; font-family: var(--font-display); font-size: 1.2rem; font-weight: 600; }
.dash-printer-state.is-busy { color: var(--accent-deep); }
.dash-printer-state.is-off { color: var(--ink-faint); }
.dash-spools { display: flex; gap: 6px; margin-top: 10px; }
.dash-spool { width: 20px; height: 20px; border-radius: 50%; box-shadow: inset 0 0 0 1px rgba(43, 39, 51, 0.22); background: var(--paper-alt); }
.dash-spool.is-empty { background: repeating-linear-gradient(45deg, var(--paper-alt) 0 3px, var(--rule) 3px 6px); }

.dash-orders .admin-panel-head .admin-h2 { display: flex; align-items: center; gap: 8px; }
.dash-order-list { list-style: none; margin: 0; padding: 0; }
.dash-order {
  display: grid; grid-template-columns: 52px minmax(0, 1fr) 80px 130px 90px 50px; align-items: center; gap: 12px;
  padding: 8px 10px; border-radius: 11px; color: var(--ink); text-decoration: none; font-size: 0.86rem;
}
.dash-order:hover { background: var(--paper); }
.dash-order.is-todo { background: #fff7e7; box-shadow: inset 3px 0 #e49b22; }
.dash-order-id { font-weight: 700; color: var(--accent-deep); }
.dash-order-name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dash-order-mode, .dash-order-date { color: var(--ink-soft); font-size: 0.8rem; }
.dash-order-total { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }
.dash-order-date { text-align: right; }
.dash-order-list li + li { border-top: 1px solid var(--rule); }
.admin-badge-warnsoft { background: #ffecc8; color: #8b5a13; }

@media (max-width: 1199px) {
  .dash-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 779px) {
  .dash-todo-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .dash-tile { padding: 10px; gap: 10px; }
  .dash-tile-n { min-width: 36px; height: 36px; font-size: 1.1rem; }
  .dash-tile-sub { display: none; }
  .dash-grid { gap: 8px; }
  .dash-kpi-value { font-size: 1.4rem; }
  .dash-order { grid-template-columns: 44px minmax(0, 1fr) auto; grid-template-areas: "id nom total" "id statut date"; row-gap: 2px; }
  .dash-order-id { grid-area: id; } .dash-order-name { grid-area: nom; } .dash-order-total { grid-area: total; }
  .dash-order .admin-badge { grid-area: statut; justify-self: start; } .dash-order-date { grid-area: date; }
  .dash-order-mode { display: none; }
  .admin-page-header .admin-page-sub { display: none; }
}

/* ── Utilitaires (23/09/2026) ───────────────────────────────────────────── */
.admin-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.admin-show-sm { display: none; }
@media (max-width: 779px) {
  .admin-hide-sm { display: none; }
  .admin-show-sm { display: inline; }
}
.admin-badge-sm { padding: 1px 8px; font-size: 0.68rem; }
[data-filter-text][hidden], [data-filter-empty][hidden], [data-tab-panel][hidden] { display: none !important; }
.admin-tab-icon { position: relative; display: inline-flex; }

/* Interrupteur autonome (formulaire d'une seule action, envoyé sans
   rechargement) : la pastille est le bouton lui-même. */
.admin-toggle-form { margin: 0; display: inline-flex; }
.admin-toggle {
  position: relative; width: 38px; height: 22px; flex-shrink: 0;
  border: 0; border-radius: 999px; padding: 0; cursor: pointer;
  background: var(--rule); transition: background 0.18s ease;
}
.admin-toggle > span {
  position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  transition: transform 0.18s var(--ease-snap);
}
.admin-toggle.is-on { background: var(--sage); }
.admin-toggle.is-on > span { transform: translateX(16px); }
.admin-toggle:hover { filter: brightness(0.95); }
.is-busy .admin-toggle { cursor: progress; }
.is-busy .admin-toggle > span { animation: admin-toggle-busy 0.8s ease-in-out infinite alternate; }
@keyframes admin-toggle-busy { to { opacity: 0.4; } }

/* ── Liste des produits (23/09/2026) ────────────────────────────────────── */
.admin-table-products td { padding-top: 7px; padding-bottom: 7px; }
.admin-table-products tbody tr[data-href] { cursor: pointer; }
.admin-table-products .p-col-art { width: 60px; padding-right: 0; }
.p-thumb {
  display: block; width: 44px; height: 44px; border-radius: 12px; overflow: hidden;
  background: var(--paper-alt) center / 18px no-repeat
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a39bb0' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 8 12 3 3 8v8l9 5 9-5z'/%3E%3Cpath d='m3 8 9 5 9-5M12 13v8'/%3E%3C/svg%3E");
}
.p-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.p-col-title { max-width: 0; width: 55%; }
.p-title {
  display: block; color: var(--ink) !important; font-weight: 600 !important; font-size: 0.9rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.admin-table-products tr:hover .p-title { color: var(--accent-deep) !important; }
.p-sub { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; font-size: 0.76rem; color: var(--ink-soft); margin-top: 1px; }
.p-sub .admin-badge { text-decoration: none; }
.admin-table-products tr.is-inactive .p-thumb img { opacity: 0.5; filter: saturate(0.4); }
.admin-table-products tr.is-inactive .p-title { color: var(--ink-soft) !important; }
.admin-table-etsy { display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.admin-gallery-actions { align-items: center; }

@media (max-width: 779px) {
  /* Téléphone : chaque produit sur une ligne compacte — vignette, titre et
     prix, interrupteur à droite ; Etsy et suppression passent dessous. */
  .admin-table-products, .admin-table-products tbody { display: block; }
  .admin-tablebox:has(> .admin-table-products) { background: none; box-shadow: none; overflow: visible; }
  .admin-table-products thead { display: none; }
  .admin-table-products tbody tr {
    display: grid; grid-template-columns: 48px minmax(0, 1fr) auto; grid-template-areas: "art titre prix" "art etsy toggle";
    align-items: center; column-gap: 10px; row-gap: 4px;
    background: var(--surface); border-radius: 16px; box-shadow: var(--card-shadow); padding: 10px 12px; margin-bottom: 8px;
  }
  .admin-table-products tbody td { border: 0; padding: 0 !important; white-space: normal; background: none !important; }
  .admin-table-products td.p-col-art { grid-area: art; width: auto; }
  .admin-table-products td.p-col-title { grid-area: titre; max-width: none; width: auto; min-width: 0; }
  .admin-table-products td.admin-table-price { grid-area: prix; }
  .admin-table-products td:nth-child(4) { grid-area: toggle; justify-self: end; }
  .admin-table-products td:nth-child(5) { grid-area: etsy; min-width: 0; }
  .admin-table-products td.admin-table-cell-actions { display: none; }
  .admin-table-products .p-sub { display: none; }
  .admin-table-products tr[data-filter-empty] { display: block; }
  .admin-main .admin-search input { width: 100%; }
  .admin-toolbar .admin-search { flex: 1 1 100%; }
}
/* `overflow: clip` après `hidden` (23/09/2026) : les cartes rognent leurs
   coins arrondis, mais `hidden` en faisait des boîtes de défilement — et un
   en-tête de colonne `sticky` à l'intérieur se calait alors sur la carte au
   lieu de l'écran : il descendait de 70 px et recouvrait la première ligne
   (tableau des options de la fiche produit, vu en capture mobile). `clip`
   rogne pareil sans créer de boîte de défilement. */
.admin-form { overflow: clip; }

/* Le champ de recherche est un <label> : la colonne générique des libellés
   posait la loupe AU-DESSUS du texte. */
.admin-main .admin-search { flex-direction: row; align-items: center; gap: 0; }
.admin-main .admin-search input[type=search] { padding-left: 32px; }

/* Galerie plus dense (23/09/2026) : vignette 4/3 et colonnes de 190 px —
   deux rangées tiennent désormais sur un portable, et deux colonnes sur un
   téléphone au lieu d'une. L'image sort du flux, sinon sa hauteur naturelle
   bat `aspect-ratio` (piège du 21/09). */
.admin-gallery { grid-template-columns: repeat(auto-fill, minmax(min(190px, 100%), 1fr)); gap: 12px; }
.admin-gallery-card { box-shadow: var(--card-shadow); }
.admin-gallery-art { position: relative; aspect-ratio: 4 / 3; }
.admin-gallery-art img { position: absolute; inset: 0; }
.admin-gallery-body { gap: 6px; padding: 10px 12px 12px; }
.admin-gallery-title { font-size: 0.86rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.admin-gallery-actions { padding-top: 8px; gap: 6px; }
@media (max-width: 779px) {
  .admin-gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .admin-gallery-body { padding: 8px 10px 10px; }
  .admin-gallery-meta .admin-badge { display: none; }
}

/* ── Fiche produit : onglets + résumé fixe (23/09/2026) ─────────────────── */
.admin-icon-back {
  display: grid; place-items: center; width: 34px; height: 34px; flex-shrink: 0;
  border-radius: 11px; background: var(--surface); box-shadow: var(--card-shadow); color: var(--ink-soft);
  transition: background 0.15s ease, color 0.15s ease;
}
.admin-icon-back:hover { background: var(--ink); color: var(--paper); }
.admin-icon-back svg { width: 15px; height: 15px; }
.pf-header .admin-page-title { flex-wrap: nowrap; min-width: 0; flex: 1; }
.pf-h1 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
/* L'indicateur d'enregistrement automatique vit dans l'en-tête collé. */
#autosaveStatus { margin: 0; padding: 5px 12px; border-radius: 999px; font-size: 0.8rem; font-weight: 600; white-space: nowrap; }
#autosaveStatus.admin-flash-warn { background: var(--paper-alt); color: var(--ink-soft); }
#autosaveStatus.admin-flash-ok::before { content: "✓ "; }
.pf-ainote { margin: 0 0 12px; }

.pf-tabs {
  position: sticky; top: var(--sticky-top); z-index: 25;
  display: flex; gap: 2px; width: fit-content; max-width: 100%;
  margin: 0 0 14px; padding: 3px; border-radius: 13px;
  background: var(--paper-alt); overflow-x: auto; scrollbar-width: none;
  box-shadow: 0 0 0 6px var(--paper);
}
.pf-tabs::-webkit-scrollbar { display: none; }
.pf-tab {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  padding: 7px 14px; border: 0; border-radius: 10px; cursor: pointer;
  background: none; color: var(--ink-soft); font: 600 0.86rem var(--font-body);
  transition: background 0.15s ease, color 0.15s ease;
}
.pf-tab:hover { color: var(--ink); }
.pf-tab.is-active { background: var(--surface); color: var(--ink); box-shadow: 0 1px 3px var(--shadow-strong); }
.pf-tab-count {
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  display: inline-grid; place-items: center; font-size: 0.7rem; font-weight: 700;
  background: var(--paper); color: var(--ink-soft);
}
.pf-tab.is-active .pf-tab-count { background: var(--paper-alt); }
.pf-tab-count.is-warn { background: var(--danger-soft); color: var(--danger); }
.pf-tab-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent-deep); }

.pf-grid { display: grid; grid-template-columns: minmax(0, 1fr) 280px; gap: 16px; align-items: start; }
.pf-main { min-width: 0; container-type: inline-size; }
.pf-main .admin-section { margin-bottom: 14px; }
.pf-side {
  position: sticky; top: calc(var(--sticky-top) + 58px);
  display: flex; flex-direction: column; gap: 12px; min-width: 0;
}
.pf-card { background: var(--surface); border-radius: var(--radius-m); box-shadow: var(--card-shadow); padding: 12px; display: flex; flex-direction: column; gap: 10px; }
.pf-cover {
  position: relative; aspect-ratio: 2 / 1; border-radius: 12px; overflow: hidden;
  background: var(--paper-alt); display: grid; place-items: center;
  color: var(--ink-faint); font-size: 0.8rem; font-weight: 600;
}
.pf-cover img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.pf-price { font-size: 0.78rem; }
.pf-price .product-price-input input { font-family: var(--font-display); font-size: 1.3rem; font-weight: 700; padding: 6px 10px; }
.pf-margin:empty { display: none; }
.pf-margin-link {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 12px;
  text-decoration: none; color: var(--ink);
}
.pf-margin-link.is-ok { background: var(--sage-soft); }
.pf-margin-link.is-ko { background: var(--danger-soft); }
.pf-margin-link.is-none { background: var(--paper); color: var(--ink-soft); font-size: 0.8rem; }
.pf-margin-value { font-family: var(--font-display); font-size: 1.25rem; font-weight: 700; white-space: nowrap; }
.pf-margin-link.is-ok .pf-margin-value { color: #4f6b5e; }
.pf-margin-link.is-ko .pf-margin-value { color: var(--danger); }
.pf-margin-txt { font-size: 0.74rem; line-height: 1.35; color: var(--ink-soft); }
.pf-status { gap: 12px; }
.pf-status .admin-switch-label { font-size: 0.86rem; }
.pf-seg { display: flex; align-items: center; gap: 2px; padding: 3px; border-radius: 11px; background: var(--paper-alt); }
.pf-seg label { flex: 1; display: block !important; margin: 0; cursor: pointer; }
.pf-seg input { position: absolute; opacity: 0; pointer-events: none; }
.pf-seg label span {
  display: block; text-align: center; padding: 5px 8px; border-radius: 8px;
  font-size: 0.8rem; font-weight: 600; color: var(--ink-soft);
}
.pf-seg input:checked + span { background: var(--surface); color: var(--ink); box-shadow: 0 1px 3px var(--shadow-strong); }
.pf-seg input:focus-visible + span { outline: 2px solid var(--accent); }
.pf-seg .admin-hint { margin: 0 4px; }
.pf-mto { font-size: 0.84rem !important; gap: 8px !important; color: var(--ink) !important; }

.pf-fields { display: grid; gap: 12px 14px; }
.pf-fields-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.pf-fields-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.pf-span-2 { grid-column: span 2; }
.pf-fields label > span:first-child { display: inline-flex; align-items: center; gap: 2px; }
.pf-fields .admin-check { gap: 8px; font-weight: 500; color: var(--ink); font-size: 0.86rem; }
.pf-input-xs { max-width: 120px; }
.pf-inline-label { justify-self: start; }
.pf-help { margin: 4px 0 0; font-size: 0.76rem; font-weight: 400; color: var(--ink-soft); line-height: 1.45; }
.pf-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 14px; align-items: start; }
.pf-cols-cost { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
@container (max-width: 620px) {
  .pf-cols, .pf-cols-cost { grid-template-columns: minmax(0, 1fr); }
  .pf-fields-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.pf-inline-section { display: flex; align-items: center; gap: 8px; }
.pf-swatch-row { display: inline-flex; align-items: center; gap: 8px; }
.pf-add-option {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin-top: 12px; padding: 10px; border-radius: 12px; background: var(--paper);
}
.pf-add-option-title { font-size: 0.78rem; font-weight: 700; color: var(--ink-soft); margin-right: 4px; }
.admin-main .pf-add-option select, .admin-main .pf-add-option input[type=text] { width: auto; flex: 1 1 140px; min-width: 0; }
.pf-delta { flex-direction: row !important; align-items: center; gap: 4px !important; flex: 0 0 auto; }
.admin-main .pf-delta input { width: 80px; }
.pf-slice { margin-top: 12px; }
.pf-model-dims { margin-left: 8px; font-family: var(--font-body); font-size: 0.8rem; font-weight: 600; color: var(--ink-soft); }
.pf-model-actions { display: flex; align-items: center; gap: 12px; margin: 0 0 10px; }
.product-model-viewer { height: 240px; }
.product-dropzone.is-compact { flex-direction: row; padding: 10px 14px; margin-top: 12px; text-align: left; }
.product-dropzone.is-compact p span { display: inline; }
.product-dropzone.is-compact p br { display: none; }
.product-dropzone.is-compact svg { width: 20px; height: 20px; }
.product-photo-grid { margin-top: 0; }
/* Modèle 3D et zone de texte réunis (28/09/2026) : un seul aperçu, un peu plus
   haut que l ancienne visionneuse pour viser la zone, puis la barre de zone. */
#productZonePicker { height: 300px; }
.pf-zone-bar { display: flex; flex-direction: column; gap: 6px; margin: 0 0 4px; padding: 10px 12px; border-radius: 12px; background: var(--paper); }
.pf-zone-title { display: flex; align-items: center; gap: 6px; margin: 0; font-size: 0.84rem; font-weight: 700; color: var(--ink); }
.pf-zone-bar p.admin-muted { margin: 0; font-size: 0.8rem; }
.pf-zone-buttons { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; }
.pf-zone-buttons .admin-muted { font-size: 0.8rem; }
.pf-taxo-filter { margin-bottom: 6px; }
.pf-suggest-line { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 6px; font-size: 0.78rem; font-weight: 400; color: var(--ink-soft); }
.pf-dims { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.admin-cost-table { width: 100%; border-collapse: collapse; font-size: 0.84rem; }
.admin-cost-table td { padding: 6px 0; border-bottom: 1px solid var(--rule); vertical-align: top; }
.admin-cost-table td:last-child { text-align: right; white-space: nowrap; padding-left: 12px; font-variant-numeric: tabular-nums; }
.admin-cost-table tr.is-total td { font-weight: 700; border-bottom: 0; }
.admin-cost-table tr.is-total + tr.is-total td { padding-top: 0; }
.pf-cost-note { display: block; font-size: 0.74rem; color: var(--ink-soft); line-height: 1.4; }
.pf-verdict { margin: 10px 0; padding: 8px 12px; border-radius: 10px; font-size: 0.84rem; font-weight: 600; }
.pf-verdict.is-ok { background: var(--sage-soft); color: #4f6b5e; }
.pf-verdict.is-ko { background: var(--danger-soft); color: var(--danger); }
.pf-suggest { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin: 0 0 10px; font-size: 0.84rem; }

@media (max-width: 1440px) {
  .pf-grid { grid-template-columns: minmax(0, 1fr) 260px; }
}
@media (max-width: 1199px) {
  .pf-grid { grid-template-columns: minmax(0, 1fr) 240px; }
}
@media (max-width: 779px) {
  .pf-grid { grid-template-columns: minmax(0, 1fr); }
  /* Téléphone : le prix et la marge restent en tête de chaque onglet, le
     statut (en ligne, catalogue, sur mesure) descend sous le contenu — il
     repoussait sinon chaque onglet de 150 px. */
  .pf-side { display: contents; }
  .pf-side > .pf-card:first-child { order: -1; margin-bottom: 12px; }
  .pf-side > .pf-status { order: 1; }
  .pf-card:first-child { display: grid; grid-template-columns: 64px minmax(0, 1fr); grid-template-areas: "cover price" "marge marge"; gap: 8px 12px; }
  .pf-cover { grid-area: cover; aspect-ratio: 1; }
  .pf-cover span { display: none; }
  .pf-price { grid-area: price; }
  .pf-margin { grid-area: marge; }
  .pf-tabs { width: auto; margin-left: calc(-1 * var(--gutter)); margin-right: calc(-1 * var(--gutter)); border-radius: 0; padding: 4px var(--gutter); box-shadow: none; background: var(--paper); }
  .pf-tab { background: var(--paper-alt); }
  .pf-tab.is-active { background: var(--ink); color: var(--paper); }
  .pf-description textarea { min-height: 160px; }
  .pf-fields-2, .pf-fields-3, .pf-dims { grid-template-columns: minmax(0, 1fr); }
  .pf-span-2 { grid-column: auto; }
  .pf-h1 { font-size: 1.1rem; }
}

/* ── Contrôle qualité (23/09/2026) ──────────────────────────────────────── */
.admin-filter-bar a .admin-nav-count { min-width: 17px; height: 17px; font-size: 0.64rem; margin-left: 3px; vertical-align: 1px; }
.qc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(330px, 100%), 1fr)); gap: 12px; }
.qc-card {
  display: flex; flex-direction: column; gap: 10px; min-width: 0;
  background: var(--surface); border-radius: var(--radius-m); box-shadow: var(--card-shadow); padding: 12px;
  transition: opacity 0.2s ease;
}
.qc-card.is-busy { opacity: 0.55; }
.qc-card.is-leaving { opacity: 0; transform: scale(0.98); transition: opacity 0.2s ease, transform 0.2s ease; }
.qc-card.qc-en_attente_controle { box-shadow: var(--card-shadow), inset 3px 0 var(--accent); }
.qc-media { display: flex; gap: 8px; }
.qc-photo, .qc-stl { width: 50%; aspect-ratio: 1; border-radius: 12px; overflow: hidden; background: #f2ede6; display: block; position: relative; }
.qc-media:not(:has(.qc-photo)) .qc-stl { width: 100%; aspect-ratio: 2 / 1; }
.qc-photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.qc-body { min-width: 0; }
.qc-title { margin: 0; font-weight: 600; font-size: 0.9rem; line-height: 1.3; }
.qc-meta { margin: 3px 0 0; font-size: 0.78rem; color: var(--ink-soft); line-height: 1.45; }
.qc-meta a { color: var(--accent-deep); font-weight: 600; text-decoration: none; }
.qc-order { background: #fff7e7; padding: 0 6px; border-radius: 6px; }
.qc-preview-tag { color: var(--ink-faint); }
.qc-verdict { margin: 6px 0 0; padding: 5px 9px; border-radius: 8px; font-size: 0.78rem; font-weight: 600; }
.qc-verdict span { font-weight: 400; opacity: 0.8; }
.qc-verdict.is-ok { background: var(--sage-soft); color: #4f6b5e; }
.qc-verdict.is-ko { background: var(--danger-soft); color: var(--danger); }
.qc-actions { display: flex; gap: 8px; align-items: center; margin-top: auto; padding-top: 10px; border-top: 1px solid var(--rule); }
.qc-actions form { margin: 0; }
.qc-refuse { display: flex; gap: 6px; flex: 1; min-width: 0; }
.admin-main .qc-refuse input { flex: 1; min-width: 0; padding: 5px 10px; min-height: 32px; font-size: 0.82rem; }
.qc-refuse-btn { border-color: var(--danger); color: var(--danger); }
.qc-refuse-btn:hover { background: var(--danger); color: #fff; }
.qc-empty { grid-column: 1 / -1; background: var(--surface); border-radius: var(--radius-m); box-shadow: var(--card-shadow); }
.qc-empty a { color: var(--accent-deep); font-weight: 600; }
@media (max-width: 779px) {
  .admin-toolbar .admin-filter-bar { max-width: 100%; }
  .admin-toolbar .admin-toolbar-spacer { display: none; }
}

/* ── Onglets de page (Réglages, Impression, Marque — 23/09/2026) ────────
   Même contrôle segmenté que les filtres : l'ancien soulignement sur toute
   la largeur coûtait une ligne entière pour quatre mots. */
.admin-tabs {
  display: inline-flex; gap: 2px; padding: 3px; margin: 0 0 14px; border: 0;
  border-radius: 12px; background: var(--paper-alt); max-width: 100%; overflow-x: auto; scrollbar-width: none;
}
.admin-page-header .admin-tabs { margin: 0; }
.admin-tab-btn {
  padding: 6px 14px; border: 0; margin: 0; border-radius: 9px; white-space: nowrap;
  font: 600 0.84rem var(--font-body); color: var(--ink-soft); background: none; cursor: pointer; text-decoration: none;
}
.admin-tab-btn:hover { color: var(--ink); }
.admin-tab-btn.is-active { background: var(--surface); color: var(--ink); box-shadow: 0 1px 3px var(--shadow-strong); border: 0; }

/* ── Réglages (23/09/2026) ─────────────────────────────────────────────── */
.set-note { margin: 0 0 12px; font-size: 0.82rem; color: var(--ink-soft); }
.set-note form { display: inline; }
.set-actions { display: flex; justify-content: flex-end; gap: 8px; }
.set-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 16px; align-items: start; }
.set-cols-etsy { grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); }
.set-inline-form { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.set-seg { min-width: 180px; }
.set-mode { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.set-mode .admin-h2 { margin-bottom: 4px; }
.set-mode p { margin: 0; font-size: 0.86rem; color: var(--ink-soft); }
.set-mode.is-live::before { background: linear-gradient(90deg, #e0554a, var(--accent)); }
.set-mode-form { display: flex; align-items: center; gap: 10px; }
.set-accounts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.set-account {
  background: var(--surface); border-radius: var(--radius-m); box-shadow: var(--card-shadow);
  padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; min-width: 0;
  border-top: 3px solid var(--sage);
}
.set-account.is-live { border-top-color: #e0554a; }
.set-account-head { display: flex; align-items: center; gap: 8px; }
.set-account-logo { font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; }
.set-env { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; padding: 2px 8px; border-radius: 999px; background: var(--sage-soft); color: #4f6b5e; }
.set-env.is-live { background: #fde3e0; color: #b8392f; }
.set-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.set-chip { font-size: 0.74rem; font-weight: 600; padding: 3px 9px; border-radius: 999px; }
.set-chip.is-ok { background: var(--sage-soft); color: #4f6b5e; }
.set-chip.is-missing { background: var(--paper-alt); color: var(--ink-faint); }
.set-account-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.set-account-actions form { margin: 0; }
.set-creds { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; align-items: end; padding: 10px; border-radius: 12px; background: var(--paper); margin-top: 8px; }
.set-creds[hidden] { display: none; }
.set-creds .admin-btn { grid-column: 1 / -1; justify-self: end; }
.admin-section .set-creds { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.set-test-mail { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--rule); }
.admin-main .set-test-mail input { flex: 1; min-width: 180px; width: auto; }
@media (max-width: 1100px) {
  .set-accounts, .set-cols, .set-cols-etsy { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 779px) {
  .set-creds { grid-template-columns: minmax(0, 1fr); }
  .admin-page-header .admin-tabs { width: 100%; }
}

/* ── Statistiques (refonte du 23/09/2026) ─────────────────────────────── */
.stats-kpis-row { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 8px; margin-bottom: 14px; }
.stats-kpi {
  display: flex; flex-direction: column; gap: 1px; min-width: 0;
  background: var(--surface); border-radius: 14px; box-shadow: var(--card-shadow); padding: 10px 12px;
}
.stats-kpi-value { font-family: var(--font-display); font-size: 1.3rem; font-weight: 700; color: var(--accent-deep); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }
.stats-kpi-label { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 0.78rem; font-weight: 600; color: var(--ink); }
.stats-kpi-label .dash-delta { font-size: 0.68rem; padding: 0 6px; }
.stats-kpi-sub { font-size: 0.7rem; color: var(--ink-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stats-chart-card .stats-chart { margin: 0; height: 150px; }
.stats-inline-sub { font-family: var(--font-body); font-size: 0.76rem; font-weight: 500; color: var(--ink-soft); margin-left: 8px; }
.stats-cols { gap: 0 14px; }
.stats-scroll { max-height: 300px; overflow-y: auto; border-radius: var(--radius-s); border: 1px solid var(--rule); }
.stats-scroll .admin-tablebox { border: 0 !important; margin: 0; }
.stats-scroll .admin-tablebox > .admin-table > thead th { position: sticky; top: 0; }
.stats-table { border: 0; }
.stats-exclusions { max-width: 720px; }
@media (max-width: 1440px) {
  .stats-kpi { padding: 8px 10px; }
  .stats-kpi-value { font-size: 1.12rem; }
  .stats-kpi-label { font-size: 0.72rem; }
  .stats-chart-card .stats-chart { height: 120px; }
}
@media (max-width: 1023px) { .stats-kpis-row { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 779px) {
  .stats-kpis-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .stats-kpi-value { font-size: 1.15rem; }
}

/* ── Marque (23/09/2026) : identité en grille dense, feuille de route plus
   serrée. Les logos « larges » n'occupent plus toute une ligne chacun. */
.brand-grid { grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr)); gap: 12px; }
.brand-item { padding: 12px; gap: 6px; box-shadow: var(--card-shadow); }
.brand-item.brand-wide { grid-column: span 2; }
.brand-preview { min-height: 88px; padding: 12px; }
.brand-preview img { max-height: 60px; }
.brand-item h3 { font-size: 0.9rem; }
.brand-item p { margin: 0; font-size: 0.78rem; line-height: 1.4; }
.brand-item-downloads a { padding: 4px 12px; font-size: 0.78rem; }
.brand-todo { padding: 14px 0; gap: 16px; }
.brand-todo.is-busy { opacity: 0.6; }
.brand-page-flash { display: none; }
@media (max-width: 779px) {
  .brand-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .brand-item.brand-wide { grid-column: 1 / -1; }
}

/* ── Commandes (23/09/2026) ─────────────────────────────────────────────── */
.admin-table-orders tbody tr[data-href] { cursor: pointer; }
.admin-table-orders .o-id { font-family: var(--font-display); font-size: 0.95rem; }
.o-grid { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 0 16px; align-items: start; }
.o-side { position: sticky; top: calc(var(--sticky-top) + 4px); }
.o-side .admin-section { margin-bottom: 12px; }
.o-line { margin: 0 0 6px; font-size: 0.88rem; line-height: 1.5; }
.o-line a { color: var(--accent-deep); text-decoration: none; font-weight: 600; }
.o-totals { display: flex; justify-content: flex-end; align-items: baseline; gap: 16px; flex-wrap: wrap; margin-top: 10px; font-size: 0.86rem; color: var(--ink-soft); }
.o-totals strong { font-family: var(--font-display); font-size: 1.15rem; color: var(--ink); }
.o-status-form { display: flex; align-items: flex-end; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.o-status-form label { flex: 1; min-width: 140px; }
@media (max-width: 1100px) {
  .o-grid { grid-template-columns: minmax(0, 1fr); }
  .o-side { position: static; order: -1; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); gap: 0 12px; }
}

/* ── Impression sur téléphone (23/09/2026) : les marges de la mise en page
   plein écran (24/30 px) écrasaient celles du téléphone, et la bibliothèque
   n'affichait qu'une carte par ligne — 12 écrans de défilement. */
.admin-tabs { flex-wrap: nowrap; }
@media (max-width: 779px) {
  .admin-main:has([data-imp-viewer]) {
    padding: 12px var(--gutter) calc(var(--tabbar-h) + 24px + env(safe-area-inset-bottom));
  }
  .imp-library { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .imp-lib-body { padding: 8px 10px 10px; gap: 3px; }
  .imp-lib-title { font-size: 0.82rem; }
  .imp-lib-meta, .imp-lib-dims { font-size: 0.7rem; }
  button.imp-lib-place { padding: 6px 8px; font-size: 0.76rem; }
  .imp-intro { font-size: 0.8rem; margin-bottom: 10px; }
  .imp-tl-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
}
/* L'icône de remplacement ne sert qu'aux produits sans photo : sous une
   vignette pâlie (produit désactivé), elle transparaissait à travers. */
.p-thumb:has(img) { background-image: none; }
.admin-main:has([data-imp-viewer]) > .admin-tabs { align-self: flex-start; }

/* ─── Notes de revue produit (29/09/2026) ──────────────────────────────
   Onglet « Notes » de la fiche (views/admin/products/_notes.php) et
   pastille de la liste des produits. Liseré gauche = statut : orange à
   traiter, ambre question de Claude, sauge traitée. */
.pf-tab-count[hidden] { display: none; }
.pf-tab-count.is-question { background: #ffecc8; color: #8b5a13; }
.pf-notes-intro { margin: -4px 0 12px; }
.pf-notes-count {
  display: inline-grid; place-items: center; min-width: 20px; height: 20px; padding: 0 6px; margin-left: 4px;
  border-radius: 10px; background: var(--paper-alt); color: var(--ink-soft);
  font: 700 0.72rem var(--font-body); vertical-align: 2px;
}
.pf-notes-empty { margin: 0; }
.pf-notes-list { display: flex; flex-direction: column; gap: 12px; }
.pf-notes-done { margin-top: 14px; }
.pf-notes-done > summary { cursor: pointer; font-size: 0.86rem; font-weight: 600; color: var(--ink-soft); padding: 4px 0; }
.pf-notes-done > summary:hover { color: var(--ink); }
.pf-notes-done[open] > summary { margin-bottom: 10px; }

.pf-note {
  border: 1px solid var(--rule); border-left: 4px solid var(--accent); border-radius: 14px;
  padding: 10px 14px 12px; background: var(--surface); min-width: 0;
}
.pf-note.is-en_attente { border-left-color: #d9a441; background: #fffaf0; }
.pf-note.is-traitee { border-left-color: var(--sage); }
.pf-note-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin-bottom: 8px; }
.pf-note-status {
  padding: 2px 9px; border-radius: 999px; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.02em;
  background: var(--blush); color: var(--accent-deep);
}
.pf-note.is-en_attente .pf-note-status { background: #ffecc8; color: #8b5a13; }
.pf-note.is-traitee .pf-note-status { background: var(--sage-soft); color: #4f6b5e; }
.pf-note-when { font-size: 0.76rem; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.pf-note-tools { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; }

.pf-note-thread { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.pf-note-msg { padding: 8px 11px; border-radius: 11px; background: var(--paper); min-width: 0; }
.pf-note-msg.is-claude { background: var(--sage-soft); margin-left: clamp(0px, 4cqi, 32px); }
.pf-note-msg-meta { font-size: 0.74rem; color: var(--ink-soft); margin-bottom: 2px; }
.pf-note-msg-meta strong { color: var(--ink); }
.pf-note-msg.is-claude .pf-note-msg-meta strong { color: #4f6b5e; }
.pf-note-msg-body { font-size: 0.88rem; line-height: 1.5; overflow-wrap: anywhere; }
.pf-note-imgs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.pf-note-img { display: block; line-height: 0; border-radius: 9px; overflow: hidden; border: 1px solid var(--rule); background: var(--surface); }
.pf-note-img img { height: 116px; width: auto; max-width: 100%; object-fit: cover; }
.pf-note-img:hover { border-color: var(--accent); }

.pf-note-foot { margin-top: 8px; }
.pf-note-foot .pf-note-composer { margin-top: 2px; }

.pf-note-composer { display: flex; flex-direction: column; gap: 8px; border-radius: 12px; transition: box-shadow 0.15s ease; }
.pf-note-composer[hidden] { display: none; }
.pf-note-composer.is-dragover { box-shadow: 0 0 0 2px var(--accent); background: var(--blush); }
.pf-note-composer-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.pf-note-composer-bar [data-note-send] { margin-left: auto; }
/* `.admin-main label` (colonne « libellé au-dessus du champ ») l'emporte sur
   une classe seule : même motif que les cases à cocher, on le double. */
.admin-main label.pf-note-attach {
  display: inline-flex; flex-direction: row; align-items: center; gap: 5px; cursor: pointer;
  font-family: var(--font-display); font-size: 0.8rem; color: var(--ink);
}
.admin-main label.pf-note-attach:hover { color: var(--paper); }
.pf-note-attach svg { width: 14px; height: 14px; }
.pf-note-hint { font-size: 0.74rem; color: var(--ink-faint); }
.pf-note-pending { display: flex; flex-wrap: wrap; gap: 8px; }
.pf-note-pending[hidden] { display: none; }
.pf-note-pending-item { position: relative; line-height: 0; }
.pf-note-pending-item img { width: 72px; height: 72px; object-fit: cover; border-radius: 9px; border: 1px solid var(--rule); }
.pf-note-pending-remove {
  position: absolute; top: -6px; right: -6px; width: 22px; height: 22px; border-radius: 50%;
  border: 0; background: var(--ink); color: var(--paper); font: 700 0.9rem/22px var(--font-body);
  cursor: pointer; padding: 0;
}
.pf-note-pending-remove:hover { background: var(--danger); }
@media (max-width: 779px) {
  .pf-note-hint { display: none; }
  .pf-note-img img { height: 88px; }
}

.admin-badge.p-notes-badge { background: var(--blush); color: var(--accent-deep); text-decoration: none; }
.admin-badge.p-notes-badge.is-question { background: #ffecc8; color: #8b5a13; }

/* ── Onglet « Paramètres impression » de la fiche produit (29/09/2026) ─────
   Plateaux d'impression dans une scène 3D commune + réglages par plateau. */
.pp-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.pp-head .admin-h2 { margin-right: auto; }
.pp-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.pp-upload { cursor: pointer; }
.pp-totals { margin: 4px 0 10px; font-size: 0.86rem; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.pp-totals:empty { display: none; }

.pp-stage { position: relative; border-radius: var(--radius-m); overflow: hidden; background: #1d2129; }
.pp-scene { height: clamp(300px, 52vh, 560px); cursor: grab; }
.pp-scene:active { cursor: grabbing; }
.pp-reframe { position: absolute; top: 10px; right: 10px; background: rgba(255, 255, 255, 0.9); }
.pp-empty { position: absolute; inset: auto 16px 16px; margin: 0; padding: 10px 12px; border-radius: 10px; background: rgba(255, 255, 255, 0.92); color: var(--ink); font-size: 0.88rem; }
.pp-empty[hidden] { display: none; }

.pp-cols { display: grid; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); gap: 14px; margin-top: 14px; align-items: start; }
@media (max-width: 900px) { .pp-cols { grid-template-columns: minmax(0, 1fr); } }

.pp-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.pp-item-btn {
  width: 100%; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; text-align: left;
  padding: 9px 11px; border: 1px solid var(--rule); border-radius: 12px; background: var(--surface);
  font: inherit; color: var(--ink); cursor: pointer; min-width: 0;
}
.pp-item-btn:hover { border-color: var(--accent); }
.pp-item-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pp-item.is-active .pp-item-btn { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); background: var(--blush); }
.pp-item-main { display: flex; flex-direction: column; flex: 1 1 180px; min-width: 0; }
.pp-item-main strong { font-size: 0.9rem; overflow-wrap: anywhere; }
.pp-item-sub { font-size: 0.76rem; color: var(--ink-soft); overflow-wrap: anywhere; }
.pp-item-nums { font-size: 0.8rem; font-variant-numeric: tabular-nums; color: var(--ink-soft); }
.pp-dot { width: 14px; height: 14px; border-radius: 50%; flex: none; background: #b9b3aa; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.18); }

.pp-chip { padding: 2px 8px; border-radius: 999px; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.02em; white-space: nowrap; }
.pp-chip.is-idle { background: var(--paper-alt); color: var(--ink-soft); }
.pp-chip.is-wait { background: #ffecc8; color: #8b5a13; }
.pp-chip.is-run { background: #dfe9f7; color: #2d5a8f; }
.pp-chip.is-ok { background: var(--paper-alt); color: var(--ink); }
.pp-chip.is-err { background: var(--danger-soft); color: var(--danger); }
.pp-chip.is-valid { background: var(--sage-soft); color: #3f5d4f; }

.pp-editor { border: 1px solid var(--rule); border-radius: 14px; padding: 12px 14px; background: var(--surface); display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.pp-editor[hidden] { display: none; }
.pp-ed-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: end; }
.pp-field { display: flex; flex-direction: column; gap: 4px; font-size: 0.8rem; font-weight: 600; color: var(--ink-soft); min-width: 0; }
.pp-field input, .pp-field select, .pp-field textarea { font: inherit; font-weight: 400; color: var(--ink); }
.pp-field small { font-weight: 400; }
.pp-grow { flex: 1 1 220px; }
.pp-seg { border: 0; margin: 0; padding: 0; flex-direction: row; flex-wrap: wrap; gap: 4px 12px; align-items: center; }
.pp-seg legend { padding: 0; margin-bottom: 4px; width: 100%; }
.pp-seg label { display: inline-flex; align-items: center; gap: 4px; font-weight: 500; color: var(--ink); }
.pp-sub { margin: 4px 0 0; font-size: 0.84rem; font-weight: 700; color: var(--ink); }
.pp-settings { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px 10px; }
.pp-settings input::placeholder { color: var(--ink-faint); }
.pp-ranges { display: flex; flex-direction: column; gap: 8px; }
.pp-ranges:empty { display: none; }
.pp-range { display: grid; grid-template-columns: repeat(3, minmax(0, 150px)) auto; gap: 8px 10px; align-items: end; }
.pp-range-add { align-self: flex-start; }
@media (max-width: 560px) { .pp-range { grid-template-columns: repeat(3, minmax(0, 1fr)); } .pp-range > button { grid-column: 1 / -1; justify-self: start; } }
.pp-ed-bar { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.pp-spacer { flex: 1 1 auto; }
.pp-dirty { margin: 0; font-size: 0.8rem; color: #8b5a13; }
.pp-dirty[hidden] { display: none; }

.pp-print { border-top: 1px dashed var(--rule); padding-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.pp-print[hidden] { display: none; }
.pp-slots { display: flex; flex-wrap: wrap; gap: 6px; font-size: 0.84rem; }
.pp-slot { display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px; border: 1px solid var(--rule); border-radius: 10px; background: var(--paper); font: inherit; cursor: pointer; }
.pp-slot:disabled { opacity: 0.45; cursor: not-allowed; }
.pp-slot.is-active { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }

.pp-valid { border-top: 1px solid var(--rule); padding-top: 10px; display: flex; flex-direction: column; gap: 6px; }
.pp-valid-ok { margin: 0; padding: 8px 10px; border-radius: 10px; background: var(--sage-soft); color: #3f5d4f; font-size: 0.86rem; font-weight: 600; }
.pp-valid-note { flex: 1 1 220px; font: inherit; }

/* Pièces des plateaux (30/09/2026) : barre de déplacement, liste. */
.pp-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; margin-top: 10px; padding: 8px 10px; border: 1px solid var(--rule); border-radius: 12px; background: var(--surface); font-size: 0.84rem; }
.pp-bar[hidden] { display: none; }
.pp-seg-btns { display: inline-flex; border: 1px solid var(--rule); border-radius: 999px; overflow: hidden; }
.pp-mode { border: 0; background: transparent; padding: 5px 12px; font: inherit; font-weight: 600; color: var(--ink-soft); cursor: pointer; }
.pp-mode.is-active { background: var(--accent); color: #fff; }
.pp-mode:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.pp-sel { color: var(--ink-soft); min-width: 0; }
.pp-move { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; color: var(--ink-soft); }
.pp-move select { font: inherit; max-width: 240px; }
.pp-pieces .pp-sub { margin-bottom: 4px; }
.pp-piece-list { list-style: none; margin: 0; padding: 0; max-height: 180px; overflow: auto; display: flex; flex-direction: column; gap: 2px; font-size: 0.82rem; }
.pp-piece-list label { display: flex; align-items: center; gap: 6px; cursor: pointer; }

.pp-bar label.pp-move { flex-direction: row; margin: 0; }

/* Statistiques > Vitrine (30/09/2026) : taux de clic des vignettes et tests
   de couverture, cf. views/admin/_stats-vitrine.php. */
.vit-intro { max-width: 860px; margin-bottom: 14px; }
.vit-kpis { grid-template-columns: repeat(6, minmax(0, 1fr)); }
@media (max-width: 1023px) { .vit-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.vit-scroll { max-height: 520px; }
.vit-table td { vertical-align: middle; }
.vit-produit { display: flex; align-items: center; gap: 10px; min-width: 220px; }
.vit-produit img { width: 36px; height: 36px; object-fit: cover; border-radius: 8px; flex-shrink: 0; }
.vit-faible td { color: var(--ink-faint); }
.vit-faible td a { color: var(--ink-soft); }
.vit-sub { color: var(--ink-faint); font-size: 0.78rem; }
.vit-ci { display: block; }
.vit-ci-track { stroke: var(--rule); stroke-width: 2; }
.vit-ci-range { fill: var(--sage-soft); stroke: var(--sage); stroke-width: 1; }
.vit-ci-avg { stroke: var(--ink-faint); stroke-width: 1.5; stroke-dasharray: 2 2; }
.vit-ci-dot { fill: var(--accent-deep); }
.vit-tests { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr)); gap: 12px; }
.vit-test { border: 1px solid var(--rule); border-radius: var(--radius-s); padding: 12px; background: var(--surface); min-width: 0; }
.vit-test-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 10px; font-weight: 600; font-size: 0.9rem; }
.vit-test-head a { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vit-variantes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.vit-variante { margin: 0; display: flex; flex-direction: column; gap: 6px; }
.vit-variante img, .vit-absente {
  width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: 10px;
  border: 2px solid transparent; background: var(--paper-alt);
}
.vit-absente { display: grid; place-items: center; font-size: 0.8rem; color: var(--ink-faint); }
.vit-variante.is-meneuse img { border-color: var(--accent); }
.vit-variante.is-gagnante img { border-color: var(--sage); }
.vit-variante figcaption { display: flex; flex-direction: column; gap: 3px; font-size: 0.78rem; color: var(--ink-soft); }
.vit-rang { font-weight: 600; color: var(--ink); }
.vit-chiffres { font-variant-numeric: tabular-nums; }
.vit-chiffres strong { color: var(--ink); }
.vit-proba { display: flex; align-items: center; gap: 6px; font-variant-numeric: tabular-nums; }
.vit-proba-bar { flex: 1; height: 6px; border-radius: 3px; background: var(--paper-alt); overflow: hidden; }
.vit-proba-bar span { display: block; height: 100%; background: var(--accent); border-radius: 3px; }
.vit-variante.is-gagnante .vit-proba-bar span { background: var(--sage); }
.vit-produit .admin-badge { white-space: nowrap; flex-shrink: 0; }
.vit-produit a { min-width: 0; }
.vit-attente { color: var(--ink-faint); font-style: italic; }
.vit-autres { margin-top: 12px; }
.vit-autres > summary { cursor: pointer; font-weight: 600; font-size: 0.88rem; color: var(--accent-deep); margin-bottom: 12px; }

/* Plateaux multicolores et éclatement par couleur (30/09/2026),
   cf. views/admin/products/_plateaux.php. */
.pp-list-sep { margin: 8px 2px 0; font-size: 0.74rem; font-weight: 700; letter-spacing: 0.03em; text-transform: uppercase; color: var(--ink-faint); }
.pp-item.is-inactive .pp-item-btn { background: var(--paper-alt); border-style: dashed; }
.pp-item.is-inactive .pp-item-main strong, .pp-item.is-inactive .pp-item-nums { color: var(--ink-soft); }

.pp-colors { display: flex; flex-direction: column; gap: 6px; }
.pp-colors[hidden] { display: none; }
.pp-color-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 8px 10px; }
.pp-color-head { display: inline-flex; align-items: center; gap: 6px; }

.pp-split { border: 1px solid var(--rule); border-radius: 12px; padding: 10px 12px; background: var(--paper-alt); display: flex; flex-direction: column; gap: 8px; }
.pp-split[hidden] { display: none; }
.pp-split .pp-sub { margin: 0; }
.pp-split .pf-help { margin: 0; }
.pp-split.is-child { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.pp-split-note { margin: 0; flex: 1 1 260px; font-size: 0.84rem; color: var(--ink-soft); }
.pp-split-err { margin: 0; font-size: 0.84rem; color: var(--danger); }
.pp-split-warn { margin: 0; font-size: 0.84rem; color: #8b5a13; }
.pp-split-sum { margin: 0; font-size: 0.86rem; color: var(--ink); font-variant-numeric: tabular-nums; }
.pp-split-run { margin: 0; display: flex; align-items: center; gap: 8px; font-size: 0.86rem; color: #2d5a8f; }
.pp-split-run::before { content: ''; width: 12px; height: 12px; flex: none; border-radius: 50%; border: 2px solid currentColor; border-right-color: transparent; animation: pp-tourne 0.9s linear infinite; }
@keyframes pp-tourne { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .pp-split-run::before { animation: none; } }
.pp-mode-switch { align-self: flex-start; }
.pp-split-row { display: flex; flex-direction: column; gap: 10px; }
.pp-split-view { display: block; border-radius: 10px; overflow: hidden; background: #fff; border: 1px solid var(--rule); }
.pp-split-view img { display: block; width: 100%; height: auto; }
.pp-montage-box { min-width: 0; }
.pp-montage { margin: 4px 0 0; padding-left: 22px; columns: 2 200px; column-gap: 18px; font-size: 0.8rem; line-height: 1.45; color: var(--ink); font-variant-numeric: tabular-nums; }
.pp-montage li { break-inside: avoid; margin-bottom: 3px; }
.pp-montage li::marker { color: var(--ink-faint); }
.pp-montage .pp-dot { display: inline-block; width: 10px; height: 10px; margin-right: 6px; vertical-align: -1px; }

/* ── Onglet « Vidéo » de la fiche produit (01/10/2026) ───────────────────── */
.pv-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.pv-cols { display: grid; grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr); gap: 18px; margin-top: 12px; align-items: start; }
.pv-cols[hidden] { display: none; }
@media (max-width: 900px) { .pv-cols { grid-template-columns: minmax(0, 1fr); } }
.pv-form { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.pv-h3 { margin: 10px 0 0; font-size: 0.86rem; font-weight: 700; color: var(--ink); display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; }
.pv-field { display: flex; flex-direction: column; gap: 4px; font-size: 0.8rem; font-weight: 600; color: var(--ink-soft); min-width: 0; }
.pv-field input, .pv-field select { font: inherit; font-weight: 400; color: var(--ink); min-width: 0; }
.pv-aide { font-size: 0.76rem; font-weight: 400; color: var(--ink-soft); margin: 0; }
.pv-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: end; }
.pv-grow { flex: 1 1 200px; }
.pv-prix { flex: 0 0 110px; }
#pvRoot .pv-debut { flex: 0 0 auto; flex-direction: row; align-items: center; gap: 8px; margin-left: auto; }
#pvRoot .pv-debut input { width: 72px; flex: 0 0 72px; }
.pv-row-centre { align-items: center; }
.pv-pastille { display: inline-block; width: 14px; height: 14px; border-radius: 50%; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.18); }
.pv-pastille[hidden], #pvRoot .pv-field[hidden] { display: none; }
.pv-lib { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.pv-clip .pv-lien + .pv-lien { margin-left: 6px; }
.pv-angle { display: flex; align-items: center; gap: 8px; }
.pv-angle input[type="range"] { flex: 1 1 auto; min-width: 0; }
.pv-angle input[type="number"] { flex: 0 0 76px; }
.pv-lien { align-self: flex-start; background: none; border: 0; padding: 0; font: inherit; font-size: 0.78rem; color: var(--accent-deep, #b8452f); text-decoration: underline; cursor: pointer; }
.pv-suppr { color: var(--danger); }
.pv-photos { display: grid; grid-template-columns: repeat(auto-fill, minmax(74px, 1fr)); gap: 8px; }
.pv-photo { position: relative; display: block; border-radius: 10px; overflow: hidden; cursor: pointer; aspect-ratio: 1; background: var(--surface-2, #f1eef3); }
.pv-photo img { width: 100%; height: 100%; object-fit: cover; display: block; opacity: 0.55; transition: opacity 0.15s; }
.pv-photo input { position: absolute; top: 6px; left: 6px; z-index: 1; }
.pv-photo input:checked + img { opacity: 1; }
.pv-photo:has(input:checked) { outline: 2px solid var(--accent, #e8674d); outline-offset: 1px; }
.pv-clips { display: flex; flex-direction: column; gap: 6px; }
.pv-clip { display: flex; align-items: center; gap: 10px; padding: 6px 10px; border-radius: 10px; background: var(--surface); box-shadow: var(--card-shadow); font-size: 0.82rem; min-width: 0; }
.pv-clip img { width: 34px; height: 46px; object-fit: cover; border-radius: 6px; flex: none; }
.pv-clip-nom { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pv-clip-nom small { display: block; color: var(--ink-soft); font-size: 0.74rem; white-space: normal; }
.pv-clip.is-bad small { color: var(--danger); }
.pv-clip .pv-lien { align-self: center; flex: none; }
.pv-upload { cursor: pointer; }
.pv-envoi { margin: 0; font-size: 0.8rem; color: var(--ink-soft); }
.pv-formats { display: flex; flex-direction: column; gap: 4px; font-size: 0.84rem; }
.pv-go { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 8px; }
.pv-results { min-width: 0; }
.pv-progress { margin: 0 0 12px; padding: 10px 14px; border-radius: 12px; background: var(--surface); box-shadow: var(--card-shadow); font-size: 0.86rem; font-weight: 600; }
.pv-progress::before { content: ""; display: inline-block; width: 10px; height: 10px; margin-right: 8px; border-radius: 50%; background: var(--accent, #e8674d); animation: pv-pouls 1.2s ease-in-out infinite; }
@keyframes pv-pouls { 50% { opacity: 0.25; } }
@media (prefers-reduced-motion: reduce) { .pv-progress::before { animation: none; } }
.pv-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.pv-item { padding: 12px 14px; border-radius: 14px; background: var(--surface); box-shadow: var(--card-shadow); }
.pv-item.is-valid { outline: 2px solid var(--ok, #2e8b57); outline-offset: -2px; }
.pv-item-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; margin-bottom: 10px; }
.pv-players { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; align-items: start; }
@media (max-width: 520px) { .pv-players { grid-template-columns: minmax(0, 1fr); } }
.pv-player { margin: 0; min-width: 0; }
.pv-player video { width: 100%; max-height: 460px; border-radius: 12px; background: #f1eef3; display: block; }
.pv-player figcaption { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; margin-top: 6px; font-size: 0.82rem; font-weight: 600; }
.pv-player figcaption small { font-weight: 400; color: var(--ink-soft); margin-right: auto; }
.pv-item-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 10px; }
.pv-item-bar .pv-lien { align-self: center; margin-left: auto; }
.pv-erreur { margin: 0; font-size: 0.84rem; color: var(--danger); }
.pv-empty { color: var(--ink-soft); font-size: 0.86rem; }

/* Boutons des places de marché (04/10/2026, demande de l'exploitant) : une
   lettre par plateforme (E = Etsy, A = Amazon) et une couleur d'état — vert =
   envoyé et à jour, orange = envoyé mais modifié depuis (ou dernier envoi en
   échec), gris = jamais envoyé ou annonce hors vente. Le survol garde la
   couleur d'état et ajoute un anneau, au lieu du fond d'accent des autres
   boutons ronds : l'orange et le survol se seraient confondus. */
.admin-mp-btn { font-family: var(--font-display); font-weight: 700; font-size: 0.82rem; line-height: 1; }
.admin-mp-btn.is-vert, .admin-mp-btn.is-vert:hover:not(:disabled) { background: #7cc293; color: #0f3b1f; }
.admin-mp-btn.is-orange, .admin-mp-btn.is-orange:hover:not(:disabled) { background: #f2a65a; color: #4a2706; }
.admin-mp-btn.is-gris, .admin-mp-btn.is-gris:hover:not(:disabled) { background: var(--paper-alt); color: var(--ink-soft); }
.admin-mp-btn:hover:not(:disabled):not([aria-disabled="true"]) { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent); }
.admin-mp-btn[aria-disabled="true"], .admin-mp-btn[aria-disabled="true"]:hover { cursor: default; transform: none; }
/* Galerie : la carte la plus étroite n’offre que 178 px à six commandes ; sans
   `flex: none`, le bouton A (seul hors formulaire) était écrasé à 20 px. */
.admin-mp-btn { flex: none; }
.admin-gallery-actions { gap: 5px; }
.admin-gallery-actions .admin-mp-btn { width: 26px; height: 26px; font-size: 0.74rem; }

/* ═══ Onglet « Amazon » de la fiche produit (05/10/2026, pont Amazon) ═══ */
a.admin-mp-btn { text-decoration: none; font-weight: 700; }
.pa-etat { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.pa-etat .admin-mp-btn { flex: none; cursor: default; }
.pa-etat .admin-mp-btn:hover { transform: none; }
.pa-etat-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 260px; }
.pa-etat-txt strong { font-size: 0.92rem; color: var(--ink); overflow-wrap: anywhere; }
.pa-sku { font-size: 0.78rem; color: var(--ink-soft); }
.pa-flash { margin: 12px 0 0; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; }
.pa-flash[hidden] { display: none; }
.pa-form { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.pa-field { display: flex; flex-direction: column; gap: 4px; font-size: 0.8rem; font-weight: 600; color: var(--ink-soft); min-width: 0; }
.pa-field input, .pa-field select, .pa-field textarea { font: inherit; font-weight: 400; color: var(--ink); min-width: 0; width: 100%; }
.pa-lib { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.pa-aide { font-size: 0.76rem; font-weight: 400; color: var(--ink-soft); margin: 0; }
.pa-compte { font-size: 0.72rem; font-weight: 400; color: var(--ink-faint); }
.pa-compte.is-trop { color: var(--danger); font-weight: 600; }
.pa-bullets { display: flex; flex-direction: column; gap: 6px; }
.pa-bullet { resize: vertical; }
.pa-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: end; }
.pa-row > input { flex: 1 1 160px; min-width: 0; }
.pa-grow { flex: 1 1 180px; }
.pa-prix { flex: 1 1 120px; }
.pa-nombre { flex: 0 1 110px; }
.pa-ia { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin: 0 0 12px; padding: 8px 12px; border-radius: var(--radius-s); background: var(--paper-alt); font-size: 0.8rem; color: var(--ink-soft); }
.pa-ia.is-encours .pa-ia-txt::before { content: ''; display: inline-block; width: 8px; height: 8px; margin-right: 8px; border-radius: 50%; background: var(--accent, #e8674d); animation: admin-badge-pulse 1.8s ease-in-out infinite; }
.pa-ia.is-erreur { background: var(--danger-soft); color: var(--danger); }
.pa-ia-txt { flex: 1 1 240px; min-width: 0; }
.pa-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.pa-actions [hidden] { display: none; }
.pa-actions + .pa-aide { margin-top: 8px; }
.pa-danger { color: var(--danger); }
.pa-image { display: flex; flex-wrap: wrap; gap: 12px 16px; align-items: flex-start; }
.pa-image-cadre { flex: none; width: 160px; height: 160px; display: flex; align-items: center; justify-content: center; background: #fff; border: 1px solid var(--rule); border-radius: var(--radius-s); overflow: hidden; }
.pa-image-cadre.is-vide { background: var(--paper-alt); border-style: dashed; }
.pa-image-cadre img { max-width: 100%; max-height: 100%; object-fit: contain; }
.pa-image-cadre img[hidden] { display: none; }
.pa-image-txt { flex: 1 1 240px; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.pa-image-txt .pa-aide { margin: 0; }
.pa-galerie { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 8px; }
.pa-galerie[hidden] { display: none; }
.pa-galerie-cadre { position: relative; width: 120px; height: 120px; }
.pa-galerie-retirer { position: absolute; top: 4px; right: 4px; width: 24px; height: 24px; border: 1px solid var(--rule); border-radius: 50%; background: #fff; color: var(--danger); font-size: 1rem; line-height: 1; cursor: pointer; }
.pa-galerie-retirer:disabled { opacity: .4; cursor: default; }
/* Contenu A+ (23/10/2026) : bannières 970 × 600 l'une sous l'autre, en
   pleine largeur comme sous l'annonce, avec leur texte de remplacement. */
.pa-aplus-etat { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; margin-bottom: 12px; font-size: 0.86rem; }
.pa-aplus-pastille { flex: none; width: 10px; height: 10px; border-radius: 50%; background: var(--ink-faint); }
.pa-aplus-pastille.is-ok { background: #7cc293; }
.pa-aplus-pastille.is-attente { background: #f2c45a; }
.pa-aplus-pastille.is-alerte { background: #f2a65a; }
.pa-aplus-pastille.is-erreur { background: var(--danger); }
.pa-aplus { list-style: none; margin: 0 0 8px; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.pa-aplus[hidden] { display: none; }
.pa-aplus-item { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.pa-aplus-img { display: block; width: 100%; max-width: 970px; height: auto; aspect-ratio: 970 / 600; object-fit: cover; border: 1px solid var(--rule); border-radius: var(--radius-s); background: var(--paper-alt); }
.pa-aplus-bas { display: flex; flex-wrap: wrap; gap: 8px; align-items: end; max-width: 970px; }
.pa-aplus-bas .admin-btn { flex: none; }
.pa-fichier { position: relative; overflow: hidden; }
.pa-fichier input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.pa-fichier:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
.pa-refus { margin: 8px 0 0; font-size: 0.8rem; color: var(--danger); }
.pa-refus[hidden] { display: none; }
.pa-h3 { margin: 16px 0 8px; font-size: 0.86rem; font-weight: 700; color: var(--ink); display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; }
.pa-issues { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.pa-issue { padding: 8px 12px; border-radius: var(--radius-s); font-size: 0.82rem; line-height: 1.45; background: var(--paper-alt); color: var(--ink); overflow-wrap: anywhere; }
.pa-issue strong { margin-right: 4px; }
.pa-issue.is-erreur { background: var(--danger-soft); }
.pa-issue.is-erreur strong { color: var(--danger); }
.pa-issue.is-alerte { background: #ffecc8; color: #5c3a0b; }
.pa-issue.is-ok { background: var(--sage-soft); color: #4f6b5e; }
.pa-issue.is-vide { color: var(--ink-soft); }
.pa-attr { display: block; margin-top: 4px; font-size: 0.74rem; color: var(--ink-soft); }
.pa-lien { background: none; border: 0; padding: 0; font: inherit; font-size: 0.8rem; color: var(--accent-deep, #b8452f); text-decoration: underline; cursor: pointer; }
@media (prefers-reduced-motion: reduce) { .pa-ia.is-encours .pa-ia-txt::before { animation: none; } }

/* ═══ Livre des dépenses, Ventes › Dépenses (05/10/2026) ═══ */
.dep-intro { margin: 0 0 16px; max-width: 75ch; }
.dep-stats { margin-bottom: 16px; }
.dep-cols { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: 0 16px; align-items: start; }
@media (max-width: 900px) { .dep-cols { grid-template-columns: minmax(0, 1fr); } }
.dep-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.dep-item { display: grid; grid-template-columns: 112px minmax(0, 1fr) auto auto; gap: 4px 14px; align-items: center; padding: 10px 0; border-top: 1px solid var(--rule); }
.dep-item:first-child { border-top: 0; padding-top: 0; }
.dep-item-date { display: flex; flex-direction: column; gap: 3px; align-items: flex-start; font-size: 0.86rem; font-variant-numeric: tabular-nums; }
.dep-item.is-passee .dep-item-date strong { color: var(--danger); }
.dep-item-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; font-size: 0.88rem; }
.dep-item-txt a { color: var(--ink); font-weight: 600; text-decoration: none; overflow-wrap: anywhere; }
.dep-item-txt a:hover { text-decoration: underline; }
.dep-item-txt .admin-muted { font-size: 0.78rem; }
.dep-item-montant { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.dep-item-actions { display: flex; gap: 10px; }
.dep-item-actions form { margin: 0; }
@media (max-width: 600px) {
  .dep-item { grid-template-columns: minmax(0, 1fr) auto; }
  .dep-item-txt, .dep-item-actions { grid-column: 1 / -1; }
}
.dep-barres { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.dep-barres li { display: grid; grid-template-columns: minmax(0, 11rem) minmax(0, 1fr) auto; gap: 10px; align-items: center; font-size: 0.84rem; }
.dep-barre { height: 8px; border-radius: 4px; background: var(--paper-alt); overflow: hidden; }
.dep-barre span { display: block; height: 100%; border-radius: 4px; background: var(--accent, #e8674d); }
.dep-barre-val { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }
.dep-filtres { display: flex; flex-wrap: wrap; gap: 10px 12px; align-items: flex-end; margin: 4px 0 14px; }
.dep-filtres label { display: flex; flex-direction: column; gap: 4px; font-size: 0.78rem; font-weight: 600; color: var(--ink-soft); min-width: 120px; }
.dep-filtres .dep-filtre-q { flex: 1 1 220px; }
.dep-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.dep-date { white-space: nowrap; font-variant-numeric: tabular-nums; }
.dep-lien { font-weight: 600; color: var(--ink); text-decoration: none; }
.dep-lien:hover { text-decoration: underline; }
.dep-objet { font-size: 0.82rem; color: var(--ink-soft); overflow-wrap: anywhere; }
.dep-table .admin-badge-sm { margin-top: 4px; }
.dep-table tr.is-annulee td { color: var(--ink-faint); }
.dep-table tr.is-annulee .dep-num strong { text-decoration: line-through; }
.dep-form { max-width: 920px; }
.dep-aide { display: block; margin-top: 4px; font-size: 0.76rem; font-weight: 400; }
.dep-calcul { margin: -4px 0 0; font-size: 0.82rem; color: var(--ink-soft); min-height: 1.2em; }
.dep-importee { padding: 10px 14px; border-radius: var(--radius-s); background: var(--paper-alt); }
.dep-importee p { margin: 0 0 4px; }
.dep-boutons { display: flex; gap: 10px; }
.dep-pieces { margin-top: 16px; max-width: 920px; }
.dep-fichiers { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.dep-fichiers li { display: flex; flex-wrap: wrap; gap: 6px 12px; align-items: center; font-size: 0.88rem; }
.dep-fichiers form { display: inline; margin: 0; }
.dep-suppr { margin-top: 12px; }
/* Factures lues par Codex (05/10/2026) */
.dep-depot { display: inline; margin: 0; }
.dep-depot-btn { cursor: pointer; }
.dep-depot-item { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; padding: 8px 0; border-top: 1px solid var(--rule); font-size: 0.86rem; }
.dep-depot-item:first-child { border-top: 0; padding-top: 0; }
.dep-depot-nom { font-weight: 600; color: var(--ink); overflow-wrap: anywhere; }
.dep-depot-etat { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; min-width: 0; }
.dep-depot-etat a { color: var(--ink); }
.dep-depot-erreur { color: var(--danger); }
.dep-depots-aide { margin: 10px 0 0; font-size: 0.8rem; }

/* ─── Planning › Impressions (06/10/2026) ─────────────────────────────────── */
.pl-tabs a { display: inline-block; text-decoration: none; }
.pl-intro { margin: 0 0 16px; max-width: 80ch; }
.pl-stats { margin-bottom: 16px; }
.pl-progress { height: 6px; margin-top: 10px; border-radius: 3px; background: var(--paper-alt); overflow: hidden; }
.pl-progress span { display: block; height: 100%; background: var(--sage); border-radius: 3px; }
.pl-cols { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: 0 16px; align-items: start; }
@media (max-width: 1100px) { .pl-cols { grid-template-columns: minmax(0, 1fr); } }
.pl-compte { font-size: .8rem; font-weight: 500; margin-left: 6px; }
.pl-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.pl-objet { display: grid; grid-template-columns: 28px 56px minmax(0, 1fr) auto; gap: 12px; align-items: start; padding: 12px 0; border-top: 1px solid var(--rule); scroll-margin-top: 90px; }
.pl-objet:first-child { border-top: none; }
.pl-objet:target { background: var(--sage-soft); border-radius: var(--radius-s); }
.pl-rang { font-family: var(--font-display); font-weight: 600; color: var(--ink-faint); text-align: right; padding-top: 4px; }
.pl-vignette { width: 56px; height: 56px; border-radius: 12px; overflow: hidden; background: var(--paper-alt); display: block; }
.pl-vignette img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pl-corps { min-width: 0; }
.pl-titre { display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: baseline; }
.pl-titre a { color: var(--ink); font-weight: 600; text-decoration: none; }
.pl-titre a:hover { color: var(--accent-deep); }
.pl-infos { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center; margin-top: 4px; font-size: .84rem; color: var(--ink-soft); }
.pl-jours { color: var(--ink); font-weight: 500; }
.pl-pasavant { color: var(--accent-deep); }
.pl-badge { display: inline-block; padding: 2px 8px; border-radius: var(--radius-pill); font-size: .72rem; font-weight: 600; }
.pl-badge.is-a-imprimer { background: var(--blush); color: var(--accent-deep); }
.pl-badge.is-a-preparer { background: var(--paper-alt); color: var(--ink-soft); }
.pl-note { margin: 6px 0 0; font-size: .82rem; color: var(--ink-soft); font-style: italic; }
.pl-details { margin-top: 6px; font-size: .84rem; }
.pl-details > summary { cursor: pointer; color: var(--ink-soft); width: max-content; max-width: 100%; }
.pl-details[open] > summary { margin-bottom: 6px; }
.pl-plateaux { list-style: none; margin: 0 0 8px; padding: 0; }
.pl-plateaux li { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center; padding: 4px 0; border-bottom: 1px dashed var(--rule); }
.pl-plateaux li.is-valide .pl-plateau-nom { color: var(--ink-faint); }
.pl-plateaux form { margin: 0 0 0 auto; }
.pl-plateau-nom { font-weight: 500; }
.pl-preciser { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: flex-end; }
.pl-preciser label { display: flex; flex-direction: column; gap: 3px; font-size: .78rem; color: var(--ink-soft); }
.pl-preciser-note { flex: 1 1 220px; }
.pl-preciser input { font: inherit; font-size: .84rem; padding: 6px 8px; border: 1px solid var(--rule); border-radius: 10px; background: var(--surface); color: var(--ink); min-width: 0; }
.pl-btn-sm { padding: 6px 12px; font-size: .8rem; }
.pl-actions { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; justify-content: flex-end; max-width: 150px; }
.pl-actions form { margin: 0; }
.pl-bouger { font-size: .95rem; line-height: 1; }
.pl-imprimes { margin-top: 14px; font-size: .86rem; }
.pl-imprimes summary { cursor: pointer; font-weight: 600; }
.pl-imprimes ul { list-style: none; margin: 8px 0 0; padding: 0; }
.pl-imprimes li { padding: 4px 0; display: flex; flex-wrap: wrap; gap: 4px 8px; }
.pl-cote { display: flex; flex-direction: column; min-width: 0; }
.pl-jours-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.pl-jour { padding: 10px 12px; border: 1px solid var(--rule); border-radius: var(--radius-s); background: var(--surface); }
.pl-jour.is-aujourdhui { border-color: var(--accent); }
.pl-jour-tete { display: flex; justify-content: space-between; gap: 8px; flex-wrap: wrap; font-size: .86rem; }
.pl-charge { height: 4px; margin: 6px 0; border-radius: 2px; background: var(--paper-alt); overflow: hidden; }
.pl-charge span { display: block; height: 100%; background: var(--accent); }
.pl-jour ul { list-style: none; margin: 0; padding: 0; font-size: .82rem; }
.pl-jour li { padding: 2px 0; }
.pl-jour a { color: var(--ink); text-decoration: none; font-weight: 500; }
.pl-jour a:hover { color: var(--accent-deep); }
.pl-filaments { list-style: none; margin: 0; padding: 0; font-size: .86rem; }
.pl-filaments li { display: flex; align-items: center; gap: 8px; padding: 5px 0; border-bottom: 1px solid var(--rule); }
.pl-filaments li span:not(.pl-pastille):not(.pl-pastilles) { flex: 1 1 auto; min-width: 0; }
.pl-pastille { width: 14px; height: 14px; border-radius: 50%; border: 1px solid var(--rule); flex: 0 0 14px; display: inline-block; }
.pl-pastille.is-vide { background: repeating-linear-gradient(45deg, var(--paper-alt) 0 3px, var(--surface) 3px 6px); }
.pl-pastilles { display: inline-flex; gap: 2px; flex: 0 0 auto; }
.pl-aide { margin: 8px 0 0; font-size: .78rem; }
.pl-reglages-form { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: flex-end; }
.pl-reglages-form label { display: flex; flex-direction: column; gap: 3px; font-size: .78rem; color: var(--ink-soft); }
.pl-reglages-form input { width: 90px; font: inherit; padding: 6px 8px; border: 1px solid var(--rule); border-radius: 10px; background: var(--surface); color: var(--ink); }
@media (max-width: 640px) {
  .pl-objet { grid-template-columns: 22px 44px minmax(0, 1fr); }
  .pl-vignette { width: 44px; height: 44px; }
  .pl-actions { grid-column: 2 / -1; justify-content: flex-start; max-width: none; }
}

/* ─── Fiche produit › Conformité (06/10/2026) ─────────────────────────────── */
.pc-etat { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center; }
.pc-etat-txt { flex: 1 1 260px; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pc-aide { color: var(--ink-soft); font-size: .8rem; }
.pc-compte { font-family: var(--font-display); font-weight: 600; color: var(--ink); }
.pc-flash { margin: 12px 0 0; }
.pc-resume { margin: 12px 0 0; max-width: 80ch; }
.pc-natures { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.pc-natures:empty { display: none; }
.pc-nature { padding: 3px 10px; border-radius: var(--radius-pill); background: var(--paper-alt); color: var(--ink); font-size: .78rem; font-weight: 600; cursor: help; }
.pc-doutes { margin-top: 12px; padding: 10px 14px; border-radius: var(--radius-s); background: var(--blush); font-size: .86rem; }
.pc-doutes ul { margin: 6px 0 0; padding-left: 18px; }
.pc-avertissement { margin: 12px 0 0; font-size: .76rem; color: var(--ink-faint); }
.pc-famille .admin-h2 { display: flex; align-items: baseline; gap: 8px; }
.pc-famille-compte { font-size: .8rem; font-weight: 500; color: var(--ink-soft); }
.pc-item { padding: 12px 0; border-top: 1px solid var(--rule); }
.pc-famille .pc-item:first-of-type { border-top: none; padding-top: 4px; }
.pc-item-tete { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center; }
.pc-item-titre { margin: 0; font-size: .95rem; flex: 1 1 240px; min-width: 0; }
.pc-item.is-fait .pc-item-titre, .pc-item.is-non_applicable .pc-item-titre { color: var(--ink-soft); }
.pc-item.is-fait .pc-item-titre::before { content: "✓ "; color: var(--sage); }
.pc-badge { padding: 2px 8px; border-radius: var(--radius-pill); font-size: .7rem; font-weight: 600; }
.pc-badge.is-boutique { background: var(--sage-soft); color: #4f6b5e; }
.pc-badge.is-verifier { background: var(--danger-soft); color: var(--danger); }
.admin-main .pc-statut { width: auto; flex: 0 0 auto; min-width: 140px; font-size: .82rem; padding: 5px 8px; }
.admin-main .pc-item.is-fait .pc-statut { border-color: var(--sage); }
.admin-main .pc-item.is-en_cours .pc-statut { border-color: var(--accent); }
.pc-base { margin: 4px 0 0; font-size: .78rem; color: var(--ink-soft); }
.pc-raison { margin: 6px 0 0; font-size: .86rem; }
.pc-plus { margin-top: 6px; font-size: .84rem; }
.pc-plus summary { cursor: pointer; color: var(--accent-deep); width: max-content; max-width: 100%; }
.pc-plus p { margin: 6px 0 0; max-width: 85ch; }
.pc-suivi { margin-top: 6px; font-size: .84rem; }
.pc-suivi > summary { cursor: pointer; color: var(--ink-soft); width: max-content; max-width: 100%; }
.pc-suivi[open] > summary { margin-bottom: 4px; }
.pc-champs { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, .8fr) minmax(0, .8fr); gap: 8px 12px; margin-top: 10px; }
.pc-champ { display: flex; flex-direction: column; gap: 3px; font-size: .76rem; color: var(--ink-soft); min-width: 0; }
.pc-champ input, .pc-champ textarea { font: inherit; font-size: .84rem; padding: 6px 8px; border: 1px solid var(--rule); border-radius: 10px; background: var(--surface); color: var(--ink); min-width: 0; width: 100%; box-sizing: border-box; }
.pc-champ textarea { resize: vertical; }
.pc-champ-note { grid-column: 1 / -1; }
.pc-fichiers { margin-top: 8px; font-size: .84rem; }
.pc-fichiers ul { list-style: none; margin: 0; padding: 0; }
.pc-fichiers li { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; padding: 2px 0; }
.pc-joindre { cursor: pointer; display: inline-block; margin-top: 4px; }
.pc-joindre.is-busy { opacity: .5; pointer-events: none; }
.pc-anciennes summary { cursor: pointer; font-weight: 600; }
@media (max-width: 640px) {
  .pc-champs { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .pc-champs .pc-champ:first-child { grid-column: 1 / -1; }
}

/* ── Production d'un article de commande (10/10/2026) ───────────────── */
.prod-scene { height: 360px; border-radius: 14px; overflow: hidden; background: var(--paper-alt); margin-bottom: 14px; }
.prod-plates { display: flex; flex-direction: column; gap: 12px; }
.prod-plate { border: 1px solid var(--rule); border-radius: 14px; padding: 12px 14px; background: var(--paper); }
.prod-plate-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; cursor: pointer; }
.prod-settings { margin: 8px 0 10px; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: 0.82rem; color: var(--ink-soft); }
.prod-launch { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; }
.prod-line { display: flex; align-items: center; gap: 8px; margin: 0 0 10px; }
.prod-facts { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 4px 12px; margin: 0; font-size: 0.88rem; }
.prod-facts dt { color: var(--ink-soft); }
.prod-facts dd { margin: 0; font-weight: 600; overflow-wrap: anywhere; }
.prod-runs li { margin-bottom: 10px; }
.prod-error { color: #a33a2a; font-size: 0.84rem; overflow-wrap: anywhere; }
.prod-note { margin-top: 12px; font-size: 0.84rem; }
@media (max-width: 760px) { .prod-scene { height: 260px; } }
.prod-calage[hidden] { display: none; }
.prod-calage { border: 1px solid var(--accent); border-radius: 14px; padding: 12px 14px; margin-bottom: 14px; display: flex; flex-direction: column; gap: 10px; }
.prod-calage .admin-h3 { margin: 0; }
.prod-picker { height: 380px; border-radius: 12px; overflow: hidden; background: var(--paper-alt); }
.prod-verif { height: 300px; margin-top: 10px; }
.prod-calage-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.prod-calage-actions #prodCalageSave { margin-left: auto; }
.prod-ok { color: #4f6b5e; font-weight: 600; margin: 0 0 8px; }

/* ── Catalogue › Revue (11/10/2026) : les produits en ligne un par un, façon
   Tinder (views/admin/products/revue.php). Carte en deux colonnes à partir de
   1000 px, photo collée en haut pendant qu'on lit la colonne de droite. */
.rv-intro { margin: 0 0 14px; max-width: 90ch; }
.rv-raccourcis { display: inline-block; margin-left: 4px; }
.rv-raccourcis kbd { font-family: var(--font-body); font-size: 0.75rem; padding: 1px 6px; border: 1px solid var(--rule); border-bottom-width: 2px; border-radius: 6px; background: var(--surface); }
.rv-compte { font-family: var(--font-display); font-weight: 600; color: var(--ink-soft); }
.rv-barre { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; max-width: 1180px; }
.rv-position { font-family: var(--font-display); font-weight: 600; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.rv-scene { max-width: 1180px; transition: opacity 0.2s ease; }
.rv-scene.is-chargement { opacity: 0.55; }

.rv-carte {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px;
  background: var(--surface); border-radius: var(--radius-l); box-shadow: var(--card-shadow);
  padding: 18px; transition: transform 0.26s var(--ease-snap), opacity 0.26s ease; touch-action: pan-y;
}
.rv-carte.is-entree { transform: translateY(14px) scale(0.985); opacity: 0; }
.rv-carte.is-partie { pointer-events: none; }
@media (min-width: 1000px) {
  .rv-carte { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); gap: 28px; padding: 22px; }
  .rv-media { position: sticky; top: calc(var(--sticky-top) + 16px); align-self: start; }
}

.rv-cadre { position: relative; aspect-ratio: 1; border-radius: var(--radius-m); overflow: hidden; background: var(--paper-alt); }
.rv-photo { width: 100%; height: 100%; object-fit: contain; display: block; }
.rv-cadre .rv-3d { position: absolute; inset: 0; height: auto; margin: 0; border-radius: 0; }
.rv-sans-photo { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; margin: 0; color: var(--ink-faint); }
.rv-compteur {
  position: absolute; left: 12px; bottom: 12px; padding: 2px 9px; border-radius: 999px;
  background: rgba(43, 39, 51, 0.62); color: #fff; font-size: 0.78rem; font-variant-numeric: tabular-nums;
}
.rv-fleche {
  position: absolute; top: 50%; transform: translateY(-50%); width: 40px; height: 40px; border-radius: 50%;
  border: 0; background: rgba(255, 255, 255, 0.86); color: var(--ink); font-size: 1.5rem; line-height: 1; cursor: pointer;
  box-shadow: 0 1px 4px var(--shadow-strong); opacity: 0; transition: opacity 0.15s ease;
}
.rv-fleche.is-prec { left: 10px; }
.rv-fleche.is-suiv { right: 10px; }
.rv-cadre:hover .rv-fleche, .rv-fleche:focus-visible { opacity: 1; }
@media (hover: none) { .rv-fleche { display: none; } }
.rv-vignettes { display: flex; gap: 8px; margin-top: 10px; overflow-x: auto; padding-bottom: 2px; }
.rv-vignette {
  flex: 0 0 56px; width: 56px; height: 56px; padding: 0; border: 2px solid transparent; border-radius: 12px;
  overflow: hidden; background: var(--paper-alt); cursor: pointer; font-family: var(--font-display); font-weight: 700; color: var(--ink-soft);
}
.rv-vignette img { width: 100%; height: 100%; object-fit: cover; display: block; }
.rv-vignette.is-active { border-color: var(--accent); }
.rv-vignette.is-3d { background: linear-gradient(160deg, #2f2b3b, var(--ink)); color: #fff; }

.rv-tete { margin-bottom: 10px; }
.rv-nom { font-family: var(--font-display); font-size: 1.45rem; font-weight: 600; line-height: 1.2; margin: 0 0 8px; }
.rv-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
.rv-prix-base { font-family: var(--font-display); font-weight: 700; font-size: 1.15rem; margin-right: 4px; }
.rv-liens { display: flex; flex-wrap: wrap; gap: 4px 16px; margin-top: 10px; font-size: 0.88rem; }
.rv-liens a { color: var(--accent-deep); font-weight: 600; text-decoration: none; }
.rv-liens a:hover { text-decoration: underline; }
.rv-resume { margin: 0 0 8px; color: var(--ink-soft); }
.rv-description { margin: 0 0 10px; }
.rv-description summary, .rv-concurrents summary { cursor: pointer; font-weight: 600; font-size: 0.9rem; }
.rv-description-texte { white-space: pre-line; font-size: 0.9rem; color: var(--ink-soft); margin-top: 6px; max-height: 340px; overflow-y: auto; }
.rv-tags { display: flex; flex-wrap: wrap; gap: 5px; margin: 0 0 12px; }
.rv-tag { font-size: 0.76rem; padding: 2px 9px; border-radius: 999px; background: var(--paper-alt); color: var(--ink-soft); }
.rv-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); gap: 8px; margin: 0 0 16px; }
@media (hover: none), (max-width: 779px) { .rv-raccourcis { display: none; } }
.rv-stats div { background: var(--paper); border-radius: var(--radius-s); padding: 8px 10px; }
.rv-stats dt { font-size: 0.72rem; color: var(--ink-soft); line-height: 1.25; }
.rv-stats dd { margin: 2px 0 0; font-family: var(--font-display); font-weight: 600; font-size: 1.05rem; }

.rv-titre-bloc { font-family: var(--font-display); font-size: 1rem; font-weight: 600; margin: 0 0 8px; }
.rv-noter, .rv-ia { border-top: 1px solid var(--rule); padding-top: 14px; margin-top: 4px; }
.rv-ia { margin-top: 16px; }
.rv-etoiles { display: flex; gap: 2px; margin-bottom: 8px; }
.rv-etoile {
  width: 46px; height: 46px; border: 0; background: none; padding: 0; cursor: pointer;
  font-size: 2.1rem; line-height: 1; color: var(--rule); transition: transform 0.12s var(--ease-snap), color 0.12s ease;
}
.rv-etoile.is-on { color: #e2a33b; }
.rv-etoile.is-survol { color: #efc27a; }
.rv-etoile:active { transform: scale(0.9); }
.rv-etoile:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 10px; }
.rv-commentaire {
  width: 100%; resize: vertical; font: inherit; font-size: 0.92rem; color: var(--ink);
  border: 1.5px solid var(--rule); border-radius: var(--radius-s); padding: 9px 12px; background: var(--surface);
}
.rv-commentaire:focus { outline: none; border-color: var(--accent); box-shadow: var(--focus-ring); }
.rv-noter-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; margin-top: 10px; }
.rv-aide { font-size: 0.84rem; color: var(--ink-soft); margin: 0 0 10px; }
.rv-noter-actions .rv-aide { margin: 0; }

.rv-attente { display: flex; align-items: center; gap: 10px; color: var(--ink-soft); margin: 4px 0; }
.rv-roue { width: 18px; height: 18px; border-radius: 50%; border: 2.5px solid var(--rule); border-top-color: var(--accent); animation: rv-tourne 0.9s linear infinite; }
@keyframes rv-tourne { to { transform: rotate(360deg); } }
.rv-erreur { margin: 0 0 10px; }
.rv-ia-tete { display: flex; gap: 14px; align-items: flex-start; margin-bottom: 10px; }
.rv-score {
  flex: 0 0 64px; height: 64px; border-radius: 50%; display: flex; align-items: baseline; justify-content: center;
  padding-top: 14px; color: #fff; font-family: var(--font-display);
}
.rv-score strong { font-size: 1.6rem; line-height: 1; }
.rv-score span { font-size: 0.78rem; opacity: 0.85; }
.rv-score.is-bon, .rv-jauge .is-bon { background: var(--sage); }
.rv-score.is-moyen, .rv-jauge .is-moyen { background: var(--accent); }
.rv-score.is-faible, .rv-jauge .is-faible { background: var(--danger); }
.rv-verdict { margin: 0 0 4px; font-weight: 500; }
.rv-meta-ia { margin: 0; font-size: 0.78rem; color: var(--ink-faint); }
.rv-perimee { margin: 0 0 10px; }
.rv-pastille { font-size: 0.76rem; font-weight: 700; padding: 2px 9px; border-radius: 999px; color: #fff; }
.rv-pastille.is-bon { background: var(--sage); }
.rv-pastille.is-moyen { background: var(--accent); }
.rv-pastille.is-faible { background: var(--danger); }

.rv-axes { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }
.rv-axe { border-radius: var(--radius-s); background: var(--paper); padding: 0 12px; }
.rv-axe summary { display: grid; grid-template-columns: 9.5rem minmax(0, 1fr) 3rem; align-items: center; gap: 10px; padding: 9px 0; cursor: pointer; list-style: none; }
.rv-axe summary::-webkit-details-marker { display: none; }
.rv-axe-nom { font-weight: 600; font-size: 0.9rem; }
.rv-jauge { height: 8px; border-radius: 4px; background: var(--paper-alt); overflow: hidden; }
.rv-jauge span { display: block; height: 100%; border-radius: 4px; }
.rv-axe-note { font-family: var(--font-display); font-weight: 700; text-align: right; }
.rv-axe-note.is-bon { color: var(--sage); }
.rv-axe-note.is-moyen { color: var(--accent-deep); }
.rv-axe-note.is-faible { color: var(--danger); }
.rv-constat { margin: 0 0 8px; font-size: 0.9rem; }
.rv-liste { margin: 0 0 10px; padding-left: 0; list-style: none; font-size: 0.86rem; }
.rv-liste li { position: relative; padding-left: 20px; margin-bottom: 3px; }
.rv-liste.is-plus li::before { content: '+'; position: absolute; left: 4px; color: var(--sage); font-weight: 700; }
.rv-liste.is-moins li::before { content: '–'; position: absolute; left: 4px; color: var(--danger); font-weight: 700; }
.rv-sous-titre { font-family: var(--font-display); font-size: 0.92rem; font-weight: 600; margin: 4px 0 6px; }
.rv-actions { margin: 0 0 12px; padding-left: 20px; font-size: 0.9rem; }
.rv-actions li { margin-bottom: 7px; }
.rv-prio, .rv-axe-chip { display: inline-block; font-size: 0.7rem; font-weight: 700; padding: 1px 7px; border-radius: 999px; margin-right: 5px; vertical-align: 1px; }
.rv-prio.is-haute { background: var(--danger-soft); color: var(--danger); }
.rv-prio.is-moyenne { background: var(--blush); color: var(--accent-deep); }
.rv-prio.is-basse { background: var(--paper-alt); color: var(--ink-soft); }
.rv-axe-chip { background: var(--sage-soft); color: #4f6d5e; font-weight: 600; }
.rv-prix { margin: 0 0 4px; font-size: 0.9rem; }
.rv-prix.is-trop_haut strong, .rv-prix.is-trop_bas strong { color: var(--accent-deep); }
.rv-prix.is-juste strong { color: var(--sage); }
.rv-concurrents { margin: 6px 0 10px; }
.rv-concurrents ul { margin: 8px 0 0; padding-left: 18px; font-size: 0.86rem; }
.rv-concurrents li { margin-bottom: 4px; }
.rv-concurrents a { color: var(--accent-deep); }
.rv-ia-pied { display: flex; justify-content: flex-end; }
.rv-fin { text-align: center; padding: 36px 20px; }
@media (max-width: 560px) {
  .rv-carte { padding: 12px; border-radius: var(--radius-m); }
  .rv-axe summary { grid-template-columns: 7.2rem minmax(0, 1fr) 2.6rem; }
  .rv-nom { font-size: 1.25rem; }
}
@media (prefers-reduced-motion: reduce) {
  .rv-carte, .rv-etoile { transition: none; }
  .rv-roue { animation-duration: 2.5s; }
}
