/* VAULT — feuille statique des pages d'extension (charte UI v1.2 : noir profond, blanc cassé, accent blanc unique).
   Tokens centralisés (charte §2–§4, §14), polices Manrope (interface) et IBM Plex Mono (secrets) embarquées (OFL, static/fonts/), aucune ressource distante.
   Pas de framework : le DOM est construit par src/dom.ts, les classes ci-dessous sont les seules primitives.
   Règles de la refonte (session 25) : un seul accent (blanc cassé et halo) pour l'action prioritaire, l'ambre ne restant qu'une teinte de repérage et d'état ; les couleurs d'état restent sémantiques et
   toujours accompagnées d'un texte ; bordures à 1 px ; mouvements courts (≤ 250 ms) sauf les deux attentes réelles (faisceau, loader). */

@font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 400; font-display: swap; src: url("fonts/IBMPlexMono-Regular-Latin1.woff2") format("woff2"); }
@font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 500; font-display: swap; src: url("fonts/IBMPlexMono-Medium-Latin1.woff2") format("woff2"); }
/* Manrope 4.000 (Mikhail Sharanda, SIL OFL 1.1, sans Reserved Font Name — fonts/Manrope-OFL.txt) : police unique de
   l'interface depuis la session 13, en remplacement d'Azonix (capitales seules, accents non dessinés). Sous-ensemble
   Latin-1 identique à Plex Mono : casse et accents rendus, aucun repli par glyphe. Plex Sans n'est plus embarquée (sans emploi). */
@font-face { font-family: "Manrope"; font-style: normal; font-weight: 400; font-display: swap; src: url("fonts/Manrope-Regular-Latin1.woff2") format("woff2"); }
@font-face { font-family: "Manrope"; font-style: normal; font-weight: 500; font-display: swap; src: url("fonts/Manrope-Medium-Latin1.woff2") format("woff2"); }
@font-face { font-family: "Manrope"; font-style: normal; font-weight: 600; font-display: swap; src: url("fonts/Manrope-SemiBold-Latin1.woff2") format("woff2"); }

/* angle du faisceau d'attente (charte §14, session 25) : propriété enregistrée pour être animée */
@property --v-beam { syntax: "<angle>"; inherits: false; initial-value: 0deg; }

:root {
  color-scheme: dark;

  /* surfaces opaques : noir profond, pas un gris bleuté */
  --v-bg-canvas: #0A0B0D;
  --v-bg-sidebar: #0E1012;
  --v-bg-surface: #111316;
  --v-bg-raised: #17191D;
  --v-bg-hover: #1C1F23;
  --v-bg-selected: #21252A;
  --v-bg-input: #0B0C0E;
  --v-bg-menu: #15181C;

  --v-text-primary: #F4F4F1;
  --v-text-secondary: #B4BAC1;
  --v-text-muted: #8C949C; /* ≥ 4,5:1 sur toutes les surfaces ci-dessus, fond animé sous voile compris (mesuré session 25) */
  --v-text-inverse: #0B0C0E;

  /* contours : une seule échelle de blanc, du séparateur au survol */
  --v-line-1: rgb(255 255 255 / 6%);
  --v-line-2: rgb(255 255 255 / 10%);
  --v-line-3: rgb(255 255 255 / 18%);
  --v-line-4: rgb(255 255 255 / 30%);
  --v-border-subtle: var(--v-line-2);
  --v-border-control: var(--v-line-3);
  --v-border-hover: var(--v-line-4);

  /* accent unique : blanc cassé et halo léger (Security Owner, recette du 2026-09-14, remplace l'ambre de la session 25) pour
     l'action prioritaire, la sélection et le focus. L'ambre ne reste qu'une teinte de repérage et d'état (--v-hue-amber). */
  --v-accent: #F4F4F1;
  --v-accent-hover: #FAFAF8;
  --v-accent-active: #DCDBD7;
  --v-accent-soft: rgb(255 255 255 / 7%);
  --v-accent-line: rgb(255 255 255 / 22%);
  --v-focus: var(--v-accent);
  --v-primary-bg: var(--v-accent);
  --v-primary-hover: var(--v-accent-hover);
  --v-primary-active: var(--v-accent-active);
  /* halo de texte : lueur blanche diffuse des liens, plus vive au survol et au focus clavier */
  --v-halo-text: 0 0 8px rgb(255 255 255 / 18%);
  --v-halo-text-hover: 0 0 12px rgb(255 255 255 / 55%);
  /* boutons principaux (recette du 2026-09-14, port du SpotlightButton de Nexus) : plus aucun bouton plein — contour en
     dégradé blanc → bleu clair → gris sur fond sombre ; au survol et au focus clavier, voile du dégradé et lueur bleue qui
     suit le pointeur (`--spot-x` / `--spot-y`, posées par `trackSpotlight`). */
  --v-edge-gradient: linear-gradient(115deg, #F4F4F1 0%, #8FB8E8 50%, #7D8590 100%);
  --v-edge-wash: linear-gradient(115deg, rgb(244 244 241 / 18%) 0%, rgb(143 184 232 / 18%) 50%, rgb(125 133 144 / 18%) 100%);
  --v-spot: rgb(143 184 232 / 53%);

  /* teintes de repérage (monogrammes) et d'état : jamais une décoration seule */
  --v-hue-amber: #F0BE5A;
  --v-hue-amber-bg: rgb(240 190 90 / 12%);
  --v-hue-coral: #F28B8B;
  --v-hue-coral-bg: rgb(242 139 139 / 12%);
  --v-hue-sky: #8FB8E8;
  --v-hue-sky-bg: rgb(143 184 232 / 12%);

  --v-success: #7FD1A0;
  --v-success-bg: rgb(127 209 160 / 12%);
  --v-warning: #E3C07C;
  --v-warning-bg: rgb(227 192 124 / 12%);
  --v-danger: #F28B8B;
  --v-danger-bg: rgb(242 139 139 / 12%);
  --v-info: #8FB8E8;
  --v-info-bg: rgb(143 184 232 / 12%);

  /* voiles translucides des grandes surfaces au-dessus du fond animé (session 12) ; champs, contrôles et menus restent opaques */
  --v-veil-nav: rgb(10 11 13 / 62%);
  --v-veil-list: rgb(10 11 13 / 46%);
  --v-veil-head: rgb(14 16 18 / 72%);
  --v-veil-detail: rgb(11 12 14 / 56%);
  --v-veil-card: rgb(17 19 22 / 72%);
  --v-veil-panel: rgb(11 12 14 / 72%);

  --v-shadow-panel: 0 24px 60px -24px rgb(0 0 0 / 70%);
  --v-shadow-floating: 0 20px 50px -12px rgb(0 0 0 / 65%);
  --v-edge-highlight: inset 0 1px 0 rgb(255 255 255 / 5%);

  /* police unique de l'interface et des données saisies : Manrope conserve la casse et les accents ;
     les secrets restent en Plex Mono (.mono), seule distinction typographique conservée.
     IBM Plex Sans reste nommée en repli (charte v1.1 §3) mais n'est plus embarquée : elle ne sert que si elle est installée sur le poste. */
  --v-font-ui: "Manrope", "IBM Plex Sans", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --v-font-mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;

  /* effet « Matrix » de l'accroche (dérogation charte, session 13) : vert d'origine du composant, tenu par deux tokens */
  --v-matrix: #00FF00;
  --v-matrix-glow: rgb(0 255 0 / 50%);

  --v-space-1: 0.25rem;
  --v-space-2: 0.5rem;
  --v-space-3: 0.75rem;
  --v-space-4: 1rem;
  --v-space-5: 1.25rem;
  --v-space-6: 1.5rem;
  --v-space-8: 2rem;
  --v-space-10: 2.5rem;
  --v-space-12: 3rem;

  --v-radius-small: 0.5rem;
  --v-radius-control: 0.625rem;
  --v-radius-panel: 1rem;
  --v-radius-dialog: 1rem;
  --v-radius-pill: 999px;

  --v-control-height: 2.5rem;
  --v-control-height-compact: 2.25rem;
  --v-control-height-touch: 2.75rem;

  --v-motion-fast: 120ms;
  --v-motion-standard: 180ms;
  --v-motion-dialog: 220ms;
  --v-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --v-ease-state: cubic-bezier(0.2, 0, 0, 1);
  --v-ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
}

/* --- base --------------------------------------------------------------------------------------------------------- */

* { box-sizing: border-box; }
html { height: 100%; }
body {
  margin: 0;
  min-height: 100%;
  background: var(--v-bg-canvas);
  color: var(--v-text-primary);
  font: 400 0.9375rem/1.5rem var(--v-font-ui);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
h1, h2, h3, p, dl, dd, dt, ul, figure { margin: 0; }
h1, h2, h3, fieldset legend { text-wrap: balance; }
p, .hint { text-wrap: pretty; }
h2 { font-size: 1.125rem; line-height: 1.625rem; font-weight: 600; letter-spacing: -0.01em; }
/* surfaces peintes par le navigateur : sélection, barres de défilement, curseur de saisie — thème, jamais la valeur système */
::selection { background: rgb(255 255 255 / 20%); color: var(--v-text-primary); }
:root { scrollbar-width: thin; scrollbar-color: rgb(255 255 255 / 18%) transparent; }
/* lien : blanc sans soulignement, repéré par son halo et son icône ; le halo s'intensifie au survol et au focus clavier */
a { color: var(--v-accent); text-decoration: none; text-shadow: var(--v-halo-text); transition: color var(--v-motion-fast) var(--v-ease-state), text-shadow var(--v-motion-fast) var(--v-ease-state); }
a:hover, a:focus-visible { color: var(--v-accent-hover); text-shadow: var(--v-halo-text-hover); }
code, .mono { font-family: var(--v-font-mono); font-variant-ligatures: none; }
.muted { color: var(--v-text-muted); }
.hint { font-size: 0.875rem; line-height: 1.25rem; color: var(--v-text-muted); margin-top: var(--v-space-2); }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.icon { flex: none; width: 1rem; height: 1rem; }

[data-vault-ui] :focus-visible { outline: 2px solid var(--v-focus); outline-offset: 2px; }

/* --- mot-symbole ---------------------------------------------------------------------------------------------------- */

/* logo VAULT (image blanche sur transparent, static/logo-vault.png) : hauteur fixée, largeur proportionnelle (549 × 72) */
.wordmark { display: inline-flex; align-items: center; margin: 0; }
.wordmark-logo { display: block; height: 1.125rem; width: auto; opacity: 0.94; }
.ws-nav .wordmark-logo { height: 1.25rem; }
.auth-panel .wordmark, body.popup .wordmark { display: flex; justify-content: center; }
.auth-panel .wordmark { padding-bottom: var(--v-space-5); }
.auth-panel .wordmark-logo { height: 2.25rem; }
body.popup .wordmark { justify-content: flex-start; }
body.popup .wordmark-logo { height: 1rem; }

/* --- badges d'état et compteurs : texte toujours présent, couleur en renfort ; le point ne porte qu'un état réel ---------- */

.badge { display: inline-flex; align-items: center; gap: 0.375rem; min-height: 1.5rem; padding: 0 0.625rem; border-radius: var(--v-radius-pill); border: 1px solid; font-size: 0.75rem; line-height: 1rem; font-weight: 500; letter-spacing: 0.01em; white-space: nowrap; }
.badge .icon { width: 0.8125rem; height: 0.8125rem; }
.badge-dot::before { content: ""; flex: none; width: 0.375rem; height: 0.375rem; border-radius: 50%; background: currentColor; box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 18%, transparent); }
.badge-muted { color: var(--v-text-secondary); background: rgb(255 255 255 / 5%); border-color: var(--v-line-2); }
.badge-sky { color: var(--v-hue-sky); background: var(--v-hue-sky-bg); border-color: rgb(143 184 232 / 24%); }
.badge-amber { color: var(--v-hue-amber); background: var(--v-hue-amber-bg); border-color: rgb(240 190 90 / 24%); }
.badge-success { color: var(--v-success); background: var(--v-success-bg); border-color: rgb(127 209 160 / 24%); }
.badge-coral { color: var(--v-hue-coral); background: var(--v-hue-coral-bg); border-color: rgb(242 139 139 / 24%); }
.count { display: inline-flex; align-items: center; justify-content: center; min-width: 1.75rem; height: 1.5rem; padding: 0 0.5rem; border-radius: var(--v-radius-small); background: rgb(255 255 255 / 6%); border: 1px solid var(--v-line-2); font-family: var(--v-font-mono); font-size: 0.8125rem; font-weight: 500; color: var(--v-text-primary); font-variant-numeric: tabular-nums; }

/* --- boutons (charte §6) : accent réservé au principal, pression à 98 %, transitions nommées ------------------------------ */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--v-space-2);
  min-height: var(--v-control-height); padding: 0 var(--v-space-4);
  border: 1px solid var(--v-line-3); border-radius: var(--v-radius-control);
  background: var(--v-bg-raised); color: var(--v-text-primary);
  font: 500 0.875rem/1.25rem var(--v-font-ui); text-decoration: none; cursor: pointer; white-space: nowrap;
  position: relative;
  transition: background-color var(--v-motion-fast) var(--v-ease-state), border-color var(--v-motion-fast) var(--v-ease-state), color var(--v-motion-fast) var(--v-ease-state), transform 160ms var(--v-ease-out), box-shadow var(--v-motion-fast) var(--v-ease-state);
}
.btn .icon { color: inherit; }
.btn-primary {
  isolation: isolate; overflow: hidden; border: 2px solid transparent; color: var(--v-text-primary); font-weight: 600;
  background: linear-gradient(var(--v-bg-raised), var(--v-bg-raised)) padding-box, var(--v-edge-gradient) border-box;
  box-shadow: 0 10px 24px -14px rgb(0 0 0 / 90%);
}
/* un seul pseudo-élément (`::after` porte l'anneau de `.is-busy`) : lueur radiale au-dessus du voile, sous le libellé */
.btn-primary::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; opacity: 0;
  background: radial-gradient(100px circle at var(--spot-x, 50%) var(--spot-y, 50%), var(--v-spot), rgb(0 0 0 / 15%)), var(--v-edge-wash);
  transition: opacity 300ms var(--v-ease-state);
}
.btn-primary:not(:disabled):focus-visible::before { opacity: 1; }
/* contrôles opaques au-dessus du fond animé (dérogation session 12, mesuré par V18) : jamais un voile sur un bouton */
.btn-secondary { background: var(--v-bg-raised); border-color: var(--v-line-3); }
.btn-ghost { background: transparent; border-color: transparent; color: var(--v-text-secondary); }
.btn-icon { width: var(--v-control-height-compact); min-height: var(--v-control-height-compact); padding: 0; background: transparent; border-color: transparent; color: var(--v-text-muted); border-radius: var(--v-radius-small); }
@media (hover: hover) {
  .btn:not(:disabled):hover { background: var(--v-bg-hover); border-color: var(--v-line-4); }
  .btn-primary:not(:disabled):hover { background: linear-gradient(var(--v-bg-raised), var(--v-bg-raised)) padding-box, var(--v-edge-gradient) border-box; border-color: transparent; }
  .btn-primary:not(:disabled):hover::before { opacity: 1; }
  .btn-secondary:not(:disabled):hover { background: var(--v-bg-hover); }
  .btn-ghost:not(:disabled):hover, .btn-icon:not(:disabled):hover { background: rgb(255 255 255 / 6%); border-color: transparent; color: var(--v-text-primary); }
}
.btn:not(:disabled):active { transform: scale(0.98); }
.btn:disabled { cursor: default; color: var(--v-text-muted); border-color: var(--v-line-2); background: var(--v-bg-surface); box-shadow: none; }
.btn-ghost:disabled, .btn-icon:disabled { border-color: transparent; background: transparent; }
.btn[data-copied="ok"] { color: var(--v-success); }
.btn[data-copied="failed"] { color: var(--v-danger); }
/* activité réelle courte : anneau discret dans le bouton, sans changement de largeur (charte §6) */
.is-busy { padding-right: calc(var(--v-space-4) + 1.25rem); }
.is-busy::after {
  content: ""; position: absolute; right: var(--v-space-3); top: 50%; width: 0.875rem; height: 0.875rem; margin-top: -0.4375rem;
  border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: vault-spin 0.8s linear infinite;
}
@keyframes vault-spin { to { transform: rotate(360deg); } }
.btn-ghost.is-danger { color: var(--v-hue-coral); }
.btn-ghost.is-danger:not(:disabled):hover { color: var(--v-hue-coral); background: var(--v-hue-coral-bg); }

.actions { display: flex; flex-wrap: wrap; gap: var(--v-space-3); margin-top: var(--v-space-6); }
.actions .btn-primary { min-width: 12rem; }

/* --- champs (charte §7) --------------------------------------------------------------------------------------------- */

.field { margin-top: var(--v-space-4); }
.field label, fieldset legend { display: block; font-size: 0.8125rem; line-height: 1.25rem; font-weight: 500; color: var(--v-text-secondary); margin-bottom: var(--v-space-2); }
input[type="text"], input[type="email"], input[type="password"], input[type="search"], textarea {
  display: block; width: 100%; min-height: var(--v-control-height); padding: var(--v-space-2) 0.875rem;
  background: var(--v-bg-input); color: var(--v-text-primary);
  border: 1px solid var(--v-line-3); border-radius: var(--v-radius-control);
  font: 400 0.9375rem/1.5rem var(--v-font-ui);
  transition: border-color var(--v-motion-fast) var(--v-ease-state), box-shadow var(--v-motion-fast) var(--v-ease-state);
}
input, textarea { caret-color: var(--v-accent); }
input.mono, textarea.mono { font-family: var(--v-font-mono); font-variant-ligatures: none; }
input.code { font-family: var(--v-font-mono); font-size: 1.375rem; line-height: 2rem; font-weight: 500; letter-spacing: 0.16em; font-variant-numeric: tabular-nums; }
input::placeholder, textarea::placeholder { color: var(--v-text-muted); opacity: 1; }
@media (hover: hover) { input:not(:disabled):hover, textarea:not(:disabled):hover { border-color: var(--v-line-4); } }
/* focus d'un champ (recette du 2026-09-14, port du preset « md » sombre de border-beam) : plus d'anneau épais. Un faisceau blanc →
   bleu clair → gris parcourt le contour de 1 px ; sous lui, un contour fixe à 40 % (≈ 3,7:1 sur le fond du champ) garde le
   focus visible sans l'animation. Le faisceau est peint dans la bordure même (`border-box` sous un fond `padding-box`) :
   un `<input>` n'a pas de pseudo-élément, et aucun champ n'a besoin d'un conteneur supplémentaire. `:not(:disabled)` pour
   passer après le contour du survol. Le conic-gradient reste écrit ici : une variable déclarée sur `:root` y figerait
   `--v-beam` (propriété non héritée). Même faisceau sur la case active du code à 6 chiffres (plutôt que sur le vrai champ
   transparent qui couvre les cases) ; `outline: none` y est sans effet. */
input:not(:disabled):focus-visible, textarea:not(:disabled):focus-visible, .slots:focus-within .slots-cells i[data-active="true"] {
  outline: none; border-color: transparent; box-shadow: none;
  background:
    linear-gradient(var(--v-bg-input), var(--v-bg-input)) padding-box,
    conic-gradient(from var(--v-beam), transparent 0%, transparent 54%, rgb(125 133 144 / 45%) 58%, rgb(143 184 232 / 80%) 64%, rgb(244 244 241 / 95%) 70%, rgb(143 184 232 / 70%) 73%, transparent 78%, transparent 100%) border-box,
    linear-gradient(rgb(255 255 255 / 40%), rgb(255 255 255 / 40%)) border-box;
  animation: vault-beam 2.8s linear infinite; /* 1,96 s du preset, ralenti de 30 % (recette du 2026-09-14) */
}
input:disabled, textarea:disabled { color: var(--v-text-secondary); border-color: var(--v-line-2); }
input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
textarea { resize: vertical; min-height: 6rem; }
.input-row { display: flex; align-items: center; gap: var(--v-space-2); }
.input-row input { flex: 1; min-width: 0; }
fieldset { border: 0; padding: 0; margin: var(--v-space-6) 0 0; }
fieldset legend { font-size: 0.875rem; color: var(--v-text-primary); font-weight: 600; margin-bottom: 0; }
fieldset .field:first-of-type { margin-top: var(--v-space-2); }

/* code à 6 chiffres en cases (session 25) : un seul vrai champ, six cases décoratives derrière lui. La police monospace est
   imposée : l'espacement des lettres est calculé sur l'avance de Plex Mono (0,6 em) pour poser un chiffre par case. */
.slots { --slot: 2.75rem; --gap: 0.5rem; --advance: 0.9rem; position: relative; width: calc(6 * var(--slot) + 5 * var(--gap)); max-width: 100%; }
.slots-cells { position: absolute; inset: 0; display: grid; grid-template-columns: repeat(6, var(--slot)); gap: var(--gap); pointer-events: none; }
.slots-cells i { display: block; height: 100%; border: 1px solid var(--v-line-3); border-radius: var(--v-radius-small); background: var(--v-bg-input); transition: border-color var(--v-motion-fast) var(--v-ease-state), box-shadow var(--v-motion-fast) var(--v-ease-state); }
.slots:focus-within .slots-cells i { border-color: var(--v-accent-line); }
.slots-cells i[data-filled="true"] { border-color: var(--v-line-4); }
input.slots-input, input.slots-input:focus-visible {
  position: relative; width: calc(6 * (var(--slot) + var(--gap))); min-height: 3.25rem; padding: 0 0 0 calc((var(--slot) - var(--advance)) / 2);
  /* `outline: none` explicite : le vrai champ couvre les 6 cases, un contour de focus y dessinait un cadre autour du groupe (mesuré, recette du 2026-09-14) */
  background: transparent; border-color: transparent; box-shadow: none; border-radius: 0; animation: none; outline: none;
  font-family: var(--v-font-mono); font-size: 1.5rem; line-height: 3.25rem; font-weight: 500; letter-spacing: calc(var(--slot) + var(--gap) - var(--advance)); font-variant-numeric: tabular-nums;
}

/* --- alertes (texte explicite, jamais la couleur seule) : contour 1 px, icône, pas de barre latérale ------------------ */

.alert { display: flex; gap: 0.625rem; margin-top: var(--v-space-4); padding: 0.75rem 0.875rem; border-radius: var(--v-radius-control); border: 1px solid; font-size: 0.875rem; line-height: 1.25rem; text-align: left; }
.alert > .icon { margin-top: 0.125rem; }
.alert strong { font-weight: 600; }
.alert-danger { background: var(--v-danger-bg); border-color: rgb(242 139 139 / 30%); }
.alert-danger > .icon, .alert-danger strong { color: var(--v-danger); }
.alert-warning { background: var(--v-warning-bg); border-color: rgb(227 192 124 / 30%); }
.alert-warning > .icon, .alert-warning strong { color: var(--v-warning); }
.alert-info { background: var(--v-info-bg); border-color: rgb(143 184 232 / 30%); }
.alert-info > .icon, .alert-info strong { color: var(--v-info); }

/* --- loader (session 25, dérogation explicite du Security Owner ; motif remplacé le 2026-09-15) : port CSS pur du « animated
   loader » fourni — sept carrés qui glissent tour à tour sur une grille 3 × 3 tournée de 45°, une case toujours libre, cycle de
   10 s. Retirés du composant : bascule clair / sombre (l'extension est sombre), grille de fond, `<style>` en ligne (CSP). Le
   déplacement passe par `transform` (jamais `left` / `top`, qui recalculent la mise en page) ; décalages posés en `nth-child`. */

.loader { display: flex; flex-direction: column; align-items: center; gap: var(--v-space-6); padding: var(--v-space-6) 0 var(--v-space-2); text-align: center; }
/* la grille tournée déborde de ~20 px de chaque côté : marge verticale pour ne pas toucher le titre */
.loader-grid { position: relative; width: 6rem; height: 6rem; margin-block: 1.25rem; transform: rotate(45deg); }
.loader-square { position: absolute; top: 0; left: 0; width: 1.75rem; height: 1.75rem; margin: 0.125rem; background: var(--v-text-primary); animation: loader-square 14.7058823529s ease-in-out infinite both; }
/* ralenti deux fois (recette du 2026-09-15) : −20 % puis −15 %, soit 0,68 × la vitesse d'origine — 10 s → 12,5 s → 14,706 s ;
   décalage d'un carré à l'autre = cycle / 7 */
.loader-square:nth-child(2) { animation-delay: -2.1008403361s; }
.loader-square:nth-child(3) { animation-delay: -4.2016806723s; }
.loader-square:nth-child(4) { animation-delay: -6.3025210084s; }
.loader-square:nth-child(5) { animation-delay: -8.4033613445s; }
.loader-square:nth-child(6) { animation-delay: -10.5042016807s; }
.loader-square:nth-child(7) { animation-delay: -12.6050420168s; }
@keyframes loader-square {
  0%, 10.5% { transform: translate(0, 0); }
  12.5%, 23% { transform: translate(2rem, 0); }
  25%, 35.5% { transform: translate(4rem, 0); }
  37.5%, 48% { transform: translate(4rem, 2rem); }
  50%, 60.5% { transform: translate(2rem, 2rem); }
  62.5%, 73% { transform: translate(2rem, 4rem); }
  75%, 85.5% { transform: translate(0, 4rem); }
  87.5%, 98% { transform: translate(0, 2rem); }
  100% { transform: translate(0, 0); }
}
.loader-text { display: flex; flex-direction: column; gap: 0.375rem; max-width: 30ch; }
.loader-title { font-size: 1rem; line-height: 1.5rem; font-weight: 500; letter-spacing: -0.01em; animation: loader-pulse-strong 3s var(--v-ease-in-out) infinite; }
.loader-sub { font-size: 0.875rem; line-height: 1.25rem; color: var(--v-text-muted); animation: loader-pulse-soft 4s var(--v-ease-in-out) infinite; }
@keyframes loader-pulse-strong { 0%, 100% { opacity: 0.92; } 50% { opacity: 0.7; } }
@keyframes loader-pulse-soft { 0%, 100% { opacity: 1; } 50% { opacity: 0.66; } }

/* --- écrans d'authentification (charte §10) ------------------------------------------------------------------------ */

.auth { min-height: 100vh; display: grid; grid-template-rows: 1fr auto; justify-items: center; padding: var(--v-space-6) var(--v-space-4); }
.auth-panel {
  position: relative; isolation: isolate; width: min(27rem, 100%); align-self: center;
  padding: var(--v-space-8) 1.75rem var(--v-space-5); background: var(--v-veil-panel);
  -webkit-backdrop-filter: blur(18px) saturate(140%); backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid var(--v-line-2); border-radius: var(--v-radius-panel);
  box-shadow: var(--v-shadow-panel), var(--v-edge-highlight);
  animation: vault-panel-enter var(--v-motion-standard) var(--v-ease-out);
}
/* faisceau d'attente (inspiration « border beam ») : un trait d'accent parcourt la bordure tant que la page attend un geste sur
   la clé ou l'ouverture du coffre — l'attente est réelle, le mouvement dit l'état ; jamais au repos */
.auth-panel::before {
  content: ""; position: absolute; inset: -1px; border-radius: inherit; padding: 1px; pointer-events: none; z-index: 1;
  background: conic-gradient(from var(--v-beam), transparent 0deg, transparent 230deg, var(--v-accent) 300deg, transparent 340deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); mask-composite: exclude;
  opacity: 0; transition: opacity var(--v-motion-standard) var(--v-ease-state);
}
.auth-panel[data-wait="true"]::before { opacity: 1; animation: vault-beam 3.71s linear infinite; } /* 2,6 s ralenti de 30 % (recette du 2026-09-14) */
@keyframes vault-beam { to { --v-beam: 360deg; } }
/* bandeau d'état : Compte et Coffre, deux informations distinctes (charte §10), sur une seule ligne à toute largeur */
.auth-status { display: grid; grid-template-columns: 1fr 1fr; gap: var(--v-space-2); padding-bottom: var(--v-space-5); border-bottom: 1px solid var(--v-line-1); }
.status-item { display: flex; align-items: center; justify-content: space-between; gap: var(--v-space-2); min-height: 2.125rem; padding: 0 0.3125rem 0 0.625rem; border-radius: var(--v-radius-small); background: rgb(255 255 255 / 3%); border: 1px solid var(--v-line-1); font-size: 0.75rem; line-height: 1rem; color: var(--v-text-muted); }
.status-key { font-weight: 500; }
.auth-tagline { margin: var(--v-space-5) 0 0; color: var(--v-text-secondary); text-align: center; font-size: 0.9375rem; }
.auth-head { display: flex; flex-direction: column; align-items: center; gap: var(--v-space-3); margin-top: var(--v-space-5); text-align: center; }
.title-icon { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 3rem; height: 3rem; border-radius: 0.875rem; background: var(--v-accent-soft); border: 1px solid var(--v-accent-line); color: var(--v-accent); box-shadow: inset 0 1px 0 rgb(255 255 255 / 8%); }
.title-icon .icon { width: 1.25rem; height: 1.25rem; }
.auth-title { font-size: 1.5rem; line-height: 2rem; font-weight: 600; letter-spacing: -0.02em; }
.auth-panel > p { color: var(--v-text-secondary); text-align: center; margin-top: var(--v-space-3); }
.auth-panel > p.hint { margin-top: var(--v-space-2); }
.auth-panel > .alert { text-align: left; }
.auth-panel .actions { flex-direction: column; gap: var(--v-space-2); margin-top: var(--v-space-5); }
.auth-panel .actions .btn { width: 100%; min-width: 0; min-height: var(--v-control-height-touch); }
.auth-panel .actions .btn-ghost { min-height: var(--v-control-height); }
.auth-panel input:not(.slots-input) { min-height: var(--v-control-height-touch); }
.auth-panel .slots { margin: 0 auto; }
.auth-panel[data-wait="true"] .actions { display: none; }
/* effet « Matrix » (dérogation charte §14/§15, session 13, src/matrix-text.ts) : la largeur d'une lettre reste celle du
   caractère réel (seul enfant dans le flux) ; le chiffre est superposé en position absolue et centré, donc le brouillage
   ne décale jamais la mise en page et n'étire pas le texte au repos. Les mots restent insécables. */
.mx-w { white-space: nowrap; }
.mx { position: relative; display: inline-block; }
.mx-g { position: absolute; left: 50%; top: 0; transform: translateX(-50%); visibility: hidden; color: var(--v-matrix); text-shadow: 0 2px 4px var(--v-matrix-glow); font-variant-numeric: tabular-nums; }
.mx[data-on="1"] .mx-c { visibility: hidden; }
.mx[data-on="1"] .mx-g { visibility: visible; }
/* ligne de confiance dans la carte : version et RP ID, faits vérifiables, pas un slogan */
.auth-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0.375rem 0.5rem; margin-top: var(--v-space-5); padding-top: var(--v-space-4); border-top: 1px solid var(--v-line-1); font-size: 0.75rem; line-height: 1.125rem; color: var(--v-text-muted); text-align: center; }
.auth-foot code { font-size: 0.75rem; color: var(--v-text-secondary); }
.key-display { margin: var(--v-space-4) 0; padding: var(--v-space-4); font-size: 1.125rem; line-height: 1.875rem; letter-spacing: 0.06em; word-break: break-all; user-select: all; text-align: center; background: var(--v-bg-input); border: 1px solid var(--v-line-3); border-radius: var(--v-radius-control); color: var(--v-text-primary); }
.secret-line { margin-top: var(--v-space-3); word-break: break-all; }
.qr { display: block; width: 12.5rem; height: 12.5rem; margin: var(--v-space-4) auto; padding: var(--v-space-2); background: #fff; border-radius: var(--v-radius-small); }
@keyframes vault-panel-enter { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }

/* --- espace de travail (charte §5, §8, §9) ------------------------------------------------------------------------ */

.ws { display: grid; grid-template-columns: 17rem 22rem minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); height: 100vh; }
/* bandeau de remise à zéro du compte (ADR-020) : pleine largeur au-dessus des trois zones, à toute largeur d'écran ; vide, il
   ne prend aucune place — les trois zones sont placées explicitement pour que son absence ne déplace rien */
.ws-alert { grid-column: 1 / -1; grid-row: 1; display: flex; flex-wrap: wrap; align-items: center; gap: var(--v-space-3); padding: var(--v-space-3) var(--v-space-4); background: var(--v-veil-head); border-bottom: 1px solid var(--v-line-1); }
.ws-alert:empty { display: none; }
.ws-alert .alert { flex: 1 1 24rem; margin-top: 0; }
.ws-nav, .ws-list, .ws-detail { grid-row: 2; }
.ws-nav { display: flex; flex-direction: column; gap: var(--v-space-4); padding: var(--v-space-5) var(--v-space-4); background: var(--v-veil-nav); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px); border-right: 1px solid var(--v-line-1); overflow: auto; }

/* déclencheur du menu compte : initiales, adresse, état du compte ; menu opaque positionné par le script (jamais coupé par un
   conteneur défilant) — voir src/account-menu.ts */
.account { display: flex; align-items: center; gap: 0.625rem; width: 100%; padding: 0.5rem 0.625rem 0.5rem 0.5rem; background: rgb(255 255 255 / 4%); border: 1px solid var(--v-line-2); border-radius: var(--v-radius-control); color: var(--v-text-primary); font: inherit; text-align: left; cursor: pointer; transition: background-color var(--v-motion-fast) var(--v-ease-state), border-color var(--v-motion-fast) var(--v-ease-state); }
@media (hover: hover) { .account:hover { background: rgb(255 255 255 / 7%); border-color: var(--v-line-3); } }
.account[aria-expanded="true"] { border-color: var(--v-accent-line); background: rgb(255 255 255 / 7%); }
.avatar { flex: none; display: grid; place-items: center; width: 2rem; height: 2rem; border-radius: 50%; padding: 2px; background: conic-gradient(from 210deg, var(--v-hue-amber), var(--v-hue-coral), var(--v-hue-sky), var(--v-hue-amber)); }
.avatar span { display: grid; place-items: center; width: 100%; height: 100%; border-radius: 50%; background: var(--v-bg-raised); color: var(--v-text-primary); font-size: 0.6875rem; line-height: 1; font-weight: 600; letter-spacing: 0.04em; }
.avatar-lg { width: 2.5rem; height: 2.5rem; }
.avatar-lg span { font-size: 0.8125rem; }
.account-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.125rem; }
.account-name { font-size: 0.8125rem; line-height: 1.125rem; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.account-sub { display: flex; align-items: center; gap: 0.375rem; font-size: 0.75rem; line-height: 1rem; color: var(--v-text-muted); white-space: nowrap; }
.dot { flex: none; width: 0.375rem; height: 0.375rem; border-radius: 50%; background: var(--v-success); box-shadow: 0 0 0 3px rgb(127 209 160 / 18%); }
.account .chevron { color: var(--v-text-muted); transition: transform var(--v-motion-standard) var(--v-ease-out); }
.account[aria-expanded="true"] .chevron { transform: rotate(180deg); }
.account-menu { position: fixed; z-index: 30; width: 19.5rem; max-width: calc(100vw - 1rem); padding: 0.375rem; background: var(--v-bg-menu); border: 1px solid var(--v-line-3); border-radius: var(--v-radius-panel); box-shadow: var(--v-shadow-floating), var(--v-edge-highlight); transform-origin: top left; animation: vault-menu-enter 160ms var(--v-ease-out); }
.account-menu[data-origin="right"] { transform-origin: top right; }
@keyframes vault-menu-enter { from { opacity: 0; transform: scale(0.96) translateY(-4px); } to { opacity: 1; transform: none; } }
.menu-head { display: flex; align-items: center; gap: 0.75rem; padding: 0.625rem 0.625rem 0.75rem; }
.menu-head .account-text { gap: 0.25rem; }
.menu-head .account-name { font-size: 0.875rem; line-height: 1.25rem; }
.menu-figures, .nav-figures { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 0.375rem 0.75rem; margin: 0 0.25rem; padding: 0.625rem 0.5rem; border-top: 1px solid var(--v-line-1); border-bottom: 1px solid var(--v-line-1); font-size: 0.8125rem; line-height: 1.25rem; }
.menu-figures dt, .nav-figures dt { display: inline-flex; align-items: center; gap: 0.5rem; color: var(--v-text-secondary); min-width: 0; }
.menu-figures dt .icon, .nav-figures dt .icon { color: var(--v-text-muted); }
.menu-figures dd, .nav-figures dd { display: flex; justify-content: flex-end; }
.nav-figures { margin: 0; padding: 0.5rem 0; border-top: 0; }
/* repérage des chiffres de la barre latérale (recette du 2026-09-14) : identifiants en bleu clair, méthodes en ambre — jamais un état */
.nav-figures dt:nth-of-type(1) .icon { color: var(--v-hue-sky); }
.nav-figures dt:nth-of-type(2) .icon { color: var(--v-hue-amber); }
.menu-group { display: flex; flex-direction: column; gap: 0.125rem; padding: 0.375rem 0; }
.menu-item { display: flex; align-items: center; gap: 0.625rem; width: 100%; min-height: 2.25rem; padding: 0 0.625rem; border: 0; border-radius: var(--v-radius-small); background: transparent; color: var(--v-text-primary); font: 500 0.875rem/1.25rem var(--v-font-ui); text-align: left; cursor: pointer; transition: background-color var(--v-motion-fast) var(--v-ease-state), color var(--v-motion-fast) var(--v-ease-state); }
.menu-item .icon { color: var(--v-text-muted); }
.menu-item:hover, .menu-item:focus-visible { background: rgb(255 255 255 / 6%); outline: none; }
.menu-item:hover .icon, .menu-item:focus-visible .icon { color: var(--v-text-primary); }
.menu-item .badge { margin-left: auto; }
.menu-item.is-danger { color: var(--v-hue-coral); }
.menu-item.is-danger .icon { color: var(--v-hue-coral); }
.menu-item.is-danger:hover, .menu-item.is-danger:focus-visible { background: var(--v-hue-coral-bg); }
.menu-item.is-danger:hover .icon, .menu-item.is-danger:focus-visible .icon { color: var(--v-hue-coral); }
.menu-foot { margin: 0 0.25rem; padding: 0.5rem 0.5rem 0.25rem; border-top: 1px solid var(--v-line-1); font-size: 0.6875rem; line-height: 1rem; color: var(--v-text-muted); overflow-wrap: anywhere; }
.menu-foot code { display: block; font-size: 0.6875rem; color: var(--v-text-secondary); }
/* menu compte, couleur et contraste (recette du 2026-09-14) : en-tête et chiffres encadrés, icônes en tuiles teintées —
   sécurité et identifiants en bleu clair, génération de clés en ambre (mêmes repères que la barre latérale), « Verrouiller »
   en corail. Teintes de repérage : le libellé porte toujours le sens. Surface opaque, un reflet bleu très léger en haut. */
.account-menu { color: var(--v-text-primary); background: linear-gradient(180deg, rgb(143 184 232 / 6%), transparent 7rem), var(--v-bg-menu); border-color: var(--v-line-4); }
.account-menu .menu-head { margin-bottom: 0.25rem; background: rgb(255 255 255 / 4%); border: 1px solid var(--v-line-2); border-radius: var(--v-radius-control); }
.account-menu .menu-head .account-sub { color: var(--v-text-secondary); }
/* tuiles alignées sur celles du cadre des chiffres (1 px de bordure), libellés sur la même colonne */
.account-menu .menu-item { gap: 0.75rem; min-height: 2.5rem; padding: 0 calc(0.5rem + 1px); }
.account-menu .menu-figures dt { gap: 0.75rem; }
.account-menu .menu-item > .icon, .account-menu .menu-figures dt .icon { box-sizing: content-box; flex: none; width: 0.875rem; height: 0.875rem; padding: 0.3125rem; border: 1px solid; border-radius: 0.4375rem; }
.account-menu #menu-security > .icon, .account-menu .menu-figures dt:nth-of-type(1) .icon { color: var(--v-hue-sky); background: var(--v-hue-sky-bg); border-color: rgb(143 184 232 / 28%); }
.account-menu .menu-figures dt:nth-of-type(2) .icon { color: var(--v-hue-amber); background: var(--v-hue-amber-bg); border-color: rgb(240 190 90 / 28%); }
.account-menu #menu-lock > .icon { color: var(--v-hue-coral); background: var(--v-hue-coral-bg); border-color: rgb(242 139 139 / 28%); }
.account-menu .menu-figures { margin: 0.25rem 0; padding: 0.5rem; gap: 0.375rem 0.75rem; background: rgb(0 0 0 / 22%); border: 1px solid var(--v-line-2); border-radius: var(--v-radius-control); }
.account-menu .menu-figures dt { color: var(--v-text-primary); }
.account-menu .menu-figures dd:nth-of-type(1) .count { color: var(--v-hue-sky); background: var(--v-hue-sky-bg); border-color: rgb(143 184 232 / 28%); }
.account-menu .menu-figures dd:nth-of-type(2) .count { color: var(--v-hue-amber); background: var(--v-hue-amber-bg); border-color: rgb(240 190 90 / 28%); }
.account-menu .menu-foot { border-top-color: var(--v-line-2); color: var(--v-text-secondary); }
.account-menu .menu-foot code { color: var(--v-text-primary); }

/* coffre actif : trait de sélection vertical de 2 px, signature VAULT (charte §1) */
.nav-vault { display: flex; align-items: center; gap: var(--v-space-3); padding: 0.625rem 0.75rem; border-left: 2px solid var(--v-hue-amber); background: rgb(255 255 255 / 4%); border-radius: 0 var(--v-radius-small) var(--v-radius-small) 0; }
.nav-vault-icon { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 2.25rem; height: 2.25rem; border-radius: var(--v-radius-small); background: var(--v-hue-amber-bg); border: 1px solid rgb(240 190 90 / 24%); color: var(--v-hue-amber); }
.nav-vault-text { display: flex; flex-direction: column; min-width: 0; gap: 0.125rem; }
.nav-vault-name { font-size: 0.9375rem; line-height: 1.375rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-vault-kind { display: flex; align-items: center; gap: 0.375rem; font-size: 0.75rem; line-height: 1rem; color: var(--v-hue-amber); }
.nav-state { display: flex; flex-direction: column; gap: var(--v-space-3); }
.nav-hint { margin: 0; }
.nav-actions { display: flex; flex-direction: column; gap: var(--v-space-2); margin-top: auto; }
.nav-actions .btn { justify-content: flex-start; }
/* verrouillage : cadenas corail (action de sécurité repérable), contour corail au survol */
#lock .icon { color: var(--v-hue-coral); }
@media (hover: hover) { #lock:not(:disabled):hover { border-color: rgb(242 139 139 / 45%); } }

/* fond de la liste : voile léger sur le fond animé ; le body reste noir si le fond est inactif */
.ws-list { display: flex; flex-direction: column; min-height: 0; background: var(--v-veil-list); border-right: 1px solid var(--v-line-1); }
.list-head { display: flex; gap: var(--v-space-2); padding: var(--v-space-3); border-bottom: 1px solid var(--v-line-1); background: var(--v-veil-head); }
.list-head input { min-height: var(--v-control-height); background: var(--v-bg-input); border-color: var(--v-line-2); }
.list-head .btn-primary { min-height: var(--v-control-height); padding: 0 0.875rem; }
.search-wrap { position: relative; flex: 1; min-width: 0; }
.search-wrap .icon { position: absolute; left: 0.75rem; top: 50%; margin-top: -0.5rem; color: var(--v-text-muted); pointer-events: none; }
.search-wrap input { padding-left: 2.25rem; }
.list-body { flex: 1; min-height: 0; overflow: auto; }
.list-inner { display: flex; flex-direction: column; }
.list-meta { padding: var(--v-space-3) var(--v-space-4) var(--v-space-1); font-size: 0.75rem; line-height: 1rem; color: var(--v-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rows { list-style: none; padding: var(--v-space-1) 0; }
.row { display: flex; align-items: center; min-height: 3.75rem; padding: 0 var(--v-space-2) 0 0; border-left: 2px solid transparent; border-bottom: 1px solid var(--v-line-1); transition: background-color var(--v-motion-fast) var(--v-ease-state), border-color var(--v-motion-fast) var(--v-ease-state); }
@media (hover: hover) { .row:hover { background: rgb(255 255 255 / 4%); } }
.row.is-selected { background: rgb(255 255 255 / 7%); border-left-color: var(--v-accent); }
.row-main { display: flex; align-items: center; gap: var(--v-space-3); flex: 1; min-width: 0; min-height: 3.75rem; padding: var(--v-space-2) var(--v-space-2) var(--v-space-2) calc(var(--v-space-4) - 2px); background: none; border: 0; color: inherit; font: inherit; text-align: left; cursor: pointer; border-radius: var(--v-radius-small); }
.row-text { display: flex; flex-direction: column; min-width: 0; }
.row-name { font-size: 0.9375rem; line-height: 1.375rem; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row-user { font-size: 0.8125rem; line-height: 1.125rem; color: var(--v-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row.is-selected .row-user { color: var(--v-text-secondary); }
.row-spacer { width: var(--v-control-height-compact); flex: none; }
/* monogramme : teinte stable par nom pour le repérage — jamais une couleur d'état */
.monogram { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 2.25rem; height: 2.25rem; border-radius: var(--v-radius-small); background: var(--v-bg-raised); border: 1px solid var(--v-line-2); color: var(--v-text-secondary); font-family: var(--v-font-mono); font-size: 0.9375rem; font-weight: 500; text-transform: uppercase; }
.monogram[data-tint="1"] { background: var(--v-hue-sky-bg); color: var(--v-hue-sky); border-color: rgb(143 184 232 / 24%); }
.monogram[data-tint="2"] { background: var(--v-hue-amber-bg); color: var(--v-hue-amber); border-color: rgb(240 190 90 / 24%); }
.monogram[data-tint="3"] { background: var(--v-hue-coral-bg); color: var(--v-hue-coral); border-color: rgb(242 139 139 / 24%); }
.monogram[data-tint="4"] { background: var(--v-bg-selected); color: var(--v-text-primary); border-color: var(--v-line-3); }
.monogram[data-tint="5"] { background: rgb(255 255 255 / 9%); color: var(--v-text-primary); border-color: var(--v-line-2); }
.row.is-selected .monogram { border-color: var(--v-accent-line); }
.monogram-lg { width: 3rem; height: 3rem; font-size: 1.25rem; border-radius: var(--v-radius-control); }
/* états vides : une tuile d'icône, une phrase, une action — jamais un simple « rien ici » */
.empty { padding: var(--v-space-10) var(--v-space-4); text-align: center; color: var(--v-text-secondary); display: flex; flex-direction: column; align-items: center; gap: var(--v-space-3); }
.empty-icon { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 3.5rem; height: 3.5rem; margin-bottom: var(--v-space-2); border-radius: 0.875rem; background: var(--v-bg-raised); border: 1px solid var(--v-line-3); color: var(--v-text-secondary); box-shadow: var(--v-edge-highlight); }
.empty-icon::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; border: 1px solid var(--v-line-2); background: var(--v-bg-surface); transform: rotate(-8deg) translate(-6px, 2px); }
.empty-icon .icon { width: 1.5rem; height: 1.5rem; }
.empty .btn { margin-top: var(--v-space-2); }

.ws-detail { min-height: 0; overflow: auto; background: var(--v-veil-detail); padding: var(--v-space-6) var(--v-space-8); }
.detail { max-width: 46rem; animation: vault-panel-enter var(--v-motion-standard) var(--v-ease-out); }
.detail-head { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--v-space-4); padding-bottom: var(--v-space-5); border-bottom: 1px solid var(--v-line-1); }
.detail-title { display: flex; align-items: center; gap: var(--v-space-3); flex: 1 1 18rem; min-width: 0; } /* base 18 rem : les actions passent à la ligne avant d'écraser le titre */
.detail-title-text { min-width: 0; }
.detail-title-text h2 { font-size: 1.5rem; line-height: 2rem; letter-spacing: -0.02em; overflow-wrap: anywhere; }
.detail-title-text h2 .title-icon { width: 2.25rem; height: 2.25rem; border-radius: var(--v-radius-small); margin-right: var(--v-space-3); vertical-align: middle; }
.detail-title-text h2 .title-icon .icon { width: 1rem; height: 1rem; }
.detail-sub { font-size: 0.875rem; line-height: 1.25rem; color: var(--v-text-muted); overflow-wrap: anywhere; }
.detail-actions { margin-left: auto; display: flex; flex-wrap: wrap; gap: var(--v-space-2); }
.detail-empty { display: flex; flex-direction: column; align-items: center; gap: var(--v-space-3); padding: var(--v-space-12) var(--v-space-4); text-align: center; color: var(--v-text-secondary); }
#back { display: none; }
.kvs { display: flex; flex-direction: column; padding-top: var(--v-space-2); }
.kv { padding: 0.875rem 0; border-bottom: 1px solid var(--v-line-1); }
/* libellés de la fiche en bleu clair (recette du 2026-09-14) : repérage du champ, la valeur reste en blanc */
.kv dt { display: flex; align-items: center; gap: var(--v-space-2); font-size: 0.75rem; line-height: 1rem; font-weight: 500; letter-spacing: 0.02em; color: var(--v-hue-sky); margin-bottom: 0.375rem; }
.kv dt .icon { width: 0.875rem; height: 0.875rem; color: var(--v-hue-sky); }
.kv dd { display: flex; align-items: center; gap: var(--v-space-3); min-height: 2.25rem; }
.kv-value .value { font-size: 1rem; line-height: 1.5rem; }
.kv-value .value.mono { font-size: 0.9375rem; }
.kv-actions .btn-ghost { color: var(--v-hue-amber); }
.kv-actions .btn-ghost:not(:disabled):hover { color: var(--v-hue-amber); background: var(--v-hue-amber-bg); }
.kv-value { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.kv-actions { flex: none; display: flex; align-items: center; gap: var(--v-space-1); min-width: 5.75rem; justify-content: flex-end; }
.value.secret { letter-spacing: 0.04em; user-select: all; }
.value.notes { white-space: pre-wrap; }
.value a { display: inline-flex; align-items: center; gap: var(--v-space-1); overflow-wrap: anywhere; }
.detail-feedback { min-height: 1.25rem; font-size: 0.8125rem; line-height: 1.25rem; margin-top: var(--v-space-3); }
.copy-feedback[data-state="ok"] { color: var(--v-success); }
.copy-feedback[data-state="failed"] { color: var(--v-danger); }
.detail-meta { margin-top: var(--v-space-4); font-size: 0.8125rem; line-height: 1.25rem; color: var(--v-text-muted); font-variant-numeric: tabular-nums; }
.editor .detail-head { border-bottom: 0; padding-bottom: 0; }
.form-actions { display: flex; flex-wrap: wrap; gap: var(--v-space-2); margin-top: var(--v-space-8); }

/* écran intermédiaire : barre compacte (logo, coffre, compte) ; Sécurité et Verrouiller vivent dans le menu compte */
@media (max-width: 79.99rem) {
  .ws { grid-template-columns: 20rem minmax(0, 1fr); grid-template-rows: auto auto minmax(0, 1fr); }
  .ws-nav { grid-row: 2; }
  .ws-list, .ws-detail { grid-row: 3; }
  .ws-nav { grid-column: 1 / -1; flex-direction: row; align-items: center; gap: var(--v-space-3); padding: var(--v-space-2) var(--v-space-3); min-height: 3.5rem; border-right: 0; border-bottom: 1px solid var(--v-line-1); background: var(--v-veil-head); overflow: visible; }
  .nav-vault { flex: 0 1 auto; min-width: 7rem; overflow: hidden; padding: 0.375rem 0.625rem; }
  .nav-vault-icon { width: 1.75rem; height: 1.75rem; }
  .nav-vault-icon .icon { width: 0.875rem; height: 0.875rem; }
  .nav-vault-name { font-size: 0.875rem; line-height: 1.25rem; }
  .nav-vault-kind { display: none; }
  .account { flex: 0 1 17rem; min-width: 0; width: auto; margin-left: auto; }
  .nav-state { display: none; }
  /* « Verrouiller » reste visible à toute largeur (charte §5, V16) : les deux actions passent en ligne, après le compte */
  .nav-actions { flex-direction: row; margin: 0; flex: none; }
}

/* petit écran : une zone à la fois, retour explicite ; le déclencheur du compte se réduit aux initiales */
@media (max-width: 47.99rem) {
  .ws { grid-template-columns: minmax(0, 1fr); }
  .ws[data-pane="list"] .ws-detail { display: none; }
  .ws[data-pane="detail"] .ws-list { display: none; }
  .ws-list { border-right: 0; }
  .ws-detail { padding: var(--v-space-4); }
  .account-text { display: none; }
  .account { flex: none; padding: 0.25rem 0.375rem 0.25rem 0.25rem; }
  /* 320–767 px : le logo quitte le bandeau (l'identité est portée par le compte et le coffre), la puce coffre prend la place restante */
  .ws-nav .wordmark { display: none; }
  .nav-vault { flex: 1 1 auto; min-width: 0; }
  /* actions du rail en icônes seules : le libellé reste dans l'arbre d'accessibilité (rendu, seulement rogné) */
  .nav-actions .btn { padding: 0 0.625rem; }
  .nav-actions .btn-label { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  #back { display: inline-flex; }
  .detail-head #back { flex-basis: 100%; }
  .kv-actions { min-width: 0; }
}

/* --- fond animé WebGL adaptatif (src/backdrop.ts) — dérogation explicite du Security Owner à la charte §14/§15/§19, session 12.
   Canvas fixe derrière la page (jamais au-dessus d'un contenu), mode auto sans contrôle ; les grandes surfaces (navigation,
   liste, fiche, panneau d'authentification) sont des voiles translucides (tokens --v-veil-*), champs et contrôles restent
   opaques. Sans WebGL : canvas masqué, la page garde le fond noir du body. */
#backdrop { position: fixed; inset: 0; z-index: 0; display: block; width: 100%; height: 100%; opacity: 0; pointer-events: none; transition: opacity 500ms var(--v-ease-out); }
#backdrop[data-ready="true"] { opacity: 1; }
#app { position: relative; z-index: 1; }

/* `hidden` doit toujours cacher. Une règle d'auteur `display` (ex. `.popup-list { display: grid }`) bat la feuille UA et
   annulait `el.hidden = true` : la liste de la popup — carte « ce site », « Remplir » — restait affichée après « Verrouiller »,
   invisible seulement tant qu'elle était vide (mesuré en recette, session 19, écart 41). Vaut pour les trois pages, et
   remplace la règle `#backdrop[hidden]` qu'elle rendait morte (session 20). */
[hidden] { display: none !important; }

/* --- popup ----------------------------------------------------------------------------------------------------------- */

/* Étape 7 b (charte §12), refonte session 25 : interface d'action rapide — en-tête compact (logo qui ouvre VAULT, badge d'état à
   point, coffre actif, « Verrouiller »), carte du site (hôte, activation), tableau des identifiants (recherche en en-tête,
   monogramme, badge de correspondance, « Remplir » explicite). Cible 400 px, repli à 320 px. Fond « Particle Drift » derrière
   (plus bas) ; champs et boutons restent opaques. */
body.popup { width: 25rem; max-width: 100%; padding: 0; background: var(--v-bg-canvas); }
.popup-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "logo status" "vault lock"; align-items: center; gap: 0.5rem var(--v-space-3); padding: 0.75rem var(--v-space-4); background: var(--v-bg-surface); border-bottom: 1px solid var(--v-line-2); box-shadow: var(--v-edge-highlight); }
/* verrouillée : ni coffre ni « Verrouiller », la seconde rangée ne laisse aucun espace vide */
body.popup .popup-head:has(> #lock[hidden]):has(> .popup-vault:empty) { row-gap: 0; }
.popup-head .wordmark { grid-area: logo; }
/* état : badge à point (`.badge-dot`, teinte posée par popup.ts) — le texte « État : … » porte le sens, jamais la couleur seule */
.popup-status { grid-area: status; justify-self: end; margin: 0; }
.popup-vault { grid-area: vault; display: flex; align-items: center; gap: 0.375rem; min-width: 0; margin: 0; color: var(--v-text-secondary); font-size: 0.8125rem; line-height: 1.125rem; font-weight: 500; }
.popup-vault > .icon { width: 0.875rem; height: 0.875rem; }
.popup-vault > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.popup-vault:empty { display: none; }
/* « Verrouiller » : contour rouge léger et halo discret par défaut (recette du 2026-09-14) ; le libellé porte l'action. Opaque. */
body.popup #lock { grid-area: lock; justify-self: end; gap: 0.375rem; min-height: 1.75rem; padding: 0 0.625rem; font-size: 0.75rem; border-radius: var(--v-radius-small); color: var(--v-danger); background: var(--v-bg-raised); border-color: rgb(242 139 139 / 45%); box-shadow: 0 0 10px -3px rgb(242 139 139 / 45%); }
@media (hover: hover) { body.popup #lock:not(:disabled):hover { color: var(--v-danger); background: color-mix(in srgb, var(--v-danger) 10%, var(--v-bg-raised)); border-color: rgb(242 139 139 / 75%); box-shadow: 0 0 14px -2px rgb(242 139 139 / 55%); } }
body.popup #lock .icon { width: 0.875rem; height: 0.875rem; }
.popup-host { display: flex; align-items: center; gap: var(--v-space-2); margin: 0; padding: 0.625rem 0.75rem; color: var(--v-text-primary); font-size: 0.8125rem; line-height: 1.125rem; font-weight: 600; }
.popup-host > .icon { width: 0.875rem; height: 0.875rem; color: var(--v-text-muted); }
.popup-host > span { min-width: 0; overflow-wrap: anywhere; } /* l'hôte reste lisible en entier (Punycode compris), jamais tronqué */
.popup-host:empty { display: none; }
/* zones cadrées (recette du 2026-09-14) : le site de l'onglet et le tableau des identifiants sont deux surfaces relevées du
   fond, contour de 1 px ; l'en-tête du tableau, plus clair, porte la recherche ; les lignes sont séparées par un filet */
.popup-card { margin: var(--v-space-3) var(--v-space-4) 0; background: var(--v-bg-raised); border: 1px solid var(--v-line-2); border-radius: var(--v-radius-control); box-shadow: var(--v-edge-highlight); overflow: hidden; }
/* alerte de remise à zéro (ADR-020 b) : première carte de la popup, teinte de danger portée par la bordure ET le titre —
   jamais par la couleur seule (CLAUDE.md §19 : aucun état critique indiqué uniquement par une couleur), le texte le dit. */
.popup-alert { border-color: rgb(242 139 139 / 32%); background: var(--v-danger-bg); }
.popup-alert:empty { display: none; }
.popup-alert > * { margin: 0; }
.popup-alert { display: flex; flex-direction: column; align-items: flex-start; gap: 0.5rem; padding: 0.625rem 0.75rem; }
.popup-alert-title { display: flex; align-items: center; gap: 0.375rem; color: var(--v-danger); font-size: 0.8125rem; font-weight: 600; line-height: 1.125rem; }
.popup-alert-title .icon { width: 0.875rem; height: 0.875rem; }
.popup-alert-text { color: var(--v-text-primary); font-size: 0.75rem; line-height: 1.0625rem; }
.popup-alert-note { color: var(--v-text-secondary); }
.popup-search { padding: 0.5rem; background: var(--v-bg-hover); border-bottom: 1px solid var(--v-line-2); }
.popup-search:has(+ .popup-list:is(:empty, [hidden])) { border-bottom: 0; }
.popup-search .search-wrap .icon { left: 0.625rem; width: 0.875rem; height: 0.875rem; margin-top: -0.4375rem; }
.popup-search input { min-height: 2rem; padding: 0.25rem 0.625rem 0.25rem 2rem; background: var(--v-bg-input); border-color: var(--v-line-2); border-radius: var(--v-radius-small); font-size: 0.8125rem; line-height: 1.25rem; }
.popup-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; max-height: 15rem; overflow-y: auto; overscroll-behavior: contain; }
.popup-list:empty { display: none; } /* vidée (verrouillage, refus) : aucun espace mort avant le message */
/* ligne : monogramme (même repérage que la liste de l'espace de travail), nom + badge de correspondance, identifiant · hôte, « Remplir » */
.popup-row { display: flex; flex-direction: column; gap: 0.5rem; padding: 0.5rem 0.625rem 0.5rem 0.75rem; border-bottom: 1px solid var(--v-line-1); transition: background-color var(--v-motion-fast) var(--v-ease-state); }
.popup-row:last-child { border-bottom: 0; }
@media (hover: hover) { .popup-row:hover { background: rgb(255 255 255 / 3%); } }
.popup-row[data-confirming="true"] { background: rgb(227 192 124 / 5%); }
.popup-row-main { display: flex; align-items: center; gap: 0.625rem; min-width: 0; }
.popup-row-main .monogram { width: 1.75rem; height: 1.75rem; font-size: 0.8125rem; border-radius: 0.4375rem; }
.popup-row-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.0625rem; }
/* le badge passe sous le nom quand la ligne est étroite (popup à 320 px) : jamais un nom cassé lettre à lettre */
.popup-row-head { display: flex; flex-wrap: wrap; align-items: center; gap: 0.125rem 0.375rem; min-width: 0; }
.popup-row-name { flex: 1 1 auto; min-width: 0; font-weight: 600; font-size: 0.8125rem; line-height: 1.125rem; overflow-wrap: anywhere; }
.popup-row-head .badge { min-height: 1.125rem; padding: 0 0.4375rem; font-size: 0.6875rem; line-height: 1rem; }
.popup-row-meta { margin: 0; color: var(--v-text-muted); font-size: 0.75rem; line-height: 1rem; overflow-wrap: anywhere; }
.popup-row-main .btn { flex: none; min-height: 1.75rem; padding: 0 0.625rem; font-size: 0.75rem; border-radius: var(--v-radius-small); }
/* « Remplir » en jaune (recette du 2026-09-14) : contour ambre plein et lueur ambre qui suit le pointeur, à la place du dégradé
   blanc → bleu des boutons principaux ; la « Confirmation » d'un autre site reste un bouton secondaire. Fond opaque. */
.popup-row .btn-primary { color: var(--v-hue-amber); background: linear-gradient(var(--v-bg-raised), var(--v-bg-raised)) padding-box, linear-gradient(115deg, #F6D58E, var(--v-hue-amber) 55%, #C99A3E) border-box; }
.popup-row .btn-primary::before { background: radial-gradient(100px circle at var(--spot-x, 50%) var(--spot-y, 50%), rgb(240 190 90 / 45%), rgb(0 0 0 / 15%)), linear-gradient(rgb(240 190 90 / 14%), rgb(240 190 90 / 14%)); }
@media (hover: hover) { .popup-row .btn-primary:not(:disabled):hover { background: linear-gradient(var(--v-bg-raised), var(--v-bg-raised)) padding-box, linear-gradient(115deg, #F6D58E, var(--v-hue-amber) 55%, #C99A3E) border-box; } }
/* Domaine inattendu (ADR-023 β) : les deux hôtes sont écrits dans une alerte, jamais portés par la seule couleur (charte §19). */
.popup-row .alert { margin: 0; padding: 0.5rem 0.625rem; font-size: 0.75rem; line-height: 1.0625rem; }
/* Les fonds d'alerte sont à 12 % : les glyphes du fond animé de la popup transparaissaient à travers l'encart de la
   seconde confirmation (ADR-023 β), l'écran qui écrit les deux hôtes. Base opaque sous la teinte, teinte inchangée
   (recette du 15 septembre 2026, défaut 2). */
.popup-row .alert-warning { background: linear-gradient(var(--v-warning-bg), var(--v-warning-bg)), var(--v-bg-surface); }
.popup-row .alert-danger { background: linear-gradient(var(--v-danger-bg), var(--v-danger-bg)), var(--v-bg-surface); }
.popup-row .alert-info { background: linear-gradient(var(--v-info-bg), var(--v-info-bg)), var(--v-bg-surface); }
.popup-row-actions { display: flex; gap: var(--v-space-2); }
.popup-row-actions .btn { min-height: 1.75rem; padding: 0 0.625rem; font-size: 0.75rem; border-radius: var(--v-radius-small); }
.popup-row-actions .btn-secondary { flex: 1; }
.popup-empty { display: flex; align-items: flex-start; gap: 0.625rem; margin: 0; padding: 0.75rem; color: var(--v-text-secondary); font-size: 0.75rem; line-height: 1.0625rem; }
.popup-empty > .icon { margin-top: 0.0625rem; width: 0.875rem; height: 0.875rem; color: var(--v-text-muted); }
.popup-empty p { margin: 0; }
.popup-feedback { margin: 0; padding: var(--v-space-3) var(--v-space-4) 0; color: var(--v-text-secondary); font-size: 0.75rem; line-height: 1.0625rem; }
.popup-feedback:empty { display: none; }
/* état verrouillé (recette du 2026-09-14) : la popup garde sa taille et un grand cadenas centré dit l'état — anneau en dégradé
   blanc → bleu → gris des boutons principaux, deux cercles concentriques très discrets, texte centré. Le badge de l'en-tête garde
   la teinte corail ; le texte porte l'état, jamais la couleur seule. */
.popup-state { display: flex; flex-direction: column; align-items: center; gap: 2.25rem; text-align: center; }
.popup-state-icon {
  position: relative; flex: none; display: grid; place-items: center; width: 5.5rem; height: 5.5rem; border-radius: 50%;
  border: 1px solid transparent; color: var(--v-text-primary);
  background: radial-gradient(circle at 50% 30%, rgb(255 255 255 / 7%), transparent 65%) padding-box, linear-gradient(var(--v-bg-raised), var(--v-bg-raised)) padding-box, var(--v-edge-gradient) border-box;
  box-shadow: 0 18px 32px -20px rgb(0 0 0 / 90%);
}
.popup-state-icon::before, .popup-state-icon::after { content: ""; position: absolute; border-radius: 50%; border: 1px solid rgb(255 255 255 / 7%); pointer-events: none; }
.popup-state-icon::before { inset: -0.75rem; }
.popup-state-icon::after { inset: -1.625rem; border-color: rgb(255 255 255 / 4%); }
.popup-state-icon .icon { width: 2.25rem; height: 2.25rem; stroke-width: 1.5; }
.popup-state-text { display: flex; flex-direction: column; align-items: center; gap: 0.375rem; min-width: 0; max-width: 30ch; }
.popup-state-title { font-size: 1.0625rem; line-height: 1.5rem; font-weight: 600; letter-spacing: -0.01em; color: var(--v-text-primary); }
.popup-state-sub { font-size: 0.8125rem; line-height: 1.25rem; color: var(--v-text-muted); }
/* « Ouvrir VAULT » porté par le logo (recette du 2026-09-14), popup et menu ancré : petite flèche d'ouverture, survol éclairci */
.wordmark-link { display: inline-flex; align-items: center; gap: 0.375rem; margin: -0.25rem -0.375rem; padding: 0.25rem 0.375rem; border: 0; border-radius: var(--v-radius-small); background: transparent; color: var(--v-text-muted); cursor: pointer; transition: background-color var(--v-motion-fast) var(--v-ease-state), color var(--v-motion-fast) var(--v-ease-state); }
.wordmark-link .icon { width: 0.75rem; height: 0.75rem; }
@media (hover: hover) { .wordmark-link:hover { background: rgb(255 255 255 / 6%); color: var(--v-text-primary); } .wordmark-link:hover .wordmark-logo { opacity: 1; } }
/* popup à taille fixe (recette du 2026-09-14) : 400 × 560 px quel que soit l'état — verrouillée, déverrouillée, une ou vingt
   lignes. Colonne à pas constant : 12 px entre blocs, 16 px sur les côtés et en bas. Le tableau garde la hauteur de son contenu,
   la liste défile quand elle déborde. La marge basse est portée par le body : celle du dernier enfant le traversait et Chrome
   dimensionnait la popup sans elle (le dernier bloc touchait le bord). */
body.popup:not(.menu) { display: flex; flex-direction: column; gap: var(--v-space-3); height: 35rem; min-height: 0; overflow: hidden; padding-bottom: var(--v-space-4); }
body.popup:not(.menu) > * { flex: none; }
body.popup:not(.menu) .popup-card { margin: 0 var(--v-space-4); }
body.popup:not(.menu) #search:not([hidden]) { display: flex; flex-direction: column; flex: 0 1 auto; min-height: 0; }
body.popup:not(.menu) .popup-search { flex: none; }
body.popup:not(.menu) .popup-list { flex: 1 1 auto; min-height: 0; max-height: none; }
body.popup:not(.menu) .popup-feedback { padding: 0 var(--v-space-4); }
body.popup:not(.menu) .popup-feedback:has(> .popup-state) { flex: 1 1 auto; min-height: 0; display: flex; align-items: center; justify-content: center; padding: 0 var(--v-space-6); }
/* fond « Particle Drift » (recette du 2026-09-14, dérogation explicite du Security Owner) : canvas décoratif derrière tout le
   contenu. En-tête et zones deviennent des voiles légers, sans flou : un flou de 4 px effaçait les glyphes de 12 px et le fond
   ne se voyait plus à travers (recette du 2026-09-14) ; champs et boutons restent opaques. Popup seulement : le menu ancré, encadré par des pages tierces, n'en a pas. */
.popup-particles { position: fixed; inset: 0; z-index: 0; display: block; width: 100%; height: 100%; pointer-events: none; }
body.popup:has(> .popup-particles) > :not(.popup-particles) { position: relative; z-index: 1; }
body.popup:has(> .popup-particles) .popup-head { background: rgb(14 16 18 / 90%); }
body.popup:has(> .popup-particles) .popup-card { background: rgb(17 19 22 / 50%); }
body.popup:has(> .popup-particles) .popup-search { background: rgb(28 31 35 / 50%); }

/* Menu ancré au champ (étape 7 c, ADR-025 ; refonte, recette du 2026-09-14) : cadre de 280 px, hauteur par paliers posée par
   l'ancrage (message seul, ou 1, 2, 3 lignes ; au-delà la liste défile) — hauteurs à tenir en phase avec `anchor.ts`. Petit
   logo (ouvre VAULT), « Fermer », puis les seuls identifiants de ce site ; la ligne entière remplit. Contour : le faisceau du
   focus des champs, en multicolore léger (ambre → corail → bleu clair), sur un contour fixe teinté et discret. */
body.popup.menu { width: 100%; height: 100vh; overflow: hidden; background: var(--v-bg-canvas); }
.menu-shell {
  position: relative; box-sizing: border-box; display: flex; flex-direction: column; height: 100vh; border: 1px solid transparent; border-radius: 10px;
  background:
    linear-gradient(var(--v-bg-menu), var(--v-bg-menu)) padding-box,
    conic-gradient(from var(--v-beam), transparent 0%, transparent 46%, rgb(240 190 90 / 55%) 56%, rgb(242 139 139 / 60%) 63%, rgb(143 184 232 / 75%) 70%, rgb(244 244 241 / 60%) 74%, transparent 82%, transparent 100%) border-box,
    linear-gradient(115deg, rgb(240 190 90 / 24%), rgb(242 139 139 / 20%) 50%, rgb(143 184 232 / 26%)) border-box;
  animation: vault-beam 4.2s linear infinite;
}
.menu-bar { flex: none; display: flex; align-items: center; justify-content: space-between; height: 2.5rem; padding: 0 0.375rem 0 0.75rem; }
body.popup.menu .wordmark-logo { height: 0.75rem; }
body.popup.menu #close { width: 1.75rem; min-height: 1.75rem; }
.menu-list { flex: 1 1 auto; min-height: 0; list-style: none; margin: 0; padding: 0 0.375rem 0.375rem; overflow-y: auto; overscroll-behavior: contain; }
.menu-list:empty { display: none; }
.menu-list li + li { margin-top: 0.125rem; }
.menu-row {
  display: flex; flex-direction: column; justify-content: center; gap: 0.0625rem; box-sizing: border-box; width: 100%; height: 2.875rem; padding: 0 0.625rem;
  border: 1px solid transparent; border-radius: var(--v-radius-small); background: transparent; color: var(--v-text-primary); font: inherit; text-align: left; cursor: pointer;
  transition: background-color var(--v-motion-fast) var(--v-ease-state), border-color var(--v-motion-fast) var(--v-ease-state), transform 160ms var(--v-ease-out);
}
@media (hover: hover) { .menu-row:hover { background: rgb(255 255 255 / 6%); border-color: var(--v-line-2); } }
.menu-row:active { transform: scale(0.98); }
.menu-row-name, .menu-row-user { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.menu-row-name { font-size: 0.8125rem; line-height: 1.125rem; font-weight: 600; }
.menu-row-user { font-size: 0.75rem; line-height: 1rem; color: var(--v-text-muted); }
.menu-feedback { margin: 0; padding: 0 0.75rem 0.625rem; color: var(--v-text-secondary); font-size: 0.75rem; line-height: 1.0625rem; }
.menu-feedback:empty { display: none; }
/* avec des lignes, un message (remplissage en cours, échec) se pose sur le bas de la liste, sans changer le palier */
.menu-list:not(:empty) ~ .menu-feedback:not(:empty) { position: absolute; left: 0.375rem; right: 0.375rem; bottom: 0.375rem; padding: 0.5rem 0.625rem; background: var(--v-bg-raised); border: 1px solid var(--v-line-3); border-radius: var(--v-radius-small); }

/* Activation site par site de l'icône dans les champs (étape 7 c, ADR-025 décision 2 b). */
.popup-site { display: flex; align-items: flex-start; gap: 0.625rem; padding: 0.625rem 0.75rem; border-top: 1px solid var(--v-line-1); background: rgb(0 0 0 / 18%); }
.popup-site > .icon { margin-top: 0.125rem; width: 0.875rem; height: 0.875rem; color: var(--v-text-muted); }
.popup-site-body { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--v-space-2) var(--v-space-3); }
.popup-site-text { flex: 1 1 11rem; margin: 0; color: var(--v-text-secondary); font-size: 0.75rem; line-height: 1.0625rem; }
.popup-site .btn { flex: 0 1 auto; max-width: 100%; min-height: 1.75rem; padding: 0.25rem 0.625rem; font-size: 0.75rem; line-height: 1rem; white-space: normal; text-align: left; border-radius: var(--v-radius-small); }
/* Accès accordé (recette du 2026-09-14) : une seule ligne — hôte à gauche, « Retirer l'accès » en contour rouge à droite ;
   l'explication devient une infobulle au survol ou au focus clavier du bouton. Le libellé porte l'action, jamais la couleur
   seule. Carte au-dessus du tableau et sans rognage pour que l'infobulle déborde. Bouton opaque (fond animé, V18). */
#site[data-granted="true"] { display: flex; align-items: center; z-index: 2; overflow: visible; }
#site[data-granted="true"] .popup-host { flex: 1; min-width: 0; }
#site[data-granted="true"] .popup-site { flex: none; padding: 0 0.625rem 0 0; border-top: 0; background: none; }
#site[data-granted="true"] .popup-site > .icon { display: none; }
#site[data-granted="true"] .popup-site-body { position: relative; }
.popup-site .btn.is-danger { color: var(--v-danger); border-color: rgb(242 139 139 / 55%); background: var(--v-bg-raised); }
/* « Activer sur … » (recette du 2026-09-14) : contour vert et halo discret par défaut ; le libellé porte l'action. Opaque. */
.popup-site .btn.is-success { color: var(--v-success); border-color: rgb(127 209 160 / 50%); background: var(--v-bg-raised); box-shadow: 0 0 10px -3px rgb(127 209 160 / 45%); }
@media (hover: hover) { .popup-site .btn.is-success:not(:disabled):hover { color: var(--v-success); border-color: rgb(127 209 160 / 80%); background: color-mix(in srgb, var(--v-success) 10%, var(--v-bg-raised)); box-shadow: 0 0 14px -2px rgb(127 209 160 / 55%); } }
@media (hover: hover) { .popup-site .btn.is-danger:not(:disabled):hover { color: var(--v-danger); border-color: var(--v-danger); background: color-mix(in srgb, var(--v-danger) 12%, var(--v-bg-raised)); } }
#site[data-granted="true"] .popup-site-text {
  position: absolute; top: calc(100% + 0.5rem); right: 0; z-index: 3; width: 15rem;
  display: flex; flex-direction: column; gap: 0.25rem; padding: 0.625rem 0.75rem;
  background: var(--v-bg-surface); border: 1px solid var(--v-line-3); border-radius: var(--v-radius-small);
  box-shadow: var(--v-edge-highlight), 0 14px 30px -12px rgb(0 0 0 / 90%);
  opacity: 0; visibility: hidden; transform: translateY(-0.25rem) scale(0.97); transform-origin: top right; pointer-events: none;
  transition: opacity 100ms var(--v-ease-out), transform 100ms var(--v-ease-out), visibility 0s linear 100ms;
}
#site[data-granted="true"] .popup-site-text::before { content: ""; position: absolute; top: -0.3125rem; right: 2.875rem; width: 0.5rem; height: 0.5rem; background: inherit; border: solid var(--v-line-3); border-width: 1px 0 0 1px; transform: rotate(45deg); }
/* entrée retardée (évite l'ouverture accidentelle au passage du pointeur), sortie immédiate */
#site[data-granted="true"] .popup-site-body:has(> .btn:focus-visible) > .popup-site-text { opacity: 1; visibility: visible; transform: none; transition: opacity 150ms var(--v-ease-out) 250ms, transform 150ms var(--v-ease-out) 250ms, visibility 0s linear 250ms; }
@media (hover: hover) { #site[data-granted="true"] .popup-site-body:has(> .btn:hover) > .popup-site-text { opacity: 1; visibility: visible; transform: none; transition: opacity 150ms var(--v-ease-out) 250ms, transform 150ms var(--v-ease-out) 250ms, visibility 0s linear 250ms; } }
.popup-tip-title { color: var(--v-text-primary); font-weight: 600; }
.popup-tip-note { color: var(--v-text-muted); }
/* ADR-024 (a) : mention honnête du presse-papiers sur la fiche (aucun effacement promis). */
.detail-note { margin: var(--v-space-2) 0 0; color: var(--v-text-muted); font-size: 0.75rem; line-height: 1rem; max-width: 44ch; }

/* --- sécurité du compte (étape 7) : méthodes de déverrouillage, seconde clé, révocation ; boutons destructifs --- */
.methods { list-style: none; display: flex; flex-direction: column; margin-top: var(--v-space-4); }
.method { display: flex; align-items: center; gap: var(--v-space-3); min-height: 4rem; padding: var(--v-space-3) 0; border-bottom: 1px solid var(--v-line-1); }
/* clés de sécurité en ambre, clé de récupération en bleu clair (recette du 2026-09-14) : repérage, jamais un état */
.method-icon { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 2.5rem; height: 2.5rem; border-radius: var(--v-radius-control); background: var(--v-hue-amber-bg); border: 1px solid rgb(240 190 90 / 24%); color: var(--v-hue-amber); }
.method[data-method="recovery-key"] .method-icon { background: var(--v-hue-sky-bg); border-color: rgb(143 184 232 / 24%); color: var(--v-hue-sky); }
.method-text { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.method-name { font-size: 0.9375rem; line-height: 1.375rem; font-weight: 500; overflow-wrap: anywhere; }
.method-meta { font-size: 0.8125rem; line-height: 1.125rem; color: var(--v-text-muted); }
.method .badge { flex: none; }
.security-step { margin-top: var(--v-space-5); }
.security .hint + .hint { margin-top: var(--v-space-4); }
.security .alert-info { margin-top: var(--v-space-4); }

/* --- mouvement réduit (charte §14) : un seul bloc, en fin de feuille ---------------------------------------------------------
   Il neutralise des règles de même spécificité : c'est la dernière déclarée qui gagne. Posé en tête de feuille, il perdait
   contre chaque raccourci `animation` écrit plus bas (mesuré sur le faisceau des champs et les carrés du loader ; le menu compte,
   le texte du loader et l'anneau des boutons occupés s'animaient encore). Toute nouvelle animation se neutralise ici. */
@media (prefers-reduced-motion: reduce) {
  :root { --v-motion-fast: 0ms; --v-motion-standard: 0ms; --v-motion-dialog: 0ms; }
  [data-vault-ui], [data-vault-ui] * { scroll-behavior: auto; }
  .btn:not(:disabled):active, .menu-row:active { transform: none; }
  .is-busy::after { animation: none; }
  .auth-panel, .detail, .account-menu, .menu-shell { animation: none; }
  /* attentes réelles : indicateur fixe et texte d'activité à la place du mouvement */
  .auth-panel[data-wait="true"]::before { animation: none; opacity: 1; background: none; border: 1px solid var(--v-accent-line); }
  .loader-title, .loader-sub { animation: none; }
  /* carrés figés : animation mise en pause (pas retirée), les décalages négatifs gardent chacun à sa case */
  .loader-square { animation-play-state: paused; }
  /* faisceau des champs immobile sur le contour fixe : le focus reste lisible */
  input:not(:disabled):focus-visible, textarea:not(:disabled):focus-visible, .slots:focus-within .slots-cells i[data-active="true"] { animation: none; }
  #backdrop { transition: none; }
  #site[data-granted="true"] .popup-site-text { transform: none; }
}
