/* ============================================================
   TACTI — Design system (light par défaut, aligné sur la landing :
   blanc, encre, hairlines, vert #10A05A, Inter partout)
   ============================================================ */

/* DM Sans (corps, Google Fonts) + Satoshi (titres, Fontshare) chargées via <link> dans le <head> de chaque page */

:root {
  color-scheme: dark;
  /* Surfaces */
  --bg:          #040B06;
  --bg-elev:     #08120A;
  --surface:     #0B1710;
  --surface-2:   rgba(255,255,255,0.04);
  --surface-3:   rgba(255,255,255,0.08);
  --surface-hi:  rgba(255,255,255,0.13);

  /* Lines */
  --border:        rgba(255,255,255,0.07);
  --border-2:      rgba(255,255,255,0.11);
  --border-strong: rgba(255,255,255,0.22);

  /* Text */
  --text:    #E8F5EC;
  --text-2:  rgba(232,245,236,0.58);
  --text-3:  rgba(232,245,236,0.32);
  --text-on-green: #FFFFFF;

  /* Brand — vivid grass, tuned for dark bg */
  --green:        #22C55E;
  --green-bright: #4ADE80;
  --green-deep:   #16A34A;
  --green-700:    #15803D;
  --green-soft:   rgba(34,197,94,0.13);
  --green-soft-2: rgba(34,197,94,0.22);
  --green-glow:   rgba(34,197,94,0.24);

  /* Étoiles de notation : pleines en vert, vides en vert atténué (jamais de gris,
     jamais d'ambre). Une seule source de vérité pour toutes les pages. */
  --star:     var(--green);
  --star-off: rgba(34,197,94,0.28);

  /* Secondary accents */
  --orange:    #FB923C;
  --orange-soft: rgba(251,146,60,0.18);
  --red:       #F87171;
  --blue:      #60A5FA;
  --yellow:    #FCD34D;

  /* Pitch */
  --pitch:       #2f8f4e;
  --pitch-2:     #2b8649;
  --pitch-line:  rgba(255,255,255,1);

  /* Radii */
  --r-xs: 6px;
  --r-sm: 8px;
  --r:    10px;
  --r-lg: 14px;
  --r-xl: 18px;
  --r-pill: 999px;

  /* Shadows */
  --shadow-sm: 0 1px 3px rgba(0,0,0,.45);
  --shadow:    0 2px 8px rgba(0,0,0,.4), 0 12px 32px rgba(0,0,0,.5);
  --shadow-lg: 0 8px 24px rgba(0,0,0,.55), 0 32px 64px rgba(0,0,0,.65);
  --ring:      0 0 0 3px var(--green-soft-2);
  /* Chip neumorphique : surlignage interne en bas + halo doux */
  --shadow-chip: inset 0 -2px 0 0 rgba(0,0,0,.28), 0 1.2px 6px 0 rgba(0,0,0,.32);

  /* Type */
  --font: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-title: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace;

  --sidebar-w: 256px;          /* largeur du volet de navigation */
  --topbar-h: 70px;
}

/* ============================================================
   Light theme
   ============================================================ */
[data-theme="light"] {
  color-scheme: light;
  /* Aligné sur la landing : fond blanc, encre quasi-noire, vert gazon en accent */
  /* Aligné sur la nouvelle landing (2026-07) : blanc, encre #131416, hairlines, vert #10A05A */
  --bg:          #FFFFFF;
  --bg-elev:     #FFFFFF;
  --surface:     #FFFFFF;
  --surface-2:   #F4F5F6;
  --surface-3:   #ECEEF0;
  --surface-hi:  #E4E6E9;
  --border:        #E9EAEC;
  --border-2:      #DFE1E4;
  --border-strong: rgba(19,20,22,0.24);
  --text:    #131416;
  --text-2:  #63676E;
  --text-3:  #9A9EA5;
  --text-on-green: #FFFFFF;
  --green:        #10A05A;
  --green-bright: #0B7A44; /* utilisé comme texte/icône d'accent : volontairement foncé pour rester lisible sur clair */
  --green-deep:   #0B7A44;
  --green-700:    #085F35;
  --green-soft:   #EAF7F0;
  --green-soft-2: rgba(16,160,90,0.16);
  --green-glow:   rgba(16,160,90,0.18);
  --star:     var(--green);
  --star-off: #C3E7D6;
  --pitch:       #38A55E;
  --pitch-2:     #41AE67;
  /* Anneau de focus clavier sur l'accent bleu de la DA (il était vert) */
  --ring:      0 0 0 3px rgba(67,135,244,.35);
  --shadow-sm: 0 1px 2px rgba(19,20,22,.04);
  --shadow:    0 1px 2px rgba(19,20,22,.04), 0 12px 32px -12px rgba(19,20,22,.10);
  --shadow-lg: 0 2px 6px rgba(19,20,22,.04), 0 30px 70px rgba(19,20,22,.12);
  --shadow-chip: inset 0 -2px 0 0 rgba(19,20,22,.05), 0 1.2px 6.3px 0 rgba(19,20,22,.05);
}
[data-theme="light"] .sidebar {
  background: #fff;
  backdrop-filter: none;
}
[data-theme="light"] .sidebar::before { display: none; }
[data-theme="light"] .topbar { background: rgba(255,255,255,0.88); }
[data-theme="light"] .lp-nav { background: rgba(255,255,255,0.88); }
[data-theme="light"] .card,
[data-theme="light"] .pcard { background: #fff; border-color: #ededed; backdrop-filter: none; --pcard-fade: #fff; }
[data-theme="light"] .pcard:hover { border-color: #dcdcde; box-shadow: var(--shadow); background: #fff; }
/* Jauge de difficulté : niveau neutre. En vert elle se lisait comme un signal
   « bon », alors qu'elle mesure une exigence. */
[data-theme="light"] .diff i { background: #ededed; }
[data-theme="light"] .diff[data-level="1"] i:nth-child(-n+1),
[data-theme="light"] .diff[data-level="2"] i:nth-child(-n+2),
[data-theme="light"] .diff[data-level="3"] i:nth-child(-n+3) { background: #18181b; }
[data-theme="light"] .btn-soft { background: #f5f5f5; color: #18181b; border-color: transparent; }
[data-theme="light"] .btn-soft:hover { background: #ececec; border-color: transparent; }
/* background-color (pas le raccourci background) : sinon on réinitialise
   background-repeat/position et le chevron du <select> se répète en mosaïque */
[data-theme="light"] .input,
[data-theme="light"] .textarea,
[data-theme="light"] .select { background-color: var(--surface); }
/* Focus des champs : simple bordure encre, comme .bd-input:focus de la page
   profil. Pas de halo en plus, la DA n'en met pas sur les saisies. */
[data-theme="light"] .input:focus,
[data-theme="light"] .textarea:focus,
[data-theme="light"] .select:focus { background-color: #fff; border-color: #18181b; box-shadow: none; }
[data-theme="light"] .select { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 256 256'%3E%3Cpath fill='%236E776B' d='m213.66 101.66l-80 80a8 8 0 0 1-11.32 0l-80-80a8 8 0 0 1 11.32-11.32L128 164.69l74.34-74.35a8 8 0 0 1 11.32 11.32'/%3E%3C/svg%3E"); }
[data-theme="light"] .search input:focus { border-color: #18181b; background-color: #fff; box-shadow: none; }
[data-theme="light"] .seg { background: var(--surface-2); }
[data-theme="light"] .seg button.active { background: var(--surface-hi); }
[data-theme="light"] .seg button:hover { background: var(--surface-3); }
[data-theme="light"] .fchip { background: #fff; border-color: #ededed; color: #747476; font-weight: 500; }
[data-theme="light"] .fchip:hover { background: #fff; border-color: #dcdcde; }
[data-theme="light"] .userchip .ava { background: var(--surface-hi); border: none; color: var(--text); }
[data-theme="light"] .userchip:hover { background: var(--surface-2); }
[data-theme="light"] .pricing-card { background: var(--surface); backdrop-filter: none; }
[data-theme="light"] .pricing-card.feature { background: linear-gradient(180deg,rgba(74,222,110,.05),transparent 40%),var(--surface); }
[data-theme="light"] .window .chrome { background: var(--surface); }
[data-theme="light"] .window .chrome .url { background: var(--bg); }

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* Réserve en permanence la place de la barre de défilement : sans ça, passer
   d'une page courte (sans scroll) à une page longue (avec scroll) décale tout
   le contenu horizontalement, d'où le « saut » à chaque changement de page. */
html { scrollbar-gutter: stable; }
/* Empêche l'inflation automatique du texte (Safari iOS, webviews, Android) :
   sans ça, les libellés dimensionnés en cqw sur le terrain (numéros, étiquettes
   de zone, cotes) grossissent tout seuls selon l'appareil. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-size: 15px;
  line-height: 1.5;
  letter-spacing: -0.011em;
}

h1, h2, h3, h4 { margin: 0; font-family: var(--font-title); font-weight: 600; letter-spacing: -0.025em; line-height: 1.08; text-wrap: balance; }
p { margin: 0; text-wrap: pretty; }
a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; }
img { display: block; max-width: 100%; }
::selection { background: var(--green-soft-2); color: var(--text); }

/* Scrollbars */
* { scrollbar-width: thin; scrollbar-color: var(--surface-3) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: 10px; border: 2px solid transparent; background-clip: padding-box; }
*::-webkit-scrollbar-thumb:hover { background: var(--surface-hi); background-clip: padding-box; }

/* ---------- Icons ---------- */
.icon { width: 18px; height: 18px; stroke-width: 2; flex: none; }
.icon-sm { width: 15px; height: 15px; }
.icon-lg { width: 22px; height: 22px; }
[data-lucide] { width: 18px; height: 18px; }

/* ---------- Utility ---------- */
.mono { font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.04em; text-transform: uppercase; }
.muted { color: var(--text-2); }
.faint { color: var(--text-3); }
.row { display: flex; align-items: center; }
.col { display: flex; flex-direction: column; }
.gap-2 { gap: 8px; } .gap-3 { gap: 12px; } .gap-4 { gap: 16px; } .gap-6 { gap: 24px; }
.grow { flex: 1; }
.center { display: flex; align-items: center; justify-content: center; }
.wrap { flex-wrap: wrap; }

/* ============================================================
   Buttons
   ============================================================ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 40px; padding: 0 16px;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  font-size: 14px; font-weight: 600; letter-spacing: -0.01em;
  white-space: nowrap; user-select: none;
  transition: background .15s, border-color .15s, transform .08s, box-shadow .15s, color .15s;
}
.btn:active { transform: translateY(1px); }
.btn .icon, .btn [data-lucide] { width: 16px; height: 16px; }

/* Focus clavier cohérent sur les éléments interactifs principaux.
   Les inputs ont déjà leur ring via .input:focus ; ici on couvre les
   boutons, la nav et les chips qui n'avaient que l'outline navigateur. */
.btn:focus-visible,
.nav-item:focus-visible,
.fchip:focus-visible,
.userchip:focus-visible,
.seg button:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}

.btn-primary { background: var(--green); color: var(--text-on-green); box-shadow: 0 1px 0 rgba(255,255,255,.18) inset, 0 6px 20px var(--green-glow); }
.btn-primary:hover { background: var(--green-bright); box-shadow: 0 1px 0 rgba(255,255,255,.18) inset, 0 8px 28px var(--green-glow); }

.btn-ghost { background: transparent; color: var(--text); border-color: var(--border-2); }
.btn-ghost:hover { background: var(--surface-2); border-color: var(--border-strong); }

.btn-soft { background: rgba(255,255,255,0.06); color: var(--text); border-color: var(--border); }
.btn-soft:hover { background: rgba(255,255,255,0.10); border-color: var(--border-2); }

.btn-quiet { background: transparent; color: var(--text-2); }
.btn-quiet:hover { background: var(--surface-2); color: var(--text); }

/* Danger : pilule rouge pâle du bouton « Résilier » (page abonnement) */
.btn-danger { background: #fee7e7; color: #e92f2f; border-color: transparent; }
.btn-danger:hover { background: #fdd5d5; border-color: transparent; }

.btn-sm { height: 32px; padding: 0 12px; font-size: 13px; border-radius: var(--r-xs); }
.btn-lg { height: 50px; padding: 0 24px; font-size: 16px; border-radius: var(--r); }
.btn-icon { width: 40px; padding: 0; }
.btn-icon.btn-sm { width: 32px; }

/* ============================================================
   Badges / tags / chips
   ============================================================ */
.tag {
  display: inline-flex; align-items: center; gap: 6px; width: fit-content;
  height: 24px; padding: 0 10px;
  border-radius: var(--r-pill);
  background: var(--surface); color: var(--text-2);
  border: .75px solid var(--border-2);
  box-shadow: var(--shadow-chip);
  font-size: 12px; font-weight: 500; letter-spacing: 0.01em; white-space: nowrap;
}
.tag-green { background: var(--green-soft); color: var(--green-bright); border-color: var(--green-soft-2); }
.tag-cat   { background: var(--surface); color: var(--text); font-family: var(--mono); font-size: 11px; letter-spacing: .04em; }

/* difficulty meter */
.diff { display: inline-flex; align-items: center; gap: 4px; }
.diff i { width: 5px; height: 5px; border-radius: 50%; background: var(--surface-hi); }
.diff[data-level="1"] i:nth-child(-n+1),
.diff[data-level="2"] i:nth-child(-n+2),
.diff[data-level="3"] i:nth-child(-n+3) { background: var(--green); }
.diff-label { font-size: 12px; font-weight: 600; color: var(--text-2); font-variant-numeric: tabular-nums; }

/* meta inline (clock / users) */
.meta { display: inline-flex; align-items: center; gap: 5px; color: var(--text-2); font-size: 13px; font-weight: 500; font-variant-numeric: tabular-nums; }
.meta .icon, .meta [data-lucide] { width: 14px; height: 14px; color: var(--text-3); }

/* ============================================================
   Inputs
   ============================================================ */
.field { display: flex; flex-direction: column; gap: 7px; }
.field > label { font-size: 13px; font-weight: 600; color: var(--text-2); }
.input, .textarea, .select {
  width: 100%;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border-2);
  color: var(--text);
  border-radius: var(--r-sm);
  padding: 11px 13px;
  font-family: inherit; font-size: 14px;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.input::placeholder, .textarea::placeholder { color: var(--text-3); }
.input:focus, .textarea:focus, .select:focus { outline: none; border-color: var(--green); box-shadow: var(--ring); background-color: rgba(255,255,255,0.07); }
.textarea { resize: vertical; min-height: 84px; line-height: 1.55; }
.select { appearance: none; cursor: pointer; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 256 256'%3E%3Cpath fill='%23A8C4AE' d='m213.66 101.66l-80 80a8 8 0 0 1-11.32 0l-80-80a8 8 0 0 1 11.32-11.32L128 164.69l74.34-74.35a8 8 0 0 1 11.32 11.32'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; padding-right: 36px; }

/* ── Chip input ────────────────────────────────────────────────
   Champ à valeurs multiples monté par chip-input.js : on valide
   d'une virgule ou d'Entrée, chaque valeur devient un jeton. */
.chip-input {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  border: 1px solid #ededed; border-radius: var(--r-sm);
  padding: 6px 10px; background: #fff; min-height: 40px; cursor: text;
  transition: border-color .15s;
}
.chip-input:hover { border-color: #dcdcde; }
.chip-input:focus-within { border-color: #18181b; }
.chip-input__chips { display: contents; }
.chip-input__chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 6px 2px 10px; border-radius: 9999px;
  background: #eaeefe; color: #4387f4;
  font-size: 12px; font-weight: 500; white-space: nowrap;
}
.chip-input__rm {
  cursor: pointer; opacity: .7; display: flex; align-items: center;
  padding: 2px; border: none; background: none; color: inherit; line-height: 1;
  border-radius: 50%;
}
.chip-input__rm:hover { opacity: 1; }
.chip-input__rm:focus-visible { outline: none; box-shadow: var(--ring); opacity: 1; }
/* Mode révélation (option revealRm) : pour des jetons d'un ou deux caractères,
   une croix permanente double la largeur du jeton pour rien. Elle n'apparaît
   qu'au clic sur le jeton visé. Le jeton garde un padding symétrique au repos
   et rouvre à droite quand la croix sort — pas de fondu d'opacité, la croix
   est là ou elle n'est pas (cf. DA). */
.chip-input--reveal .chip-input__chip {
  padding: 2px 10px; cursor: pointer;
  transition: background .12s, padding .12s;
}
.chip-input--reveal .chip-input__chip:hover { background: #dfe5fd; }
.chip-input--reveal .chip-input__chip:focus-visible { outline: none; box-shadow: var(--ring); }
.chip-input--reveal .chip-input__rm { display: none; }
.chip-input--reveal .chip-input__chip.is-open { padding: 2px 6px 2px 10px; background: #dfe5fd; }
.chip-input--reveal .chip-input__chip.is-open .chip-input__rm { display: flex; }
.chip-input__field {
  border: none; outline: none; background: transparent;
  font-family: inherit; font-size: 13px; color: var(--text);
  min-width: 80px; flex: 1; padding: 0;
}
.chip-input__field::placeholder { color: var(--text-3); }
/* Maximum atteint : le champ ne sert plus à rien, on le retire du flux plutôt
   que de laisser taper dans le vide. */
.chip-input.is-full .chip-input__field { display: none; }

/* ── Number field ──────────────────────────────────────────────
   Choix de nombre unifié : groupe [ − | valeur | + ] monté par
   number-field.js sur les input[type=number]. Le champ garde son
   id et ses écouteurs, les boutons émettent input + change. */
.nf {
  display: inline-flex; align-items: stretch; flex: none;
  height: 42px;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border-2);
  border-radius: var(--r-sm);
  overflow: hidden;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.nf:focus-within { border-color: var(--green); box-shadow: var(--ring); }
[data-theme="light"] .nf { background: var(--surface); }
/* Même focus encre que les autres saisies de la DA */
[data-theme="light"] .nf:focus-within { border-color: #18181b; box-shadow: none; }
.nf > button {
  width: 36px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border: none; background: transparent; color: var(--text-2);
  font-family: inherit; font-size: 17px; line-height: 1; padding: 0;
  cursor: pointer; user-select: none; -webkit-user-select: none; touch-action: manipulation;
  transition: background .13s, color .13s;
}
.nf > button:hover { background: var(--surface-2); color: var(--text); }
.nf > button:active { background: var(--surface-3); }
.nf > button:disabled { color: var(--text-3); background: transparent; cursor: default; opacity: .5; }
.nf > .nf-dec { border-right: 1px solid var(--border); }
.nf > .nf-inc { border-left: 1px solid var(--border); }
.nf input.nf-input {
  width: 48px; min-width: 0; flex: 1 1 auto; height: 100% !important;
  border: none !important; background: transparent !important; box-shadow: none !important;
  border-radius: 0; padding: 0 4px; text-align: center;
  color: var(--text); font-family: inherit; font-size: 14px; font-weight: 600;
  font-variant-numeric: tabular-nums;
  appearance: textfield; -moz-appearance: textfield;
}
.nf input.nf-input::-webkit-outer-spin-button,
.nf input.nf-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.nf input.nf-input:focus { outline: none; }
/* Variante compacte (barres d'outils, lignes denses) */
.nf.nf-sm { height: 29px; border-radius: 7px; }
.nf.nf-sm > button { width: 27px; font-size: 14px; }
.nf.nf-sm input.nf-input { width: 40px; font-size: 12px; }

/* ── Champ liste (list-field.js) ───────────────────────────────
   Remplace les textarea « une par ligne » : une carte à rangées
   numérotées, même dessin que les consignes d'une fiche procédé.
   Le textarea d'origine reste dans le DOM, masqué. */
.lf-src { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); border: 0; }
.lf {
  border: 1px solid #ededed; border-radius: 14px;
  background: #fff; overflow: hidden;
  transition: border-color .12s;
}
.lf:focus-within { border-color: #dcdcde; }
.lf-row { display: flex; align-items: flex-start; gap: 9px; padding: 8px 8px 8px 10px; border-bottom: 1px solid #ededed; }
.lf-row:last-child { border-bottom: none; }
/* Numéro : badge « Étape » de la fiche, pilule blanche à texte bleu */
.lf-num {
  width: 22px; height: 22px; flex: none; margin-top: 2px;
  border-radius: 9999px; background: #fff; border: 1px solid #ededed;
  color: #4387f4; font-size: 11.5px; font-weight: 500;
  display: flex; align-items: center; justify-content: center;
  font-variant-numeric: tabular-nums;
}
/* Le champ n'a pas de cadre : c'est la rangée qui fait l'objet */
.lf-input {
  flex: 1; min-width: 0; border: none; outline: none; background: none;
  resize: none; overflow: hidden; padding: 3px 0;
  font-family: inherit; font-size: 13.5px; line-height: 20px; color: #18181b;
}
.lf-input::placeholder { color: #9a9ea5; }
.lf-acts { display: flex; align-items: center; gap: 1px; flex: none; opacity: 0; transition: opacity .12s; }
.lf-row:hover .lf-acts, .lf-row:focus-within .lf-acts { opacity: 1; }
.lf-btn {
  width: 24px; height: 24px; flex: none; padding: 0;
  border: none; background: none; border-radius: 7px;
  color: #9a9ea5; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .12s, color .12s;
}
.lf-btn svg { width: 14px; height: 14px; }
.lf-btn:hover { background: #f5f5f5; color: #18181b; }
.lf-btn.lf-del:hover { background: #fee7e7; color: #e92f2f; }
.lf-btn:disabled { opacity: .32; cursor: default; }
.lf-btn:disabled:hover { background: none; color: #9a9ea5; }
.lf-add {
  display: flex; align-items: center; gap: 7px; width: 100%;
  padding: 9px 12px; border: none; border-top: 1px solid #ededed;
  background: none; color: #747476; cursor: pointer; text-align: left;
  font-family: inherit; font-size: 13px; font-weight: 500;
  transition: background .12s, color .12s;
}
.lf-add svg { width: 14px; height: 14px; }
.lf-add:hover { background: #fafafa; color: #18181b; }
/* Une seule rangée vide : le trait au-dessus du bouton ferait doublon */
.lf-rows:not(:has(.lf-row + .lf-row)) + .lf-add { border-top-color: #f5f5f5; }

/* ── Barre de recherche ────────────────────────────────────────
   Pilule sobre : bordure fine, icône à gauche, anneau vert au focus.
   Aucune animation d'ouverture, le champ est toujours prêt à saisir. */
.search {
  position: relative;
  display: flex; align-items: center;
  width: min(352px, 100%); height: 40px;
}
.search .icon,
.search > svg {
  position: absolute; left: 15px;
  width: 17px; height: 17px; flex: none;
  color: var(--text-3); pointer-events: none;
  transition: color .12s;
}
.search input {
  width: 100%; height: 100%;
  padding: 0 16px 0 42px;
  border: 1px solid var(--border-2); border-radius: var(--r-pill);
  background: var(--surface); color: var(--text);
  font-family: inherit; font-size: 14px; outline: none;
  transition: border-color .12s, box-shadow .12s, background-color .12s;
}
.search input::placeholder { color: var(--text-3); }
.search:hover input { border-color: var(--border-strong); }
.search input:focus {
  border-color: var(--green);
  box-shadow: var(--ring);
  background-color: var(--surface-2);
}
.search:focus-within .icon,
.search:focus-within > svg { color: var(--green); }
/* Champ de type search : pas de croix native, on garde la pilule propre */
.search input::-webkit-search-cancel-button,
.search input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }

/* segmented control */
.seg { display: inline-flex; background: rgba(255,255,255,0.05); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 3px; gap: 2px; }
.seg button { height: 30px; padding: 0 13px; border: none; background: none; color: var(--text-2); font-size: 13px; font-weight: 600; border-radius: var(--r-xs); transition: background .12s, color .12s; }
.seg button:hover { color: var(--text); background: rgba(255,255,255,0.06); }
.seg button.active { background: rgba(255,255,255,0.12); color: var(--text); }

/* ============================================================
   Cards
   ============================================================ */
.card {
  background: rgba(14,31,20,0.75);
  border: 1px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
.card-pad { padding: 18px; }

/* Procédé card */
.pcard {
  background: rgba(14,31,20,0.75);
  border: 1px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
  cursor: pointer;
  transition: border-color .18s, transform .18s, box-shadow .18s, background .18s;
  display: flex; flex-direction: column;
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
.pcard:hover { border-color: rgba(34,197,94,0.35); transform: translateY(-4px); box-shadow: 0 8px 32px rgba(0,0,0,.5), 0 0 0 1px rgba(34,197,94,0.18); background: rgba(14,31,20,0.95); }
/* overflow:hidden : le flou et le zoom du schéma au survol débordent sinon
   sur le corps de la carte, le halo n'étant pas borné par l'élément. */
.pcard .preview { position: relative; overflow: hidden; box-shadow: inset 0 -1px 0 0 rgba(0,0,0,.28); }

/* ── Actions au survol ──────────────────────────────────────────
   Au survol de la carte, un voile et les actions apparaissent sur le
   schéma : partager, dupliquer, favori. Modifier et supprimer n'y sont
   pas, elles vivent sur la fiche du procédé. */
.pcard .preview-actions {
  position: absolute; inset: 0; z-index: 5;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,.22);
  opacity: 0; pointer-events: none;
  transition: opacity .18s ease;
}
/* Actions secondaires au coin : le centre du schéma reste libre, le clic
   sur la carte (n'importe où) ouvre la fiche du procédé. */
.pcard .pv-side { position: absolute; top: 9px; right: 9px; display: flex; gap: 6px; }
@media (hover: hover) {
  .pcard:hover .preview-actions { opacity: 1; pointer-events: auto; }
}
.pcard .pv-act {
  width: 30px; height: 30px; border-radius: 50%;
  border: none; background: rgba(255,255,255,.94);
  color: #16241A; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 2px 10px rgba(0,0,0,.28);
  transition: background .12s, transform .12s;
}
.pcard .pv-act [data-lucide] { width: 15px; height: 15px; }
.pcard .pv-act:hover { background: #fff; transform: scale(1.08); }
.pcard .pv-act:active { transform: scale(.95); }
.pcard .pv-act.bk.saved { color: #EF4444; }
/* Animation de like : le glyphe Phosphor est un tracé rempli, impossible de
   transiter fill/stroke comme un vrai contour. On superpose donc un cœur
   plein (même contour extérieur que le glyphe) qui grandit avec un ressort
   au like, pendant que l'icône entière fait un petit pop (squash sur le
   wrapper HTML, jamais de scale au repos sur le <svg> : Chromium rastérise
   à 1× un SVG inline transformé, flou en hi-DPI). Pas de fondu d'opacité. */
.pcard .bk .bk-icon { position: relative; display: flex; align-items: center; justify-content: center; }
.pcard .bk .bk-heart-fill {
  position: absolute; inset: 0; width: 100%; height: 100%;
  color: #EF4444; pointer-events: none;
  transform: scale(0); transform-origin: center;
  transition: transform .18s cubic-bezier(.4,0,.2,1);
}
.pcard .bk.saved .bk-heart-fill { transform: none; transition: transform .35s cubic-bezier(.34,1.96,.64,1); }
.pcard .bk.just-liked .bk-icon { animation: bk-like-pop .35s cubic-bezier(.34,1.96,.64,1); }
@keyframes bk-like-pop { 0% { transform: scale(1); } 30% { transform: scale(.82); } 100% { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) {
  .pcard .bk .bk-icon { animation: none !important; }
  .pcard .bk .bk-heart-fill { transition: none !important; }
}
/* Avatar de l'éducateur qui a partagé le procédé (coin haut-gauche). */
.pcard .preview .author-pin {
  position: absolute; top: 10px; left: 10px; z-index: 4;
  width: 30px; height: 30px; border-radius: 50%; overflow: hidden;
  background: rgba(8,12,8,.55); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  border: 1.5px solid rgba(255,255,255,.6);
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: 12.5px; font-weight: 700; line-height: 1;
  box-shadow: 0 2px 8px rgba(0,0,0,.4);
}
.pcard .preview .author-pin img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pcard { --pcard-fade: #0E1F14; }
.pcard .body { padding: 12px 14px 14px; display: flex; flex-direction: column; gap: 6px; flex: 1; }
/* Titre clampé sur 2 lignes avec une hauteur réservée : les cartes gardent
   la même structure quelle que soit la longueur du titre. */
.pcard h3 {
  font-size: 15px; font-weight: 600; line-height: 1.3; text-wrap: balance;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; min-height: calc(1.3em * 2);
}
/* Tags sur une seule ligne, surplus masqué par un fondu à droite plutôt
   qu'un retour à la ligne qui fait varier la hauteur des cartes. */
.pcard .tagrow {
  display: flex; gap: 5px; flex-wrap: nowrap; overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
          mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent);
}
.pcard .card-author { font-size: 11px; color: var(--text-3); font-weight: 600; display: flex; align-items: center; gap: 4px; }
/* Footer : infos à gauche, actions en overlay à droite. Les actions
   apparaissent au survol par un simple fondu, sans agrandir la carte, donc
   plus aucun reflow de la grille quand on survole une carte. */
.pcard .card-footer { position: relative; display: flex; align-items: center; min-height: 28px; margin-top: auto; padding-top: 4px; }
.pcard .card-info { display: flex; align-items: center; gap: 10px; flex-wrap: nowrap; overflow: hidden; flex: 1; min-width: 0; }
.pcard .card-actions {
  position: absolute; right: 0; top: 50%;
  transform: translateY(-50%) translateX(6px);
  display: flex; gap: 4px; align-items: center; padding-left: 20px;
  background: linear-gradient(to right, transparent, var(--pcard-fade) 24%);
  opacity: 0; pointer-events: none;
  transition: opacity .15s ease, transform .15s cubic-bezier(0.2, 0, 0, 1);
}
.pcard:hover .card-actions { opacity: 1; transform: translateY(-50%) translateX(0); pointer-events: auto; }

/* ============================================================
   Pitch (terrain) — see pitch.js
   ============================================================ */
.pitch {
  position: relative;
  aspect-ratio: 3 / 2;
  width: 100%;
  background: var(--pitch);
  container-type: inline-size;
  overflow: hidden;
  user-select: none;
  -webkit-user-select: none;
}
/* Safari sélectionne parfois le texte pendant un drag malgré user-select:none ;
   la sélection était peinte avec ::selection (color: var(--text), quasi noir en
   thème clair) → numéros de pions et textes semblaient passer en noir pendant
   le déplacement. On neutralise le rendu de sélection dans le terrain, sauf en
   édition de texte où une sélection visible reste nécessaire. */
.pitch ::selection { background: transparent; color: currentColor; }
.pitch .tok-text[contenteditable="true"]::selection { background: rgba(23,163,74,0.6); color: #fff; }
.pitch.flat svg.lines .stripe { display: none; }
.pitch svg.lines { position: absolute; inset: 0; width: 100%; height: 100%; display: block; pointer-events: none; }
/* pointer-events:none sur la racine SVG : sinon le calque couvre tout le terrain
   et intercepte les clics destinés aux zones en dessous. Les traits de détection
   des flèches (pointer-events:stroke) et les polygones (pointer-events:all)
   réactivent les events là où il le faut. */
.pitch svg.arrows { position: absolute; inset: 0; width: 100%; height: 100%; display: block; z-index: 2; pointer-events: none; }
.pitch svg.zones-poly { position: absolute; inset: 0; width: 100%; height: 100%; display: block; z-index: 1; pointer-events: none; }
.pitch svg.zones-split { position: absolute; inset: 0; width: 100%; height: 100%; display: block; z-index: 0; pointer-events: none; }
/* Surlignage de la case sélectionnée : overlay au-dessus de tout, contour vert net + halo doux */
.pitch svg.cell-sel-overlay { position: absolute; inset: 0; width: 100%; height: 100%; display: block; z-index: 3; pointer-events: none; }
/* Pilules de cote : au-dessus des tracés/zones/coupelles, sous les pions */
.pitch svg.measures { position: absolute; inset: 0; width: 100%; height: 100%; display: block; z-index: 3; pointer-events: none; }
.cell-sel-overlay polygon {
  fill: rgba(34,197,94,0.12);
  stroke: rgba(52,211,128,0.95);
  stroke-width: 2;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  filter: drop-shadow(0 0 4px rgba(23,163,74,0.55));
  animation: cellSelPulse 2s ease-in-out infinite;
}
/* Respiration douce et symétrique : reste stable même si l'overlay est recréé pendant un drag */
@keyframes cellSelPulse {
  0%, 100% { opacity: 0.88; filter: drop-shadow(0 0 3px rgba(23,163,74,0.4)); }
  50%      { opacity: 1;    filter: drop-shadow(0 0 6px rgba(23,163,74,0.65)); }
}
.pitch.editable .zone-poly { cursor: grab; }
.pitch.editable .zone-poly:active { cursor: grabbing; }
.zone-poly.poly-selected { filter: drop-shadow(0 0 3px rgba(255,255,255,1)) drop-shadow(0 0 9px rgba(23,163,74,0.9)); }
.pitch.freepen { cursor: crosshair; }
.pitch.polygon-mode { cursor: crosshair; }
/* Handles de redimensionnement — design unique : rond vert de 10 px à bord
   blanc, quel que soit l'élément (zones, flèches, sommets). Seules les
   poignées d'intersection/courbure (data-cp : divisions de la flèche
   distance, points de contrôle des tracés) sont bleues. */
.rz-handle {
  position: absolute; z-index: 20;
  width: 10px; height: 10px;
  background: var(--green);
  border: 1.5px solid rgba(255,255,255,0.85);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  transition: filter .1s, transform .1s;
  pointer-events: all;
  cursor: grab;
}
.rz-handle:hover { filter: brightness(1.15); transform: translate(-50%,-50%) scale(1.35); }
.rz-handle:active { cursor: grabbing; }
.rz-handle[data-h="n"], .rz-handle[data-h="s"] { cursor: ns-resize; }
.rz-handle[data-h="e"], .rz-handle[data-h="w"] { cursor: ew-resize; }
.rz-handle[data-cp] { background: var(--blue); }
/* Poignée de rotation (objets orientables : buts, mannequins, etc.) */
.rot-line {
  position: absolute; z-index: 19;
  width: 1.5px;
  background: rgba(255,255,255,0.6);
  pointer-events: none;
}
.rot-handle {
  position: absolute; z-index: 21;
  width: 18px; height: 18px;
  background: rgba(255,255,255,0.95);
  border: 1.5px solid rgba(0,0,0,0.28);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  display: flex; align-items: center; justify-content: center;
  cursor: grab;
  transition: background .1s, transform .1s;
  pointer-events: all;
  touch-action: none;
}
.rot-handle:hover { background: var(--green); transform: translate(-50%,-50%) scale(1.15); }
.rot-handle:active { cursor: grabbing; }
.rot-handle svg { width: 11px; height: 11px; display: block; pointer-events: none; }
/* Coupelles liées au contour d'une zone : décoratives, non interactives */
.tok.zone-cup { pointer-events: none; z-index: 2; }
/* tracers cliquables en mode édition */
.pitch.editable .arrow-hit { cursor: pointer; }
/* Tracé déjà sélectionné : un clic sur son corps ajoute un point de contrôle.
   Le curseur « copy » l'annonce, comme dans l'animateur. Crayon et coupe en
   sont exclus : chez eux le clic n'ajoute rien. */
.pitch.editable .arrow-hit.arrow-selected:not([data-t="pen"]):not([data-t="cut"]) { cursor: copy; }
.pitch.editable .zone { cursor: grab; }
.pitch.editable .zone:active { cursor: grabbing; }
/* sélection tracer */
.arrow-hit.arrow-selected { filter: drop-shadow(0 0 3px rgba(255,255,255,1)) drop-shadow(0 0 9px rgba(23,163,74,0.9)); }
/* sélection zone : rect, polygone, rond et libre partagent .zone-poly.poly-selected */
.pitch .tok {
  position: absolute; transform: translate(-50%, -50%);
  display: flex; align-items: center; justify-content: center;
  z-index: 3;
}
/* ---- Joueur (couleur via --pc, texte via --ptc) ---- */
/* Le div ne fait que positionner et recevoir les clics : disque, anneau, reflet
   et numéro sont tous dessinés dans le SVG (voir playerTokenSVG dans pitch.js).
   Une bordure CSS de 0.17cqw retombait à 0.6 px sur mobile, où le moteur
   l'arrondit au pixel entier côté par côté : l'anneau disparaissait d'un côté
   et le pion paraissait décentré. */
.tok-player {
  /* --tok-boost : boost par terrain réduit (posé par Pitch.render) */
  width: calc(1.83cqw * var(--tok-boost, 1)); height: calc(1.83cqw * var(--tok-boost, 1)); border-radius: 50%;
  color: var(--ptc, #fff);
  display: flex; align-items: center; justify-content: center;
}
.tok-player > .tok-num {
  position: absolute; left: 0; top: 0; width: 100%; height: 100%;
  display: block; overflow: visible; pointer-events: none;
}

/* ---- Cône (SVG) ---- */
.tok-cone-svg { width: 5.5cqw; height: 6.5cqw; overflow: visible; display: block; filter: drop-shadow(0 0.4cqw 0.7cqw rgba(0,0,0,.35)); }

/* ---- Ballon (SVG) ---- */
.tok-ball-svg { width: 5cqw; height: 5cqw; display: block; filter: drop-shadow(0 0.3cqw 0.7cqw rgba(0,0,0,.45)); }

/* ---- Flag ---- */
.tok-flag { width: calc(3.6cqw * var(--tok-boost, 1)); height: calc(3.6cqw * var(--tok-boost, 1)); border-radius: 18%; background: var(--yellow); box-shadow: 0 0.4cqw 0.8cqw rgba(0,0,0,.3); }

/* ---- Mannequin (SVG externe, ratio 549:44) ---- */
.tok-mannequin { width: 11cqw; height: 0.88cqw; }
.tok-mannequin svg { width: 100%; height: 100%; display: block; overflow: visible; }

/* ---- Haie (SVG externe, ratio 606:239) ---- */
.tok-haie { width: 10cqw; height: 3.94cqw; }
.tok-haie svg { width: 100%; height: 100%; display: block; overflow: visible; }

/* ---- Mini-but ---- */
.tok-minibut { width: 15cqw; height: 7.5cqw; }
.tok-minibut svg { width: 100%; height: 100%; display: block; }

/* ---- Porte ---- */
.tok-porte { width: 10cqw; height: 7cqw; }
.tok-porte svg { width: 100%; height: 100%; display: block; overflow: visible; }

/* ---- Poteau de slalom ---- */
.tok-poteau { width: calc(2.8cqw * var(--tok-boost, 1)); height: calc(9cqw * var(--tok-boost, 1)); }
.tok-poteau svg { width: 100%; height: 100%; display: block; overflow: visible; }


/* ---- Arc de rebond ---- */
.tok-arc { width: 13cqw; height: 8cqw; }
.tok-arc svg { width: 100%; height: 100%; display: block; overflow: visible; }

/* ---- Échelle de rythme (SVG externe, ratio 480:1770) ---- */
.tok-echelle { width: 3.53cqw; height: 13cqw; }
.tok-echelle svg { width: 100%; height: 100%; display: block; overflow: visible; }

/* ---- Coupelle & Ballon (SVG externes) ---- */
.tok-coupelle { width: 4.375cqw; height: 3.125cqw; }
.tok-ballon   { width: 4.5cqw;   height: 3.75cqw;  }
.tok-cone     { width: 3.75cqw;  height: 3.75cqw;  }
.tok-cerceau  { width: 3.5cqw;   height: 3.5cqw;   }
.tok-jalon    { width: 7.875cqw; height: 23.625cqw; }
.tok-goal     { width: 4cqw;     height: 11.94cqw; }
.tok-petitbut { width: 1.985cqw; height: 4cqw; }
.tok-petitbut svg { width: 100%; height: 100%; display: block; overflow: visible; }

/* Buts hors terrain (palettes, listes de matériel, exports) : leurs SVG sont
   en tracé 100 % blanc, invisibles sur fond clair. Le sélecteur porte sur la
   source pour couvrir tous les emplacements d'un coup ; le terrain lui-même
   dessine ses buts en <image> dans du SVG, il n'est donc pas concerné et
   garde bien ses traits blancs sur le vert. */
[data-theme="light"] .goal-thumb,
[data-theme="light"] img[src*="goal.svg"],
[data-theme="light"] img[src*="petit but.svg"] { filter: brightness(0) opacity(0.55); }
/* Couchés à l'horizontale dans les vignettes : le tracé est au rapport 1:3, en
   vertical il se réduit à un filet de 5px illisible. La palette du créateur
   porte déjà sa propre rotation en style inline, qui l'emporte sur celle-ci. */
img[src*="goal.svg"], img[src*="petit but.svg"] { transform: rotate(90deg); }

/* ---- Texte libre ---- */
.tok-text {
  font-size: 3.5cqw; font-weight: 700; letter-spacing: -0.02em; line-height: 1.25;
  white-space: pre-wrap;
  color: rgba(255,255,255,0.95); cursor: grab; min-width: 4cqw;
  word-break: break-word;
}
.tok-text[contenteditable="true"] {
  outline: 2px solid rgba(255,255,255,0.55);
  border-radius: 3px;
  cursor: text;
  padding: 2px 4px;
}
/* ---- Zone ---- */
.pitch .zone { position: absolute; z-index: 1; }
.zone-label {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%);
  font-size: 2.275cqw; font-weight: 700; letter-spacing: -0.02em;
  color: rgba(255,255,255,0.95);
  pointer-events: none; white-space: nowrap; font-family: var(--font);
}
/* Les cotes (L/H, rayon, côté, distances) sont rendues en pilules SVG par
   measuresLayer dans pitch.js — plus de spans .zone-dim */

/* ---- Sélection en éditeur ---- */
.pitch.editable .tok { cursor: grab; }
/* Cible de clic étendue dans l'éditeur : les petits objets (coupelle ~14 px,
   cône ~9 px depuis les proportions réelles) gardent une prise d'au moins 2.6cqw
   sans changer leur rendu. max(0px, …) : aucun effet sur les objets déjà grands. */
.pitch.editable .tok::after {
  content: ""; position: absolute;
  top:    calc(-1 * max(0px, (2.6cqw - 100%) / 2));
  bottom: calc(-1 * max(0px, (2.6cqw - 100%) / 2));
  left:   calc(-1 * max(0px, (2.6cqw - 100%) / 2));
  right:  calc(-1 * max(0px, (2.6cqw - 100%) / 2));
}
.pitch.editable .tok:active { cursor: grabbing; }
.tok.selected {
  filter: drop-shadow(0 0 2px rgba(255,255,255,0.98)) drop-shadow(0 0 8px rgba(23,163,74,0.95));
  z-index: 8 !important;
}
.tok.selected::after { content: none; }
.tok.tok-dragging {
  z-index: 10;
  cursor: grabbing !important;
  /* Pas de glow drop-shadow pendant le drag : le filter ne s'invalide pas
     lors d'un déplacement left/top et laisse un résidu à la position de départ */
  filter: none !important;
}

/* ============================================================
   Onglets de variantes — contrôle segmenté (variant-tabs.js)
   Piste posée au-dessus du terrain ; un indicateur glisse sous
   l'onglet actif et se redimensionne à sa largeur.
   ============================================================ */
/* Pilule de la page bilan (.pchip) mais sans piste grise : l'onglet actif est
   une pilule blanche à filet #ededed, les autres ne sont que du texte gris. */
.vtabs {
  position: relative;
  display: inline-flex; align-items: center; gap: 2px;
  max-width: 100%; margin-bottom: 12px;
  background: transparent;
  /* Beaucoup de variantes : la piste défile plutôt que de passer à la ligne,
     l'indicateur ne saurait pas suivre sur deux rangs. */
  overflow-x: auto; scrollbar-width: none;
}
.vtabs::-webkit-scrollbar { display: none; }

.vtabs__ind {
  position: absolute; left: 0; top: 0;
  width: 0; height: 100%;
  background: #fff; border: 1px solid #ededed; border-radius: 9999px;
  box-shadow: 0 1px 2px rgba(19,20,22,.04);
  transition: transform .38s cubic-bezier(.32,.72,0,1), width .38s cubic-bezier(.32,.72,0,1);
  pointer-events: none;
}
/* Premier rendu : pas de glissement depuis la gauche. */
.vtabs.is-init .vtabs__ind { transition: none; }

.vtab {
  position: relative; z-index: 1; flex: none;
  display: inline-flex; align-items: center;
  height: 32px; padding: 0 14px;
  border: none; border-radius: 9999px; background: transparent;
  font-family: var(--font); font-size: 13px; line-height: 20px; letter-spacing: 0;
  /* Graisse constante entre les états : sinon la largeur des onglets change au
     changement de variante et toute la rangée se décale. */
  font-weight: 500;
  color: #747476; white-space: nowrap; cursor: pointer;
  transition: color .18s;
}
.vtab:hover:not(.is-on), .vtab.is-on { color: #18181b; }
.vtab:focus-visible { outline: none; box-shadow: var(--ring); }

/* ============================================================
   Lecteur d'animation (anim-player.js)
   Superposé au terrain : bouton central escamotable + barre
   d'avancement scrubbable.
   ============================================================ */
/* DA de l'app (profil / parrainage / abonnement) : surfaces blanches, filets
   #ededed, pilules, encre #18181b, accent bleu #4387f4. Aucun voile sombre ni
   verre dépoli sur le terrain — le schéma reste lisible en permanence.
   overflow caché : la barre s'escamote en glissant sous le bord bas du terrain. */
.aplay { position: absolute; z-index: 6; pointer-events: auto; overflow: hidden; }

/* Bouton central : pilule ronde encre, la couleur d'action de l'app */
.aplay__btn {
  position: absolute; left: 50%; top: 50%; width: 56px; height: 56px; margin: -28px 0 0 -28px;
  border: none; border-radius: 50%; padding: 0; cursor: pointer;
  background: #18181b; color: #fff;
  display: grid; place-items: center;
  box-shadow: 0 2px 6px rgba(0,0,0,.14), 0 12px 28px -14px rgba(0,0,0,.45);
  /* Escamotage par l'échelle seule : pas de fondu d'opacité. */
  transform: scale(var(--s, 1));
  transition: transform .34s cubic-bezier(.32,1.5,.52,1), background .18s;
}
.aplay__btn svg { width: 21px; height: 21px; display: block; }
/* Centrage optique du triangle, une fois son tracé centré géométriquement
   (voir PLAY dans anim-player.js) : la masse d'un triangle se concentre vers sa
   base, son centre de gravité est donc à gauche du centre de la boîte et la
   forme paraît adossée à gauche. Un demi-pixel vers la droite suffit à
   rééquilibrer ; au-delà, le décalage se voit. */
.aplay:not(.is-playing) .aplay__btn svg { transform: translateX(0.5px); }
.aplay__btn:hover { background: #2f2f33; }
.aplay__btn:active { --s: .94; }
.aplay__btn:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(67,135,244,.5), 0 2px 6px rgba(0,0,0,.14); }
.aplay.is-idle .aplay__btn {
  --s: 0; pointer-events: none;
  transition: transform .22s cubic-bezier(.4,0,.7,.4);
}
/* Au repos (hors survol), les commandes disparaissent : le schéma se lit sans
   surcouche. Escamotage par transform seule, jamais par fondu d'opacité. */
.aplay.is-away .aplay__btn {
  --s: 0; pointer-events: none;
  transition: transform .22s cubic-bezier(.4,0,.7,.4);
}
/* +14px : la barre est décollée du bord, il faut aussi effacer cet écart */
.aplay.is-away .aplay__bar { transform: translateY(calc(100% + 14px)); pointer-events: none; }

/* Pastille « Animé » : seul repère quand les commandes sont escamotées. Reprend
   le badge « Étape » du parrainage (pilule blanche, filet, texte bleu). Coin
   haut droit, hors des zones de jeu ; s'efface dès que le lecteur apparaît. */
.aplay__hint {
  position: absolute; right: 10px; top: 10px;
  display: flex; align-items: center;
  height: 24px; padding: 0 10px; border-radius: 9999px;
  background: #fff; border: 1px solid #ededed; color: #4387f4;
  box-shadow: 0 1px 2px rgba(0,0,0,.05);
  font-size: 12px; font-weight: 500; letter-spacing: 0; text-transform: none;
  line-height: 1; white-space: nowrap; pointer-events: none;
  /* Ancrage centré : la pastille croît et se retire depuis son propre centre */
  transform: scale(var(--h, 0)); transform-origin: 50% 50%;
  transition: transform .22s cubic-bezier(.4,0,.7,.4);
}
.aplay.is-away:not(.is-playing) .aplay__hint {
  --h: 1;
  transition: transform .34s cubic-bezier(.32,1.5,.52,1);
}

/* Barre d'avancement : pilule blanche flottante décollée du bord, comme les
   cartes de l'app. Plus de dégradé sombre en travers du terrain. */
.aplay__bar {
  position: absolute; left: 12px; right: 12px; bottom: 12px; height: 36px;
  display: flex; align-items: center; gap: 11px; padding: 0 14px;
  background: #fff; border: 1px solid #ededed; border-radius: 9999px;
  box-shadow: 0 1px 2px rgba(0,0,0,.04), 0 8px 20px -10px rgba(0,0,0,.3);
  cursor: pointer; touch-action: none;
  transition: transform .26s cubic-bezier(.32,.72,0,1);
}
.aplay__track { position: relative; flex: 1; min-width: 0; height: 4px; border-radius: 99px; background: #ededed; }
.aplay__fill { position: absolute; left: 0; top: 0; bottom: 0; width: 0; border-radius: 99px; background: #4387f4; }
.aplay__knob {
  position: absolute; top: 50%; left: 0; width: 12px; height: 12px; margin: -6px 0 0 -6px;
  border-radius: 50%; background: #4387f4; box-shadow: 0 0 0 2px #fff, 0 1px 4px rgba(0,0,0,.25);
  transform: scale(var(--k, 0)); transition: transform .18s cubic-bezier(.32,.72,0,1);
}
.aplay:hover .aplay__knob, .aplay.is-scrub .aplay__knob { --k: 1; }
/* Minutage : chiffres tabulaires, la largeur ne saute pas à chaque image */
.aplay__time {
  flex: none; font-size: 11.5px; font-weight: 500; color: #747476;
  font-variant-numeric: tabular-nums; line-height: 1; white-space: nowrap;
}
.aplay__bar:focus-visible { outline: none; }
.aplay__bar:focus-visible .aplay__track { box-shadow: 0 0 0 3px rgba(67,135,244,.35); }

/* Terrains étroits (mobile) : barre un peu plus haute pour rester touchable */
@media (max-width: 640px) {
  .aplay__bar { height: 40px; left: 10px; right: 10px; bottom: 10px; }
  .aplay__btn { width: 52px; height: 52px; margin: -26px 0 0 -26px; }
}

/* ============================================================
   App shell
   ============================================================ */
.app { display: grid; grid-template-columns: var(--sidebar-w) 1fr; min-height: 100vh; }

.sidebar {
  position: sticky; top: 0; height: 100vh;
  background: rgba(9,20,13,0.92);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column;
  padding: 20px;
  gap: 6px;
  overflow: hidden;
}
.sidebar::before {
  content: '';
  position: absolute;
  top: -80px; left: -60px;
  width: 300px; height: 300px;
  background: radial-gradient(ellipse, rgba(34,197,94,0.14), transparent 68%);
  pointer-events: none;
  animation: sideGlow 9s ease-in-out infinite alternate;
}
@keyframes sideGlow {
  0%   { transform: translate(0,0) scale(1); opacity: 1; }
  100% { transform: translate(24px,36px) scale(1.2); opacity: .7; }
}
.brand { display: flex; align-items: center; gap: 9px; padding: 6px 8px 16px; color: var(--text); }
/* Filet sous le logo, comme entre les groupes de nav. Scopé à la sidebar : la
   classe .brand sert aussi à la landing et au pied des PDF générés. */
.sidebar .brand {
  margin-bottom: 16px; border-bottom: 1px solid var(--border);
  /* Le filet doit tomber pile sur celui de la barre du haut, sinon les deux
     lignes se croisent en biais à l'angle. La barre mesure --topbar-h bordure
     comprise (box-sizing: border-box), son filet est donc à --topbar-h - 1.
     Ici on part de 20 (retrait haut de la sidebar) + 6 (retrait haut du bloc)
     + 32 (hauteur du logo) = 58, d'où un retrait bas de --topbar-h - 59. */
  padding-bottom: calc(var(--topbar-h) - 59px);
}
.brand-logo { height: 32px; width: auto; flex: none; display: block; }
.brand-mark { width: 32px; height: 32px; flex: none; display: block; }
.brand-name { font-family: var(--font-title); font-size: 20px; font-weight: 800; letter-spacing: -0.04em; color: var(--text); line-height: 1; }
.brand .mark { width: 32px; height: 32px; border-radius: 9px; background: linear-gradient(150deg, var(--green-bright), var(--green-deep)); display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 14px var(--green-glow); flex: none; }
.brand .mark span { width: 13px; height: 13px; border-radius: 50%; background: #fff; box-shadow: 0 0 0 2px rgba(6,33,15,.25) inset; }
.brand .name { font-family: var(--font-title); font-size: 19px; font-weight: 600; letter-spacing: -0.03em; }
.brand .name b { color: var(--green); }

.nav-group { display: flex; flex-direction: column; }
/* Un filet sépare les groupes (design Figma 74:487). */
.nav-group + .nav-group { margin-top: 16px; padding-top: 16px; border-top: 1px solid #ededed; }
.nav-label { font-size: 14px; line-height: 20px; font-weight: 500; letter-spacing: 0; text-transform: none; color: #6f747b; padding: 0 8px 12px; }
.nav-item { display: flex; align-items: center; gap: 8px; height: 32px; padding: 0 12px; border-radius: 9999px; color: #6f747b; font-size: 14px; line-height: 20px; font-weight: 500; letter-spacing: 0; transition: background .14s, color .14s; position: relative; z-index: 1; }
.nav-item .icon, .nav-item [data-lucide] { width: 18px; height: 18px; flex: 0 0 auto; color: #6f747b; transition: color .14s; }
.nav-ic { width: 18px; height: 18px; flex: 0 0 auto; display: flex; align-items: center; justify-content: center; }
.nav-ic svg { width: 100%; height: 100%; display: block; }
.upop-item .nav-ic { color: var(--text-3); transition: color .12s; }
.upop-item:hover .nav-ic { color: var(--text-2); }
.upop-item.danger:hover .nav-ic { color: #ef4444; }
/* Le survol ne dessine pas de pilule : le fond gris est réservé à la page active. */
.nav-item:hover { color: #18181b; }
.nav-item:hover .icon, .nav-item:hover [data-lucide] { color: #18181b; }
/* Actif : pilule gris clair pleine largeur, encre (fond #f5f5f5 du Figma). */
.nav-item.active { background: #f5f5f5; color: #18181b; font-weight: 500; box-shadow: none; }
.nav-item.active .icon, .nav-item.active [data-lucide] { color: #18181b; }
.nav-item .count { margin-left: auto; font-size: 12px; color: var(--text-3); font-weight: 600; font-variant-numeric: tabular-nums; }

.side-cta { margin: 8px 4px 0; }
/* Passer en Pro (comptes free) — même pilule noire que la page parrainage
   (.pr-btn-dark) : fond encre, texte blanc, arrondi complet. L'app est en
   thème clair forcé, les couleurs dures sont voulues. */
.side-pro { padding: 0 4px; margin-bottom: 8px; }
.side-pro-btn {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  height: 32px; padding: 8px 10px; border-radius: 9999px;
  background: #18181b; color: #fff;
  font-size: 14px; line-height: 20px; font-weight: 500;
  text-decoration: none; white-space: nowrap;
  transition: background .15s, scale .14s cubic-bezier(.2,0,0,1);
}
.side-pro-btn:hover { background: #2f2f33; }
.side-pro-btn:active { scale: .96; }
/* Compte à rebours d'essai, au-dessus du bouton. Volontairement sobre : c'est
   un rappel d'échéance, pas une alarme. Il ne vire au rouge à aucun moment,
   l'urgence est portée par le nombre lui-même et par l'écran de fin d'essai. */
.side-trial { display: flex; flex-direction: column; gap: 6px; }
.side-trial-txt {
  font-size: 11.5px; line-height: 15px; font-weight: 500;
  color: var(--text-3); text-align: center;
  letter-spacing: -.1px; white-space: nowrap;
}
/* Pilule noire générique (CTA « encre »), même dessin que .pr-btn-dark de la
   page parrainage — utilisée par les écrans d'upsell (proGateOverlay). */
.btn-ink {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 32px; padding: 0 12px; border: none; border-radius: 9999px;
  background: #18181b; color: #fff;
  font-family: inherit; font-size: 13.5px; font-weight: 500;
  text-decoration: none; cursor: pointer; white-space: nowrap;
  transition: background .15s, scale .14s cubic-bezier(.2,0,0,1);
}
.btn-ink:hover { background: #2f2f33; }
.btn-ink:active { scale: .96; }
/* Pas de filet de séparation : le cadre du bouton profil suffit à détacher le
   pied du reste de la nav, deux traits rapprochés faisaient doublon. */
.side-foot { margin-top: auto; padding-top: 12px; }
.userchip { display: flex; align-items: center; gap: 10px; cursor: pointer; }
.userchip .ava { width: 32px; height: 32px; border-radius: 50%; background: var(--green-soft); border: 1px solid var(--green-soft-2); display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 13px; color: var(--green-bright); flex: none; }

/* ---- Avatar par défaut : ni photo, ni nom d'où tirer des initiales -------
   Une silhouette plutôt qu'un « ? », qui se lisait comme un échec de
   chargement. Le SVG (AVATAR_PH_SVG dans app.js) porte son propre fond et
   remplit toute la boîte : c'est le conteneur qui lui donne sa forme, rond
   dans la sidebar, carré arrondi sur la page profil. */
.ava-ph { display: block; width: 100%; height: 100%; }
.ava-ph-bg  { fill: var(--surface-hi); }
.ava-ph-fig { fill: var(--text-3); }
/* Le chip peint un rond vert derrière ses initiales : il doit s'effacer,
   sinon le liseré et la teinte débordent de la silhouette. */
.userchip .ava.is-ph { background: none; border: none; overflow: hidden; }
/* La pastille auteur est posée sur un terrain : elle garde son fond verre
   dépoli et son liseré blanc, seule la silhouette est reprise en blanc. */
.pcard .preview .author-pin .ava-ph-bg  { fill: none; }
.pcard .preview .author-pin .ava-ph-fig { fill: rgba(255,255,255,.92); }
/* Pastille « vérifié » des comptes Pro, ancrée en bas à droite de l'avatar.
   Le liseré qui la détache de la photo est le `stroke` du blason (voir
   PRO_BADGE_SVG dans app.js) : il épouse les festons, contrairement à un
   box-shadow. Le liseré reprend le fond du chip, opaque dans les deux thèmes. */
.userchip .ava-wrap { position: relative; flex: none; display: flex; }
.userchip .ava-badge { position: absolute; right: -3px; bottom: -2px; width: 15px; height: 15px; pointer-events: none; }
.userchip .ava-badge-seal  { fill: var(--green); stroke: var(--bg-elev); }
.userchip .ava-badge-check { fill: var(--text-on-green); }
/* Les deux lignes sont tronquées, jamais renvoyées à la ligne. Sans ça, un nom
   de club un peu long suivi d'un rôle (« US Saint-Marc Saint-Ouen · Responsable
   technique ») s'étalait sur trois lignes et faisait enfler le chip, qui poussait
   le reste de la barre latérale. Le chip a une hauteur d'avatar, il doit s'y
   tenir quel que soit le contenu.
   Le texte complet reste accessible : app.js pose un attribut title. */
.userchip .nm,
.userchip .sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.userchip .nm { font-size: 13.5px; font-weight: 600; line-height: 1.2; }
.userchip .sub { font-size: 12px; color: var(--text-3); line-height: 1.35; }

/* Le chip profil est un bouton : il ouvre le menu compte (profil, abonnement,
   déconnexion). Dessiné comme un bouton contour (cadre hairline + fond élevé)
   pour qu'on voie au premier coup d'œil que la zone est cliquable — un simple
   survol ne le disait pas. */
.userchip {
  width: 100%; padding: 8px 12px 8px 8px;
  background: var(--bg-elev); border: 1px solid var(--border-2); border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  color: inherit; font: inherit; text-align: left; text-decoration: none;
  transition: background .14s, border-color .14s, scale .14s cubic-bezier(.2,0,0,1);
}
.userchip:hover { background: var(--surface-2); border-color: var(--border-strong); }
.userchip:active { scale: .985; }
/* Chevron du chip : pivote à 180° à l'ouverture (200 ms ease-out, design appica) */
.userchip .caret { margin-left: auto; flex: none; width: 15px; height: 15px; color: var(--text-3); transition: transform .2s ease-out; }
.userchip[aria-expanded="true"] .caret { transform: rotate(180deg); }

/* Menu compte — s'ouvre vers le haut, ancré sur le chip. La sidebar est en
   overflow:hidden : le menu doit rester dans ses bornes, d'où l'ouverture
   au-dessus et non en dessous. */
.user-menu { position: relative; }
.upop {
  position: absolute; bottom: calc(100% + 8px); left: 0; right: 0; z-index: 60;
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg); padding: 6px;
  /* Le panneau émerge du chip (scale + glissement + fondu) et y retourne à la
     fermeture. Sortie volontairement plus courte et plus discrète que l'entrée
     (150 ms ease-in vs 220 ms expo-out) : l'attention part ailleurs, le menu ne
     doit pas la retenir. Exception assumée à la règle « pas de fondu » : sans
     opacité, le panneau restait plein puis disparaissait d'un coup au [hidden]. */
  opacity: 0;
  transform: scale(.96) translateY(8px); transform-origin: bottom center;
  transition: transform .15s ease-in, opacity .15s ease-in;
}
.upop[hidden] { display: none; }
.upop.open {
  opacity: 1; transform: none;
  transition: transform .22s cubic-bezier(.2,0,0,1), opacity .18s cubic-bezier(.2,0,0,1);
}
@media (prefers-reduced-motion: reduce) {
  .upop, .upop.open, .userchip .caret { transition: none; }
}
.upop-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 10px; border: 0; border-radius: var(--r-sm);
  background: none; color: var(--text); font: inherit; font-size: 13.5px; font-weight: 500;
  text-align: left; text-decoration: none; cursor: pointer; transition: background .12s, color .12s;
}
.upop-item [data-lucide] { width: 16px; height: 16px; flex: none; color: var(--text-3); transition: color .12s; }
.upop-item:hover { background: var(--surface-2); }
.upop-item:hover [data-lucide] { color: var(--text-2); }
.upop-item.danger:hover { background: rgba(239,68,68,.10); color: #ef4444; }
.upop-item.danger:hover [data-lucide] { color: #ef4444; }
.upop-sep { height: 1px; margin: 5px 6px; background: var(--border); }

/* main */
.main { display: flex; flex-direction: column; min-width: 0; }
.topbar { position: sticky; top: 0; z-index: 20; height: var(--topbar-h); background: rgba(9,20,13,.88); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 16px; padding: 0 30px; }
.topbar h1 { font-size: 21px; font-weight: 700; }
.topbar .sub { font-size: 13px; color: var(--text-3); margin-top: 2px; }
.content { padding: 30px; }
.content-wide { padding: 0; }

.page-title { display:flex; flex-direction:column; }

/* filter bar */
.filterbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 22px; }
.fchip { display: inline-flex; align-items: center; gap: 7px; height: 38px; padding: 0 13px; border-radius: var(--r-sm); background: rgba(255,255,255,0.04); border: 1px solid var(--border-2); color: var(--text-2); font-size: 13.5px; font-weight: 600; transition: border-color .12s, color .12s, background .12s; }
.fchip:hover { border-color: var(--border-strong); color: var(--text); background: rgba(255,255,255,0.07); }
.fchip .icon, .fchip [data-lucide] { width: 15px; height: 15px; color: var(--text-3); }
.fchip.active { background: var(--green-soft); color: var(--green-bright); border-color: rgba(34,197,94,0.25); }
.fchip.active .icon { color: var(--green); }
.fchip .x { margin-left: 2px; color: var(--text-3); }
.fchip .x:hover { color: var(--text); }

/* grid of cards */
.pgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 18px; }

/* ============================================================
   Landing
   ============================================================ */
.lp { max-width: 1180px; margin: 0 auto; padding: 0 28px; }
.lp-nav { position: sticky; top: 0; z-index: 50; backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); background: rgba(9,20,13,.82); border-bottom: 1px solid var(--border); }
.lp-nav .inner { max-width: 1180px; margin: 0 auto; height: 68px; display: flex; align-items: center; gap: 26px; padding: 0 28px; }
.lp-nav .links { display: flex; gap: 26px; margin-left: 18px; }
.lp-nav .links a { font-size: 14px; font-weight: 600; color: var(--text-2); }
.lp-nav .links a:hover { color: var(--text); }

.glow-top { position: absolute; top: -180px; left: 50%; transform: translateX(-50%); width: 900px; height: 500px; background: radial-gradient(ellipse at center, var(--green-glow), transparent 65%); filter: blur(40px); opacity: .5; pointer-events: none; }

.eyebrow { display: inline-flex; align-items: center; gap: 8px; min-height: 32px; padding: 6px 14px; border-radius: var(--r-pill); background: var(--surface); border: .75px solid var(--border-2); box-shadow: var(--shadow-chip); font-size: 12.5px; font-weight: 500; color: var(--text-2); white-space: nowrap; }
.eyebrow b { color: var(--green); }

.pricing-card { background: rgba(14,31,20,0.75); border: 1px solid var(--border); border-radius: var(--r-lg); padding: 28px; display: flex; flex-direction: column; gap: 18px; backdrop-filter: blur(12px); }
.pricing-card.feature { border-color: rgba(34,197,94,0.35); box-shadow: 0 0 0 1px rgba(34,197,94,0.2), 0 20px 60px rgba(0,0,0,.5); background: linear-gradient(180deg, rgba(34,197,94,0.08), transparent 50%), rgba(14,31,20,0.9); }
.pricing-card .price { font-size: 46px; font-weight: 800; letter-spacing: -0.04em; }
.pricing-card .price small { font-size: 15px; font-weight: 600; color: var(--text-3); letter-spacing: 0; }
.feat-li { display: flex; align-items: flex-start; gap: 10px; font-size: 14.5px; color: var(--text); }
.feat-li .ck { width: 20px; height: 20px; border-radius: 50%; background: var(--green-soft); color: var(--green); display: flex; align-items: center; justify-content: center; flex: none; margin-top: 1px; }
.feat-li .ck .icon { width: 13px; height: 13px; }

.window { border: 1px solid var(--border-2); border-radius: var(--r-lg); overflow: hidden; background: var(--bg-elev); box-shadow: var(--shadow-lg), 0 0 0 1px rgba(255,255,255,0.04); }
.window .chrome { height: 38px; display: flex; align-items: center; gap: 7px; padding: 0 14px; background: rgba(255,255,255,0.04); border-bottom: 1px solid var(--border); }
.window .chrome i { width: 11px; height: 11px; border-radius: 50%; background: var(--surface-hi); }
.window .chrome .url { margin-left: 12px; height: 22px; flex: 1; max-width: 320px; border-radius: 6px; background: rgba(255,255,255,0.05); border: 1px solid var(--border); display: flex; align-items: center; padding: 0 10px; font-size: 11px; color: var(--text-3); font-family: var(--mono); }

/* image placeholder */
.ph { background-color: var(--surface-2); background-image: repeating-linear-gradient(45deg, rgba(255,255,255,.025) 0 10px, transparent 10px 20px); border: 1px dashed var(--border-2); border-radius: var(--r); display: flex; align-items: center; justify-content: center; color: var(--text-3); font-family: var(--mono); font-size: 11px; text-align: center; }

/* dividers */
.hr { height: 1px; background: var(--border); border: none; margin: 0; }

/* misc reveal for landing on-load */
.section { padding: 96px 0; }

/* ============================================================
   Responsive
   ============================================================ */

/* Visibilité conditionnelle, centralisée (les pages la redéfinissaient en
   inline ; on garde le même comportement mais une seule source de vérité). */
.mobile-only { display: none; }
.desktop-only { display: revert; }
@media (max-width: 1000px) {
  .mobile-only { display: inline-flex; }
  .desktop-only { display: none !important; }
}

/* Voile sombre derrière le tiroir de navigation (créé par app.js). */
.nav-scrim {
  position: fixed; inset: 0; z-index: 99;
  background: rgba(0,0,0,.5);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  opacity: 0; pointer-events: none;
  transition: opacity .24s ease;
}
.nav-scrim.show { opacity: 1; pointer-events: auto; }
@media (min-width: 1001px) { .nav-scrim { display: none !important; } }
/* Bloque le défilement du fond quand le tiroir est ouvert. */
body.nav-open { overflow: hidden; }

/* ---- Tablet (≤ 1000px) — sidebar devient un drawer ---- */
@media (max-width: 1000px) {
  .app { grid-template-columns: 1fr; }
  .sidebar {
    position: fixed; left: 0; top: 0;
    width: min(290px, 86vw); height: 100vh; height: 100dvh;
    transform: translateX(-100%);
    transition: transform .26s cubic-bezier(.32,.72,0,1);
    z-index: 100; box-shadow: var(--shadow-lg);
    background: rgba(9,20,13,0.985);
    padding-left: max(14px, env(safe-area-inset-left));
    padding-bottom: max(18px, env(safe-area-inset-bottom));
    overscroll-behavior: contain;
    /* La base met overflow:hidden ; ici le contenu peut dépasser l'écran,
       il faut pouvoir défiler jusqu'au profil en bas. */
    overflow-x: hidden; overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  /* Sans ça, flexbox compresse les groupes de nav au lieu de laisser
     le tiroir défiler. */
  .sidebar > * { flex-shrink: 0; }
  /* En tiroir, la sidebar recouvre la page : il n'y a plus de filet de barre du
     haut à rattraper, on revient à un retrait confortable (le calcul tomberait
     à zéro sous 640px, où --topbar-h passe à 58). */
  .sidebar .brand { padding-bottom: 16px; }
  .sidebar.open { transform: none; }
  .lp-nav .links { display: none; }
  .topbar { padding: 0 20px; gap: 10px; }
  .topbar .sub { display: none; }
  /* Le titre ne doit jamais pousser les actions hors de l'écran. */
  .topbar .page-title, .topbar h1 { min-width: 0; }
  .topbar h1 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* Filet de sécurité : aucune page ne doit défiler horizontalement. Le
     contenu trop large est rogné au bord de l'écran (overflow:clip ne crée
     pas de conteneur de défilement et n'affecte pas le topbar sticky). Les
     rangées volontairement défilables ont leur propre overflow-x:auto. */
  .main { overflow-x: clip; }
}

/* ---- Mobile (≤ 640px) ---- */
@media (max-width: 640px) {
  :root { --topbar-h: 58px; }
  .topbar {
    padding: 0 12px;
    padding-left: max(12px, env(safe-area-inset-left));
    padding-right: max(12px, env(safe-area-inset-right));
    gap: 8px; height: 58px;
  }
  .topbar h1 { font-size: 17px; }
  .content {
    padding: 16px;
    padding-left: max(16px, env(safe-area-inset-left));
    padding-right: max(16px, env(safe-area-inset-right));
  }
  .pgrid { grid-template-columns: 1fr; gap: 12px; }
  .pcard h3 { font-size: 14px; }
  .filterbar { gap: 6px; }
  .fchip { height: 34px; padding: 0 11px; font-size: 12.5px; }

  /* Boutons de topbar en icône seule pour tenir sur une ligne. Les libellés
     sont souvent des nœuds texte bruts (pas de <span>), donc on masque le
     texte via font-size:0 tout en restaurant la taille de l'icône.
     Pour conserver un libellé, ajouter .keep-label au bouton. */
  .topbar .btn:not(.keep-label) { font-size: 0; gap: 0; }
  .topbar .btn:not(.keep-label) .icon,
  .topbar .btn:not(.keep-label) [data-lucide],
  .topbar .btn:not(.keep-label) svg { font-size: initial; }
  .topbar .btn:not(.btn-icon):not(.keep-label) { width: 32px; padding: 0; }
  .topbar .btn-sm:not(.btn-icon):not(.keep-label) { width: 32px; }
  /* boutons marqués à cacher sur mobile */
  .hide-on-mobile { display: none !important; }

  /* Barres d'outils horizontales : on défile au doigt plutôt que de
     déborder/couper. S'applique aux contrôles segmentés et aux rangées
     d'onglets ou de chips marquées .scroll-x. */
  .seg, .scroll-x {
    max-width: 100%;
    overflow-x: auto; overflow-y: hidden;
    flex-wrap: nowrap;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .seg::-webkit-scrollbar, .scroll-x::-webkit-scrollbar { display: none; }
  .seg button { flex: none; }

  /* Cibles tactiles confortables sur les éléments interactifs courants. */
  .btn-sm { min-height: 36px; }
  .nav-item { height: 44px; }
}

/* Bannière « première utilisation » (créée par app.js) : centrée et
   réduite à la largeur de l'écran sur mobile, posée au-dessus de la
   zone sûre du bas. */
.firstrun-banner {
  position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
  z-index: 8000;
  display: flex; align-items: center; gap: 12px;
  max-width: min(560px, calc(100vw - 24px));
  padding: 12px 18px;
  background: var(--surface-3); border: 1px solid var(--border-strong);
  border-radius: 12px; box-shadow: var(--shadow-lg);
  font-size: 13px; font-weight: 600; color: var(--text);
}
.firstrun-banner > span { flex: 1; min-width: 0; }
.firstrun-banner .frb-cta {
  flex: none; height: 30px; padding: 0 13px; border-radius: 99px;
  background: var(--green); color: #fff; font-size: 12px; font-weight: 700;
  display: inline-flex; align-items: center; text-decoration: none;
}
.firstrun-banner .frb-close {
  flex: none; width: 22px; height: 22px; border: none; background: none;
  cursor: pointer; color: var(--text-3); padding: 0;
  display: flex; align-items: center; justify-content: center;
}
@media (max-width: 640px) {
  .firstrun-banner {
    left: 12px; right: 12px; transform: none; max-width: none;
    bottom: max(16px, env(safe-area-inset-bottom));
    padding: 11px 13px; gap: 10px; font-size: 12.5px;
    align-items: center;
  }
}

/* ---- Système blocker pages bureau uniquement ---- */
.desktop-only-msg {
  display: none;
  flex-direction: column; align-items: center; justify-content: center;
  gap: 16px; padding: 56px 28px; text-align: center;
  min-height: calc(100vh - var(--topbar-h));
}
.desktop-only-msg .dom-ico {
  display: flex; align-items: center; justify-content: center;
  width: 76px; height: 76px; border-radius: 22px;
  background: var(--green-soft); border: 1px solid var(--green-soft-2);
  color: var(--green-bright); margin-bottom: 2px;
}
.desktop-only-msg .dom-ico [data-lucide] { width: 34px; height: 34px; }
.desktop-only-msg [data-lucide] { width: 52px; height: 52px; color: var(--text-3); }
/* Les icônes dans un bouton (ex. « Parcourir la bibliothèque ») gardent la
   taille/couleur normale du bouton, sans hériter du gros icône d'illustration. */
.desktop-only-msg .btn [data-lucide] { width: 16px; height: 16px; color: inherit; }
.desktop-only-msg h2 { font-size: 21px; font-weight: 800; color: var(--text); }
.desktop-only-msg p { font-size: 14.5px; color: var(--text-2); max-width: 320px; line-height: 1.6; margin: 0; }

@media (max-width: 760px) {
  .desktop-only-content { display: none !important; }
  .desktop-only-msg { display: flex; }
}

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

/* ============================================================
   Date picker custom (datepicker.js)
   ============================================================ */
/* Masque l'icône native, on gère l'ouverture nous-mêmes */
input.scfg-date::-webkit-calendar-picker-indicator { display: none; }
input.scfg-date::-webkit-inner-spin-button,
input.scfg-date::-webkit-clear-button { display: none; }
input.scfg-date { cursor: pointer; position: relative; background-image: none; }

.dp-pop {
  position: fixed;
  z-index: 9999;
  width: 286px;
  padding: 12px;
  background: var(--bg-elev);
  border: 1px solid var(--border-2);
  border-radius: var(--r);
  box-shadow: var(--shadow-lg);
  font-family: var(--font);
  opacity: 0;
  transform: translateY(-4px) scale(.98);
  transform-origin: top left;
  pointer-events: none;
  transition: opacity .14s ease, transform .14s ease;
}
.dp-pop.open { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }

.dp-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px; }
.dp-title {
  font-family: var(--font-title); font-size: 15px; font-weight: 700; letter-spacing: .2px;
  color: var(--text); background: none; border: none; padding: 4px 8px; margin: -4px -8px;
  border-radius: var(--r-xs); cursor: pointer; transition: background .12s ease, color .12s ease;
}
.dp-title:hover:not(.dp-title-static) { background: var(--surface-2); color: var(--green-bright); }
.dp-title-static { cursor: default; }

.dp-nav { display: flex; align-items: center; gap: 2px; }
.dp-nav-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0; border: none; border-radius: var(--r-xs);
  background: transparent; color: var(--text-2); cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
.dp-nav-btn:hover { background: var(--surface-2); color: var(--text); }
.dp-nav-btn svg { width: 16px; height: 16px; fill: currentColor; }
.dp-today-dot::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: var(--green); box-shadow: 0 0 0 3px var(--green-soft);
}
.dp-today-dot:hover::before { background: var(--green-bright); }

.dp-grid { display: grid; grid-template-columns: repeat(7, 1fr); }
.dp-weekdays { margin-bottom: 4px; }
.dp-weekdays span {
  text-align: center; font-size: 11px; font-weight: 700; color: var(--text-3);
  padding: 4px 0; text-transform: uppercase; letter-spacing: .5px;
}
.dp-days { gap: 2px; }
.dp-day {
  position: relative; height: 34px; border: none; background: transparent;
  border-radius: var(--r-xs); color: var(--text); font-size: 13px; font-weight: 600;
  font-family: inherit; cursor: pointer; transition: background .1s ease, color .1s ease;
}
.dp-day:hover:not(.dp-disabled):not(.dp-sel) { background: var(--surface-3); }
.dp-day.dp-out { color: var(--text-3); font-weight: 500; }
.dp-day.dp-today:not(.dp-sel) { color: var(--green-bright); font-weight: 700; }
.dp-day.dp-today:not(.dp-sel)::after {
  content: ""; position: absolute; bottom: 5px; left: 50%; transform: translateX(-50%);
  width: 4px; height: 4px; border-radius: 50%; background: var(--green-bright);
}
.dp-day.dp-sel {
  background: var(--green); color: var(--text-on-green); font-weight: 700;
  box-shadow: 0 2px 8px var(--green-glow);
}
.dp-day.dp-disabled { color: var(--text-3); opacity: .35; cursor: not-allowed; }

.dp-cells { gap: 6px; grid-template-columns: repeat(3, 1fr); margin-top: 2px; }
.dp-cell {
  height: 44px; border: none; background: var(--surface-2); border-radius: var(--r-sm);
  color: var(--text); font-size: 13px; font-weight: 600; font-family: inherit; cursor: pointer;
  transition: background .1s ease, color .1s ease;
}
.dp-cell:hover:not(.dp-sel) { background: var(--surface-hi); }
.dp-cell.dp-today:not(.dp-sel) { color: var(--green-bright); }
.dp-cell.dp-sel { background: var(--green); color: var(--text-on-green); font-weight: 700; box-shadow: 0 2px 8px var(--green-glow); }

.dp-foot {
  display: flex; justify-content: space-between; gap: 8px;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border);
}
.dp-foot-btn {
  flex: 1; height: 30px; border: none; border-radius: var(--r-xs);
  background: var(--surface-2); color: var(--text-2); font-size: 12px; font-weight: 600;
  font-family: inherit; cursor: pointer; transition: background .12s ease, color .12s ease;
}
.dp-foot-btn:hover { background: var(--green-soft); color: var(--green-bright); }
.dp-foot-clear:hover { background: rgba(248,113,113,.14); color: var(--red); }

/* ============================================================
   COMBOBOX — remplace les <select> natifs (combobox.js)
   Le bouton .cbx-trigger hérite des classes du <select> d'origine
   (.input / .select / .scfg-select / style inline) : il garde donc
   exactement la même boîte. On ne fait qu'ajouter le layout flex,
   le chevron custom et l'état ouvert/survol.
   ============================================================ */
.cbx { position: relative; display: block; max-width: 100%; }
.cbx-native {
  position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0; opacity: 0; pointer-events: none;
}

button.cbx-trigger {
  display: inline-flex; align-items: center; gap: 8px;
  text-align: left; cursor: pointer;
  appearance: none; -webkit-appearance: none;
  background-image: none !important; /* tue le chevron en image du .select */
  font-weight: inherit; line-height: 1.2;
}
/* .select réservait padding-right:36px pour son chevron en image,
   désormais inutile (notre chevron est un enfant flex). */
button.cbx-trigger.select { padding-right: 13px; }
button.cbx-trigger .cbx-value {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
button.cbx-trigger.cbx-placeholder .cbx-value { color: var(--text-3); }
button.cbx-trigger .cbx-chevron {
  flex: none; color: var(--text-3);
  transition: transform .18s ease, color .18s ease;
}
button.cbx-trigger:hover { border-color: var(--border-strong); }
button.cbx-trigger:hover .cbx-chevron { color: var(--text-2); }
button.cbx-trigger:focus-visible {
  outline: none; border-color: var(--green); box-shadow: var(--ring);
}
.cbx-open button.cbx-trigger {
  border-color: var(--green); box-shadow: var(--ring);
}
.cbx-open button.cbx-trigger .cbx-chevron {
  transform: rotate(180deg); color: var(--green-bright);
}
button.cbx-trigger:disabled { opacity: .5; cursor: not-allowed; }

/* ── Panneau ── */
.cbx-panel {
  position: absolute; z-index: 80;
  top: calc(100% + 6px); left: 0; min-width: 100%;
  max-height: 264px; overflow-y: auto; overscroll-behavior: contain;
  padding: 5px;
  background: var(--bg-elev);
  border: 1px solid var(--border-2);
  border-radius: var(--r-md, 12px);
  box-shadow: var(--shadow-lg);
  transform-origin: top center;
  animation: cbx-in .14s cubic-bezier(.16,1,.3,1);
}
.cbx-panel.cbx-up {
  top: auto; bottom: calc(100% + 6px); transform-origin: bottom center;
}
@keyframes cbx-in {
  from { opacity: 0; transform: translateY(-4px) scale(.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.cbx-panel.cbx-up { animation-name: cbx-in-up; }
@keyframes cbx-in-up {
  from { opacity: 0; transform: translateY(4px) scale(.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* Sur mobile, le panneau devient un bottom sheet ancré au <body> (voir
   combobox.js) : dans son conteneur il serait rogné par les barres
   défilantes ou déborderait de l'écran près des bords. */
.cbx-scrim { display: none; }
@media (max-width: 760px) {
  .cbx-scrim {
    display: block; position: fixed; inset: 0; z-index: 9150;
    background: rgba(0,0,0,.45);
    -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
    opacity: 0; pointer-events: none; transition: opacity .22s ease;
  }
  .cbx-scrim.show { opacity: 1; pointer-events: auto; }
  body.cbx-sheet-open { overflow: hidden; }
  .cbx-panel.cbx-sheet {
    position: fixed; top: auto; left: 0; right: 0; bottom: 0; z-index: 9200;
    min-width: 0; width: 100%; max-height: 70dvh;
    border-radius: 22px 22px 0 0; border: none; border-top: 1px solid var(--border-2);
    padding: 10px 14px calc(12px + env(safe-area-inset-bottom));
    box-shadow: 0 -20px 60px rgba(0,0,0,.35);
    animation: cbx-sheet-in .3s cubic-bezier(.32,.72,0,1);
  }
  .cbx-panel.cbx-sheet::before {
    content: ""; display: block; width: 40px; height: 4px; border-radius: 99px;
    background: var(--border-strong); opacity: .55; margin: 2px auto 10px;
  }
  @keyframes cbx-sheet-in {
    from { transform: translateY(28px); opacity: .5; }
    to   { transform: none; opacity: 1; }
  }
  .cbx-sheet-title {
    font-size: 12px; font-weight: 700; text-transform: uppercase;
    letter-spacing: .07em; color: var(--text-3); padding: 0 6px 8px;
  }
  .cbx-sheet .cbx-item { min-height: 46px; padding: 11px 10px; font-size: 14.5px; }
}

.cbx-item {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 9px; border-radius: var(--r-sm);
  font-size: 13.5px; font-weight: 500; color: var(--text-2);
  cursor: pointer; user-select: none;
  transition: background .1s ease, color .1s ease;
}
.cbx-item .cbx-check { flex: none; opacity: 0; color: var(--green-bright); }
.cbx-item-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cbx-item.cbx-active { background: var(--surface-2); color: var(--text); }
.cbx-item.cbx-selected { color: var(--text); font-weight: 600; }
.cbx-item.cbx-selected .cbx-check { opacity: 1; }
.cbx-item.cbx-disabled { opacity: .4; cursor: not-allowed; }
.cbx-item.cbx-disabled.cbx-active { background: transparent; }

@media (prefers-reduced-motion: reduce) {
  .cbx-panel { animation: none; }
  button.cbx-trigger .cbx-chevron { transition: none; }
}

/* Coupe les animations décoratives en boucle pour les utilisateurs
   sensibles au mouvement (halo de la sidebar, pulse de sélection terrain). */
@media (prefers-reduced-motion: reduce) {
  .sidebar::before { animation: none; }
  .cell-sel-overlay polygon { animation: none; }
}

/* ============================================================
   Light = langage visuel de la nouvelle landing
   CTA encre, hairlines, labels mono, chrome blanc, sans glows
   ============================================================ */

/* Boutons : le primaire devient encre comme les CTA de la landing */
/* Boutons : pilules de la DA abonnement/parrainage — noire (« Copier mon lien
   affilié »), grise (« Contacter le support »), rouge pâle (« Résilier »). */
[data-theme="light"] .btn { height: 32px; padding: 8px 12px; border-radius: 9999px; font-size: 14px; line-height: 20px; font-weight: 500; letter-spacing: 0; }
[data-theme="light"] .btn-primary { background: #18181b; color: #fff; box-shadow: none; }
[data-theme="light"] .btn-primary:hover { background: #2f2f33; box-shadow: none; }
[data-theme="light"] .btn-ghost { background: #f5f5f5; color: #18181b; border-color: transparent; }
[data-theme="light"] .btn-ghost:hover { background: #ececec; border-color: transparent; }
[data-theme="light"] .btn-quiet:hover { background: #f5f5f5; }
[data-theme="light"] .btn-sm { border-radius: 9999px; }
[data-theme="light"] .btn-icon { width: 32px; padding: 0; }
[data-theme="light"] .btn-danger { background: #fee7e7; color: #e92f2f; border-color: transparent; }
[data-theme="light"] .btn-danger:hover { background: #fdd5d5; border-color: transparent; }

/* Chips et tags : blanc + hairline, plus de relief néomorphique */
[data-theme="light"] .tag { background: #fff; border-color: #ededed; box-shadow: none; }
[data-theme="light"] .tag-cat { font-family: inherit; letter-spacing: 0; color: #747476; font-weight: 500; }
[data-theme="light"] .tag-green { background: #d9ffe3; color: #2cb94f; border-color: transparent; font-weight: 500; }

/* ── Teintes de thème ──────────────────────────────────────────
   Un chip de thème porte la couleur de sa catégorie (voir THEME_TONES dans
   data.js). Même formule pour toutes : fond pastel très clair + texte saturé
   du même ton, de la famille des combos de la DA. Elles s'appliquent aussi
   bien à un .tag (cartes, séances) qu'à un .f2-chip (fiche procédé). */
[data-theme="light"] .tone-bleu   { background: #eaeefe; color: #4387f4; border-color: transparent; font-weight: 500; }
[data-theme="light"] .tone-corail { background: #ffe8e0; color: #ef6540; border-color: transparent; font-weight: 500; }
[data-theme="light"] .tone-indigo { background: #e9e9fe; color: #6366f1; border-color: transparent; font-weight: 500; }
[data-theme="light"] .tone-ambre  { background: #fdf3d1; color: #dd950a; border-color: transparent; font-weight: 500; }
[data-theme="light"] .tone-vert   { background: #d9ffe3; color: #2cb94f; border-color: transparent; font-weight: 500; }
[data-theme="light"] .tone-rose   { background: #fce7f3; color: #d6339a; border-color: transparent; font-weight: 500; }
[data-theme="light"] .tone-rouge  { background: #fee7e7; color: #e92f2f; border-color: transparent; font-weight: 500; }
[data-theme="light"] .tone-violet { background: #f3e8ff; color: #9333ea; border-color: transparent; font-weight: 500; }
[data-theme="light"] .tone-cyan   { background: #dff6f8; color: #0e9bab; border-color: transparent; font-weight: 500; }
[data-theme="light"] .tone-neutre { background: #f5f5f5; color: #757575; border-color: transparent; font-weight: 500; }

/* Chips dans les listes compactes (étapes de séance, bibliothèque du créateur,
   fiches séance et de partage) : un thème long comme « Transition défensive
   (perte → organisation) » débordait de la carte, .tag étant en nowrap sans
   largeur maximale. On le borne à la place disponible et on coupe à l'ellipse ;
   le texte entier reste accessible par l'infobulle.
   display bloc et non flex : text-overflow ne s'applique pas à un conteneur
   flex (un élément de flex est de toute façon « blockifié »). */
.sitem .meta-min .tag,
.libitem .meta-min .tag,
.proc-tags .tag {
  display: inline-block; min-width: 0; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  line-height: 18px;
}
/* Le conteneur des métadonnées d'une étape n'était pas stylé du tout : sans
   flex ni min-width, rien ne limitait la largeur de ses chips. */
.sitem .meta-min { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-width: 0; }
[data-theme="light"] .fchip { background: #fff; border-color: #ededed; color: #747476; font-weight: 500; }
[data-theme="light"] .fchip:hover { background: #fff; border-color: #dcdcde; }
[data-theme="light"] .fchip.active { background: #eaeefe; color: #4387f4; border-color: transparent; }
[data-theme="light"] .fchip.active .icon { color: #4387f4; }

/* Sidebar : blanc opaque. Les libellés de groupes étaient en mono espacé comme
   les labels de section de la landing ; ils suivent maintenant la typo courante
   de la nav, la structure passant par les filets de séparation. */
[data-theme="light"] .sidebar { background: #fff; }
[data-theme="light"] .brand-name { font-weight: 600; letter-spacing: -.03em; }
[data-theme="light"] .userchip .ava { color: var(--green-deep); }

/* Topbar : titres à la graisse et au tracking de la landing */
[data-theme="light"] .topbar h1 { font-weight: 600; letter-spacing: -.02em; }

/* Segmented control : pastille blanche qui glisse, comme un toggle de la landing */
[data-theme="light"] .seg { background: var(--surface-2); border-color: var(--border); }
[data-theme="light"] .seg button.active { background: #fff; box-shadow: var(--shadow-sm); }

/* Cartes : hover plus sobre (la landing ne fait presque pas léviter) */
[data-theme="light"] .pcard:hover { transform: translateY(-2px); }

/* Divers chrome */
[data-theme="light"] .firstrun-banner { background: #fff; border-color: var(--border-2); }
[data-theme="light"] .window .chrome { background: var(--surface-2); }
[data-theme="light"] .eyebrow { box-shadow: none; }

/* ============================================================
   Envoi — fenêtre unique de partage / export (envoi-modal.js)
   Classes volontairement sans « share » : les bloqueurs de pub
   masquent ces sélecteurs (filtres cosmétiques).
   ============================================================ */
.envoi-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.55); display: flex; align-items: center; justify-content: center; z-index: 8600; padding: 20px; opacity: 0; transition: opacity .15s; pointer-events: none; }
.envoi-backdrop.open { opacity: 1; pointer-events: all; }
.envoi-box { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); padding: 28px; width: 100%; max-width: 420px; transform: translateY(10px); transition: transform .15s; box-shadow: 0 24px 60px rgba(0,0,0,.35); max-height: 90vh; overflow-y: auto; }
.envoi-backdrop.open .envoi-box { transform: translateY(0); }
.envoi-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 18px; }
.envoi-title { font-size: 17px; font-weight: 800; }
.envoi-sub { font-size: 13px; color: var(--text-3); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 300px; }
.envoi-linkrow, .envoi-mailrow { display: flex; gap: 8px; }
.envoi-linkrow { margin-bottom: 10px; }
.envoi-linkrow input, .envoi-mailrow input {
  flex: 1; min-width: 0; height: 40px; padding: 0 12px;
  border-radius: var(--r-sm); border: 1px solid var(--border-2);
  background: var(--surface-2); color: var(--text); font-size: 13px;
}
.envoi-linkrow input { font-family: var(--mono); font-size: 12px; color: var(--text-2); }
.envoi-linkrow input::placeholder, .envoi-mailrow input::placeholder { color: var(--text-3); }
.envoi-mailinfo { display: flex; gap: 8px; align-items: flex-start; font-size: 12px; color: var(--text-3); margin-top: 9px; line-height: 1.5; }
.envoi-mailinfo [data-lucide] { width: 14px; height: 14px; flex: none; margin-top: 1px; color: var(--green-bright); }
.envoi-mailto { background: none; border: none; padding: 0; font-family: inherit; font-size: 12px; font-weight: 600; color: var(--text-3); cursor: pointer; text-decoration: underline; }
.envoi-mailto:hover { color: var(--text-2); }
.envoi-recents-label { font-size: 12px; font-weight: 600; color: var(--text); margin: 14px 0 6px; }
.envoi-recent { display: flex; align-items: center; gap: 9px; padding: 6px; border-radius: 8px; cursor: pointer; }
.envoi-recent:hover { background: var(--surface-2); }
.envoi-recent .av { flex: none; width: 22px; height: 22px; border-radius: 50%; background: var(--green-soft); color: var(--green-deep); display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; text-transform: uppercase; }
.envoi-recent .em { flex: 1; min-width: 0; font-size: 12.5px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.envoi-recent .ts { flex: none; font-size: 11px; color: var(--text-3); }
.envoi-foot { display: flex; justify-content: flex-end; gap: 10px; flex-wrap: wrap; margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border); }
.envoi-foot img { width: 14px; height: auto; flex: none; }
@media (max-width: 760px) {
  .envoi-backdrop { align-items: flex-end; padding: 0; }
  .envoi-box { max-width: none; border-radius: 20px 20px 0 0; border-left: none; border-right: none; border-bottom: none; padding: 22px 18px calc(20px + env(safe-area-inset-bottom)); max-height: 86dvh; }
  .envoi-backdrop.open .envoi-box { transform: none; }
}

/* Avatar du destinataire (compte Tacti reconnu par son e-mail) */
.envoi-mailwrap { position: relative; flex: 1; min-width: 0; display: flex; }
.envoi-mailwrap input { width: 100%; transition: padding-left .15s; }
.envoi-mailava { position: absolute; left: 8px; top: 50%; transform: translateY(-50%); width: 24px; height: 24px; border-radius: 50%; object-fit: cover; z-index: 1; border: 1px solid var(--border-2); background: var(--surface); }
.envoi-mailwrap.has-ava input { padding-left: 40px; }
.envoi-recent .av { overflow: hidden; }
.envoi-recent .av img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* img{display:block} global : il faut ré-imposer le masquage de l'avatar */
.envoi-mailava[hidden] { display: none; }
/* Récents : l'icône d'envoi remplace l'horodatage au survol */
.envoi-recent .go { display: none; width: 14px; height: 14px; flex: none; color: var(--green-bright); }
.envoi-recent:hover .go { display: block; }
.envoi-recent:hover .ts { display: none; }

/* ── Menu dropdown (recette Transitions.dev) ───────────────────
   Ouverture : léger scale depuis le point d'ancrage, 250ms.
   Fermeture : plus courte (150ms) et plus discrète, l'utilisateur a
   déjà tourné son attention ailleurs.

   Usage :
     <div class="t-dropdown" data-origin="top-right"> … </div>
   États : ajouter .is-open pour montrer ; à la fermeture, remplacer
   .is-open par .is-closing puis retirer .is-closing après
   --dropdown-close-dur.

   data-origin : top-left | top-center | top-right |
                 bottom-left | bottom-center | bottom-right. */
:root {
  --dropdown-open-dur: 250ms;
  --dropdown-close-dur: 150ms;
  --dropdown-pre-scale: 0.97;
  --dropdown-closing-scale: 0.99;
  --dropdown-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

.t-dropdown {
  transform-origin: top left;
  transform: scale(var(--dropdown-pre-scale));
  opacity: 0;
  pointer-events: none;
  transition:
    transform var(--dropdown-open-dur) var(--dropdown-ease),
    opacity   var(--dropdown-open-dur) var(--dropdown-ease);
  will-change: transform, opacity;
}
.t-dropdown[data-origin="top-right"]     { transform-origin: top right; }
.t-dropdown[data-origin="top-center"]    { transform-origin: top center; }
.t-dropdown[data-origin="bottom-left"]   { transform-origin: bottom left; }
.t-dropdown[data-origin="bottom-center"] { transform-origin: bottom center; }
.t-dropdown[data-origin="bottom-right"]  { transform-origin: bottom right; }

.t-dropdown.is-open {
  transform: scale(1);
  opacity: 1;
  pointer-events: auto;
}
.t-dropdown.is-closing {
  transform: scale(var(--dropdown-closing-scale));
  opacity: 0;
  pointer-events: none;
  transition:
    transform var(--dropdown-close-dur) var(--dropdown-ease),
    opacity   var(--dropdown-close-dur) var(--dropdown-ease);
}

@media (prefers-reduced-motion: reduce) {
  .t-dropdown { transition: none !important; }
}
