:root {
  /* Color Palette - Neutrals */
  --bg: #FFFFFF;
  --bg-subtle: #F8FAFC;
  --bg-muted: #F1F5F9;
  --card: #FFFFFF;
  --text: #0F172A;
  --text-muted: #475569;
  --text-faint: #64748B;
  
  --border: rgba(15, 23, 42, 0.08);
  --border-subtle: rgba(15, 23, 42, 0.05);
  --border-hover: rgba(15, 23, 42, 0.16);
  
  /* Primary Brand - Dynamic Blue */
  --primary: #2563EB;
  --primary-hover: #1D4ED8;
  --primary-light: #EFF6FF;
  --primary-border: #BFDBFE;
  --primary-glow: rgba(37, 99, 235, 0.16);
  
  /* Accent - Deep Slate / Midnight */
  --accent: #0F172A;
  --accent-hover: #1E293B;
  
  /* Semantic - Success (Emerald) */
  --success: #059669;
  --success-hover: #047857;
  --success-light: #ECFDF5;
  --success-border: #A7F3D0;
  --success-glow: rgba(5, 150, 105, 0.15);
  
  /* Semantic - Danger (Crimson) */
  --danger: #DC2626;
  --danger-hover: #B91C1C;
  --danger-light: #FEF2F2;
  --danger-border: #FECACA;
  
  /* Semantic - Amber / Warning */
  --amber: #D97706;
  --amber-hover: #B45309;
  --amber-light: #FFFBEB;
  --amber-border: #FDE68A;
  --amber-glow: rgba(217, 119, 6, 0.15);

  /* Semantic - Violet / Agent MCP */
  --violet: #7C3AED;
  --violet-hover: #6D28D9;
  --violet-light: #F5F3FF;
  --violet-border: #DDD6FE;
  --violet-glow: rgba(124, 58, 237, 0.15);

  /* Typography */
  --sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", "Segoe UI Mono", Menlo, Consolas, monospace;
  
  /* Geometry & Radius */
  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-xl: 20px;
  --radius-full: 9999px;

  /* Multi-level Soft Shadows */
  --shadow-xs: 0 1px 2px 0 rgba(15, 23, 42, 0.04);
  --shadow-sm: 0 1px 3px 0 rgba(15, 23, 42, 0.06), 0 1px 2px -1px rgba(15, 23, 42, 0.04);
  --shadow-md: 0 4px 6px -1px rgba(15, 23, 42, 0.06), 0 2px 4px -2px rgba(15, 23, 42, 0.04);
  --shadow-lg: 0 10px 15px -3px rgba(15, 23, 42, 0.07), 0 4px 6px -4px rgba(15, 23, 42, 0.04);
  --shadow-xl: 0 20px 25px -5px rgba(15, 23, 42, 0.08), 0 8px 10px -6px rgba(15, 23, 42, 0.04);
  --shadow-glow: 0 0 20px -2px var(--primary-glow);
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
.wrap {
  max-width: 980px;
  margin: 0 auto;
  padding: 0 24px;
}
.wrap.narrow { max-width: 760px; }
.wrap.wide { max-width: 1120px; }

a {
  color: var(--primary);
  text-decoration: none;
  transition: color 0.15s ease;
}
a:hover { color: var(--primary-hover); }

/* ---------- Bandeau (Masthead) ---------- */
.masthead {
  border-bottom: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.88);
  backdrop-filter: blur(10px);
  position: sticky;
  top: 0;
  z-index: 50;
}
.masthead .wrap {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  min-height: 64px;
  gap: 16px;
}
.masthead .ref {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--sans);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--text);
  text-decoration: none;
}
.masthead .ref .badge-eu {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 700;
  background: var(--primary-light);
  color: var(--primary);
  border: 1px solid var(--primary-border);
  padding: 2px 7px;
  border-radius: var(--radius-xs);
  letter-spacing: 0.04em;
}
.masthead .who {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 13.5px;
  color: var(--text-muted);
}
.masthead .who form { display: flex; }

.mast-nav {
  display: flex;
  align-items: center;
  /* flex-wrap sur la navigation, et pas seulement sur le bandeau qui la
     contient : à trois onglets elle tenait, le quatrième — « Jeton d'API » — a
     franchi le seuil. Mesuré à 320 px : 270 px de texte plus 48 px de
     gouttières font 318 px demandés pour 288 disponibles, soit 14 px de
     débordement de la page entière.
     
     La contrainte appartient à l'élément, pas à un palier : un cinquième onglet
     déborderait à une largeur qu'on n'aurait pas prévue. */
  flex-wrap: wrap;
  gap: 20px;
  margin-left: auto;
  margin-right: 24px;
}
.mast-nav a {
  color: var(--text-muted);
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  padding: 4px 0;
  transition: color 0.15s ease;
}
.mast-nav a:hover { color: var(--text); }
.mast-nav a.on { color: var(--text); font-weight: 600; }

.plan-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  padding: 3px 8px;
  border-radius: var(--radius-sm);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.plan-pill--free {
  background: var(--bg-muted);
  color: var(--text-muted);
  border: 1px solid var(--border);
}
.plan-pill--pro {
  background: #EFF6FF;
  color: #1D4ED8;
  border: 1px solid #93C5FD;
}
.plan-pill--workspace {
  background: #F5F3FF;
  color: #6D28D9;
  border: 1px solid #DDD6FE;
}
.tag-up { text-decoration: none; }
.tag-up:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); }

.who-mail { color: var(--text-muted); font-weight: 500; }

.masthead button.link {
  background: none;
  border: 0;
  color: var(--text-muted);
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  text-decoration: underline;
  padding: 0;
  transition: color 0.15s ease;
}
.masthead button.link:hover { color: var(--danger); }

/* ---------- Menu Compte (Account Dropdown) ---------- */
.account-menu {
  position: relative;
  display: inline-block;
}

.account-trigger {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 10px 4px 5px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  list-style: none;
  user-select: none;
  transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.account-trigger::-webkit-details-marker,
.account-trigger::marker {
  display: none;
}
.account-trigger:hover {
  background: var(--bg-subtle);
  border-color: var(--border-hover);
}
.account-trigger:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
.account-menu[open] .account-trigger {
  background: var(--bg-muted);
  border-color: var(--border-hover);
}

.account-avatar {
  width: 26px;
  height: 26px;
  border-radius: var(--radius-full);
  background: var(--bg-muted);
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  flex-shrink: 0;
}
.account-chevron {
  display: flex;
  align-items: center;
  color: var(--text-faint);
  transition: transform 0.2s ease;
}
.account-menu[open] .account-chevron {
  transform: rotate(180deg);
}

.account-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 240px;
  max-width: 320px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 6px 0;
  z-index: 100;
  animation: menuDropIn 0.15s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes menuDropIn {
  from {
    opacity: 0;
    transform: translateY(-4px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.account-dropdown-header {
  padding: 8px 14px 6px;
}
.account-dropdown-email {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.account-dropdown-sep {
  height: 1px;
  background: var(--border);
  margin: 5px 0;
}

.account-dropdown-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  font-family: var(--sans);
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text);
  text-decoration: none;
  background: transparent;
  border: 0;
  width: 100%;
  text-align: left;
  cursor: pointer;
  box-sizing: border-box;
  transition: background 0.12s ease, color 0.12s ease;
}
.account-dropdown-item:hover {
  background: var(--bg-muted);
  color: var(--text);
}
.account-dropdown-item.on {
  font-weight: 600;
  color: var(--primary);
  background: var(--primary-light);
}
.account-dropdown-item.on .account-dropdown-icon {
  color: var(--primary);
}
.account-dropdown-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-muted);
  flex-shrink: 0;
}
.account-dropdown-badge {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  color: var(--text-muted);
  background: var(--bg-muted);
  padding: 2px 6px;
  border-radius: var(--radius-xs);
  border: 1px solid var(--border);
}
.account-dropdown-item.on .account-dropdown-badge {
  border-color: var(--primary-border);
  background: #DBEAFE;
  color: var(--primary-hover);
}

.account-dropdown-logout {
  color: var(--text-muted);
}
.account-dropdown-logout:hover {
  background: var(--danger-light);
  color: var(--danger);
}
.account-dropdown-logout:hover .account-dropdown-icon {
  color: var(--danger);
}
.account-dropdown form {
  display: block;
  margin: 0;
}

@media (max-width: 720px) {
  .masthead { position: static; }
  .masthead .wrap { padding-top: 14px; padding-bottom: 8px; }
  .mast-nav {
    order: 3;
    flex-basis: 100%;
    margin: 0;
    justify-content: center;
    gap: 16px;
  }
  .who-mail { display: none; }
  .mast-nav a { min-height: 44px; display: flex; align-items: center; }
  .account-dropdown {
    right: 0;
    left: auto;
    max-width: calc(100vw - 32px);
  }
}

.masthead button.link,
.masthead .tag-up { position: relative; }
.masthead button.link::after,
.masthead .tag-up::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 44px;
  transform: translateY(-50%);
}

/* ---------- Page Headers, Eyebrow & Typography ---------- */
.page-head {
  padding: 56px 0 44px;
  border-bottom: 1px solid var(--border);
  background: radial-gradient(circle at 50% 0%, var(--primary-light) 0%, transparent 60%);
}
.page-head-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
}
.page-head-actions {
  flex-shrink: 0;
  margin-bottom: 4px;
}
.page-head-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.page-head-meta .eyebrow { margin-bottom: 0; }
.page-title {
  font-size: clamp(28px, 4.5vw, 42px);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.03em;
  color: var(--text);
  /* Le titre de la page de gestion EST le slug : vingt-six caractères sans
     espace, quarante-deux pour un slug choisi avec son suffixe non listé. Un mot
     insécable de cette longueur réclamait 432 px et faisait défiler la page
     entière — mesuré, 143 px de débordement à 320 px de large.

     « anywhere » et non « break-word » : ici c'est bien le calcul du
     min-content qu'il faut réduire, et seul « anywhere » le fait. La nuance est l'inverse de
     celle des cellules du tableau, où « anywhere » effondrait la colonne à un
     caractère — un titre autonome n'a pas de colonne voisine à écraser.

     Hors média : un slug de quarante-deux caractères déborde aussi à 768 px.
     La contrainte appartient au contenu, pas à la largeur de l'écran. Les
     autres titres — « Gestion de votre offre » — ont des espaces et se coupent
     donc normalement ; la règle ne s'applique qu'au mot qui ne tient pas. */
  overflow-wrap: anywhere;
}
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--primary);
  background: var(--primary-light);
  padding: 4px 10px;
  border-radius: var(--radius-full);
  margin-bottom: 14px;
}
.eyebrow svg { flex-shrink: 0; }
.lede {
  margin-top: 14px;
  font-size: 16.5px;
  max-width: 62ch;
  line-height: 1.6;
  color: var(--text-muted);
}
.lede b, .lede strong { color: var(--text); }

h1 { font-family: var(--sans); font-weight: 800; font-size: clamp(28px, 4.5vw, 42px); line-height: 1.15; letter-spacing: -0.025em; color: var(--text); }
h2 { font-family: var(--sans); font-weight: 700; font-size: clamp(20px, 3vw, 26px); line-height: 1.25; letter-spacing: -0.02em; color: var(--text); }
h3 { font-family: var(--sans); font-weight: 600; font-size: 17px; color: var(--text); }

section { padding: 56px 0; }
section + section { border-top: 1px solid var(--border); }
/* Le fond alterné du site public. Deux sections de même poids typographique et
   de même fond se lisaient comme une seule page qui n'en finit pas : la bande
   grise dit où « publier » s'arrête et où « ce que j'ai publié » commence. */
.section--alt { background: var(--bg-subtle); }
.section-head { margin-bottom: 28px; max-width: 740px; }
.section-head h2 { margin-bottom: 6px; }
.section-sub { font-size: 15px; color: var(--text-muted); margin-top: 6px; line-height: 1.6; }

/* ---------- Cartes ---------- */
.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

/* ---------- Bande d'indicateurs ---------- */
/* min(100%, 220px) et non 220px tout court : une piste plus large que son
   conteneur ne se replie pas, elle déborde. C'est la leçon responsive du dépôt,
   appliquée ici comme dans la grille des offres.

   220 plutôt que les 180 de .value-strip sur le site public : à 180, quatre
   cartes tiennent à trois par ligne autour de 700 px de large, et la quatrième
   se retrouve seule sur une deuxième ligne à côté d'un vide des deux tiers.
   À 220, la bascule se fait directement de quatre colonnes à deux, soit une
   grille 2×2 pleine sur tablette. */
/* La bande d'indicateurs : UNE boîte, des cellules séparées par la gouttière.
   « gap: 1px » sur un fond couleur bordure DESSINE les filets — un filet par
   frontière, exactement, à n'importe quel nombre de colonnes et sans
   arithmétique de :nth-child. Le trait EST la gouttière, pas une bordure.

   Quatre cellules, et ce nombre est une contrainte plutôt qu'un hasard : 4 se
   divise en 4, en 2×2 et en 1×4, donc aucune largeur ne laisse d'orpheline. La
   version précédente en avait quatre dans une grille auto-fit à 220 px, soit
   4×220 + 3×20 = 940 px demandés pour les 932 px utiles de .wrap. Il manquait
   HUIT pixels, et la quatrième carte tombait seule sur une deuxième ligne. Une
   grille auto-fit choisit le nombre de colonnes elle-même ; à huit pixels près,
   elle choisit mal. Un nombre de colonnes explicite ne peut pas se tromper. */
.stat-strip {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
/* 2×2 sous 720 px : quatre colonnes y donneraient 160 px par cellule, où
   « Prochaine expiration » se casse en trois lignes. La règle vit ici, avec
   l'élément, et non dans le bloc média du bandeau de navigation. */
@media (max-width: 720px) {
  .stat-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.stat-card {
  background: #fff;
  padding: 16px 18px 15px;
  display: flex;
  flex-direction: column;
  gap: 7px;
  /* Sans min-width: 0, une cellule au contenu insécable refuse de se réduire et
     repousse ses voisines hors de la boîte. */
  min-width: 0;
}
/* Aucun effet de survol : ces cellules ne sont pas cliquables, et une tuile qui
   se soulève sous le curseur promet une action qui n'existe pas. */
.stat-label {
  display: flex;
  align-items: center;
  gap: 7px;
  font: 500 12.5px var(--sans);
  color: var(--text-muted);
}
/* L'icône passe EN LIGNE avec le libellé. Dans son pavé teinté de 36 px elle
   occupait une rangée à elle seule : la bande dépensait 250 px de hauteur pour
   dire quatre choses. */
.stat-label svg {
  width: 15px;
  height: 15px;
  color: var(--primary);
  flex-shrink: 0;
}
/* Le chiffre en 28px/800 : c'est l'information de la carte, tout le reste la
   qualifie. Tabular-nums pour que quatre cartes côte à côte n'aient pas des
   chiffres de largeurs différentes. */
.stat-num {
  font-size: 28px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.stat-num .unit {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-muted);
  letter-spacing: 0;
}
/* La cellule d'échéance porte du TEXTE — « dans 21 h », et sans JavaScript un
   instant absolu de vingt-deux caractères. Plus petit que .stat-num pour cette
   raison, et c'est la bonne hiérarchie : ce n'est pas un nombre. */
.stat-when {
  font-size: 19px;
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--text);
}
.stat-foot { font-size: 12px; color: var(--text-faint); margin-top: auto; }

/* La jauge de quota. Gouttière + remplissage, sans <progress> : l'élément natif
   se style différemment sur chaque navigateur, et il annoncerait une barre de
   progression là où il s'agit d'un remplissage. */
.quota-bar {
  height: 6px;
  border-radius: var(--radius-full);
  background: var(--bg-muted);
  overflow: hidden;
}
.quota-fill {
  height: 100%;
  border-radius: var(--radius-full);
  background: var(--primary);
}
/* Ambre et non rouge : être proche de son quota n'est pas une erreur, c'est un
   fait dont on veut être averti avant de buter dessus. */
.quota-fill.tight { background: var(--amber); }

/* ---------- Formulaire ---------- */
label { display: block; font: 600 13px var(--sans); color: var(--text); margin-bottom: 6px; }
input, select {
  width: 100%;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font: 14.5px var(--sans);
  background: #fff;
  color: var(--text);
  transition: border-color .15s, box-shadow .15s;
}
input:focus, select:focus {
  outline: 0;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-light);
}
input::placeholder { color: var(--text-faint); }
/* Les cases à cocher échappent au gabarit des champs texte. La règle globale
   « input { width:100% ; padding:10px 14px } » les étirait sur toute la ligne :
   une case devenue un bloc pleine largeur avalait la rangée flex de l'écran de
   commande et écrasait son libellé en colonne d'un caractère. Invisible
   jusqu'ici — ces cases sont les premières du tableau de bord. */
input[type="checkbox"] {
  width: 16px;
  height: 16px;
  padding: 0;
  flex: none;
  accent-color: var(--primary);
}
select {
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%2371717A' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 13px center;
  padding-right: 36px;
}
.field { margin-bottom: 0; }
.hint { font-size: 12.5px; color: var(--text-muted); margin-top: 5px; line-height: 1.45; }

/* ---------- Boutons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background: linear-gradient(180deg, var(--primary) 0%, var(--primary-hover) 100%);
  color: #fff;
  border: 1px solid rgba(29, 78, 216, 0.3);
  border-radius: var(--radius-sm);
  padding: 9px 18px;
  font-family: var(--sans);
  font-size: 14.5px;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.15);
  transition: all .15s ease;
}
.btn:hover {
  background: linear-gradient(180deg, var(--primary-hover) 0%, #1e40af 100%);
  border-color: rgba(29, 78, 216, 0.5);
  color: #fff;
  transform: translateY(-1px);
  box-shadow: var(--shadow-md), 0 0 12px var(--primary-glow);
}
.btn:active {
  transform: translateY(0);
  box-shadow: var(--shadow-xs);
}
.btn.big {
  padding: 13px 26px;
  font-size: 15.5px;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
.btn.small {
  padding: 6px 12px;
  font-size: 13px;
  border-radius: var(--radius-sm);
}
.btn.ghost {
  background: #fff;
  color: var(--text);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-xs);
}
.btn.ghost:hover {
  background: var(--bg-subtle);
  border-color: var(--border-hover);
  color: var(--text);
  box-shadow: var(--shadow-sm);
}
.btn.primary-cta {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}
.btn.primary-cta:hover {
  background: var(--primary-hover);
  border-color: var(--primary-hover);
}
.btn.danger {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
}
.btn.danger:hover {
  background: #B91C1C;
  border-color: #B91C1C;
}
.btn.link-danger {
  background: none;
  border: 0;
  color: var(--danger);
  padding: 6px 10px;
  font-size: 13px;
  font-weight: 500;
  text-decoration: none;
  box-shadow: none;
}
.btn.link-danger:hover {
  background: var(--danger-light);
  border-radius: var(--radius-sm);
  transform: none;
}
/* Après les variantes (.primary-cta, .danger, …) pour gagner la cascade
   quelle que soit la variante du bouton désactivé. */
.btn:disabled,
.btn:disabled:hover {
  background: var(--bg-muted);
  border-color: var(--border);
  color: var(--text-faint);
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}

/* ---------- Zone de Dépôt & Hub de Publication ---------- */
.publisher-card {
  background: #FFFFFF;
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  padding: 24px;
  box-shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.05), 0 2px 6px -1px rgba(0, 0, 0, 0.02);
  margin-top: 8px;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

/* Onglets du type de publication.
   Segmenté plutôt que soulignés : trois choix exclusifs se lisent mieux dans un
   contrôle unique, et le contour rappelle qu'il s'agit d'un réglage du dépôt qui
   suit — pas d'une navigation vers une autre page. */
.up-tabs {
  display: flex;
  gap: 4px;
  padding: 4px;
  margin-bottom: 14px;
  background: #F1F5F9;
  border-radius: var(--radius-md);
}
.up-tab {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 9px 12px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-soft);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.up-tab:hover { color: var(--text); }
.up-tab.on {
  background: #FFFFFF;
  color: var(--primary);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
/* Le focus doit rester visible : ces onglets se parcourent aux flèches. */
.up-tab:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }

/* La règle du type choisi, et les limites du plan. Deux niveaux de gris :
   la règle est une information de sécurité qu'on veut lire, les limites un
   rappel qu'on consulte. */
.up-rule {
  margin: 12px 2px 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-soft);
}
/* Le plafond du type : une contrainte, donc plus discrète que la règle de
   sécurité au-dessus, mais lisible avant l'échec plutôt qu'après. */
.up-cap {
  margin: 3px 2px 0;
  font-size: 12.5px;
  color: var(--text-soft);
}
.up-limits {
  margin: 4px 2px 0;
  font-size: 12.5px;
  color: var(--text-faint, #94A3B8);
}
.up-limits strong { color: var(--text-soft); font-weight: 600; }

/* Sous 560px, trois onglets côte à côte tronquent leurs libellés : on masque
   l'icône avant le texte, qui porte le sens. */
@media (max-width: 560px) {
  .up-tab { padding: 9px 6px; font-size: 12.5px; }
  .up-tab svg { display: none; }
}

.drop {
  border: 2px dashed #CBD5E1;
  border-radius: var(--radius-lg);
  background: #F8FAFC;
  padding: 38px 24px 30px;
  text-align: center;
  cursor: pointer;
  transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
  position: relative;
}
.drop:hover, .drop.over {
  border-color: var(--primary);
  background: #EFF6FF;
  transform: translateY(-1px);
  box-shadow: 0 6px 16px -2px rgba(37, 99, 235, 0.1);
}
.drop-icon-box {
  width: 50px;
  height: 50px;
  border-radius: var(--radius-md);
  background: #FFFFFF;
  border: 1px solid #E2E8F0;
  color: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
  margin: 0 auto 14px;
  transition: transform 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.drop:hover .drop-icon-box {
  transform: scale(1.06);
  border-color: var(--primary-border);
}
.drop-text-main {
  margin-bottom: 18px;
}
.drop-text-main strong {
  display: block;
  font-size: 16.5px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 4px;
}
.drop-text-main span {
  font-size: 13.5px;
  color: var(--text-muted);
}
.drop-actions {
  display: flex;
  justify-content: center;
  gap: 10px;
  flex-wrap: wrap;
}
/* Les deux boutons de la zone de dépôt sont des ACTIONS, pas une notice. À
   7px/13px sur fond blanc ils se lisaient comme une légende : le propriétaire du
   produit a cru deux fois de suite qu'un seul des deux chemins existait — « je
   ne peux pas choisir un dossier », puis « je ne peux uploader qu'un dossier ».
   Les deux fois, l'option manquante était à l'écran. */
.drop-btn {
  background: #FFFFFF;
  border: 1px solid var(--border);
  color: var(--text);
  padding: 11px 20px;
  font-size: 14.5px;
  font-weight: 600;
  border-radius: var(--radius-sm);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  box-shadow: var(--shadow-sm);
  transition: all 0.15s ease;
  cursor: pointer;
}
.drop-btn:hover {
  background: var(--bg-muted);
  border-color: var(--border-hover);
  color: var(--text);
  transform: translateY(-1px);
}
.drop-btn svg {
  /* L'icône prend la couleur du texte : en gris muet, elle ajoutait à l'air de
     mention discrète que ces deux boutons avaient. */
  color: var(--text);
}

.files {
  margin-top: 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: #FFFFFF;
  overflow: hidden;
  display: none;
  box-shadow: var(--shadow-sm);
  animation: fade 0.15s ease-out;
}
.files.show { display: block; }
.files-head {
  background: var(--bg-subtle);
  padding: 10px 16px;
  font: 600 13px var(--sans);
  color: var(--text);
  border-bottom: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.files-head svg {
  color: var(--primary);
}
.btn-clear-files {
  background: none;
  border: 0;
  color: var(--text-muted);
  font: 500 12.5px var(--sans);
  cursor: pointer;
  padding: 2px 6px;
  border-radius: var(--radius-xs);
  transition: all 0.15s ease;
}
.btn-clear-files:hover {
  background: var(--bg-muted);
  color: var(--danger);
}
.files-list { max-height: 180px; overflow-y: auto; }
.files-list div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 16px;
  font: 12.5px var(--mono);
  color: var(--text);
  border-bottom: 1px solid var(--border);
}
.files-list div:last-child { border-bottom: 0; }
.files-list em { color: var(--primary); font-style: normal; font-weight: 600; font-family: var(--sans); font-size: 11.5px; }

/* Paramètres de publication */
.publish-config {
  margin-top: 20px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
.config-grid, .options {
  display: grid;
  grid-template-columns: 1.3fr 1fr 1fr;
  gap: 16px;
}
@media (max-width: 768px) {
  .config-grid, .options { grid-template-columns: 1fr; }
}
.config-field label {
  display: flex;
  align-items: center;
  gap: 6px;
  font: 600 13px var(--sans);
  color: var(--text);
  margin-bottom: 6px;
}
.config-field label svg {
  color: var(--text-muted);
  flex-shrink: 0;
}
.config-field input, .config-field select {
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font: 14px var(--sans);
  background: #FFFFFF;
}
.config-field select {
  padding-right: 32px;
}
.config-field .hint {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 5px;
  line-height: 1.4;
}

.publisher-foot {
  margin-top: 22px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
  font-size: 12.5px;
  color: var(--text-muted);
  font-weight: 500;
}
.guarantee-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.guarantee-item svg {
  color: #059669;
  flex-shrink: 0;
}
.guarantee-dot {
  color: var(--border-hover);
  font-weight: bold;
}
/* ---------- Choix d'accès : des cartes radio, pas un <select> ----------
   Un select cache ses options derrière un clic et n'a pas de place pour dire ce
   que chacune implique. Ici le choix qui décide QUI PEUT LIRE un document
   s'explique en même temps qu'il se fait.

   Le radio natif est masqué mais reste dans le flux et gardé accessible : c'est
   lui qui porte l'état, le focus et la navigation au clavier. Le sélecteur
   :checked + label habille la carte. Aucun JavaScript. */
.acc-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 10px;
  margin-top: 14px;
}
.acc-opt { position: relative; }
.acc-opt input {
  position: absolute;
  top: 11px;
  left: 11px;
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--primary);
  cursor: pointer;
}
.acc-opt label {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  margin: 0;
  min-height: 64px;
  padding: 9px 11px 9px 34px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--card);
  cursor: pointer;
  transition: border-color .15s, background .15s;
  box-sizing: border-box;
}
.acc-opt label:hover { border-color: var(--border-hover); }
.acc-opt input:checked + label { border-color: var(--primary); background: var(--primary-light); }
.acc-opt input:focus-visible + label { outline: 2px solid var(--primary); outline-offset: 2px; }
.acc-opt input:disabled + label { opacity: .55; cursor: not-allowed; background: var(--bg-muted); }
.acc-opt .acc-name {
  display: flex;
  align-items: center;
  gap: 6px;
  font: 600 13.5px var(--sans);
  color: var(--text);
  flex-wrap: wrap;
}
.acc-opt .acc-why {
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-muted);
  margin-top: 2px;
}

/* Les champs propres à un mode n'apparaissent que si ce mode est choisi, et
   sans script.
   
   :has() sur le conteneur, et non « ~ » depuis le radio : le radio vit à
   l'intérieur de .acc-opt, donc il n'est PAS frère des zones conditionnelles —
   il en est le neveu, et « ~ » ne franchit pas cette frontière. Écrit avec « ~ »
   d'abord, le champ « mot de passe » ne s'affichait jamais, y compris sur un
   site qui EST protégé par mot de passe. Vu à l'écran, pas au relecture.
   
   :has() est déjà utilisé ailleurs dans cette feuille (voir la carte qui porte
   le tableau) : aucune hypothèse nouvelle sur le navigateur. */
.acc-extra {
  display: none;
  grid-column: 1 / -1;
  margin-top: 8px;
  padding: 12px 14px;
  background: var(--bg-subtle, #f9fafb);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.acc-grid:has(#acc-password:checked) .acc-extra-password,
.acc-grid:has(#acc-email_domain:checked) .acc-extra-email_domain,
.acc-grid:has(#exp-custom:checked) .acc-extra-custom { display: block; }

/* ---------- La courbe de consultation ----------
   Un SVG inline, pas trente <div>.
   
   La version en div a coûté cher : en flex les barres refusaient de se
   réduire (48 px chacune dans un conteneur de 570, débordé à 1401), et en
   grille de trente colonnes égales, vingt-huit gardaient 48 px sans que les
   règles appliquées ne l'expliquent. Un viewBox de 30 sur 100 rend la
   géométrie EXACTE et indépendante de toute subtilité de mise en page : la
   barre du jour i occupe la colonne i, point.

   preserveAspectRatio="none" étire le dessin à la largeur disponible sans
   déformer la lecture — les hauteurs restent proportionnelles entre elles,
   qui est la seule chose que la courbe affirme. */
.chart { display: block; width: 100%; height: 64px; margin-top: 10px; }
.chart rect { fill: var(--bg-muted); }
.chart rect.on { fill: var(--primary); }
.chart-legend {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  color: var(--text-faint);
  margin-top: 4px;
}

/* ---------- La courbe de l'écran client : des colonnes, pas un SVG ----------
   Le SVG s'étirait avec preserveAspectRatio="none", ce qui aurait déformé
   horizontalement tout texte posé dedans. Le nombre ne pouvait donc pas y
   vivre, et il n'existait que dans un <title> — invisible sans survol, et
   inatteignable au doigt. En colonnes HTML, l'étiquette est du texte normal. */
.chart-cols {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  margin-top: 12px;
}
.chart-col {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
}
/* Hauteur RÉSERVÉE même quand le nombre est vide : sans elle, une colonne à
   zéro serait plus courte que ses voisines et les fonds ne s'aligneraient pas. */
.chart-num {
  height: 13px;
  line-height: 13px;
  font-size: 10px;
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.chart-track {
  width: 100%;
  height: 64px;
  display: flex;
  align-items: flex-end;
  background: var(--bg-muted);
  border-radius: 3px;
  overflow: hidden;
}
.chart-fill { width: 100%; background: transparent; }
.chart-fill.on { background: var(--primary); }
/* visibility et non display : la place reste prise, donc toutes les colonnes
   gardent la même hauteur et les fonds restent alignés. */
.chart-x {
  font-size: 10px;
  line-height: 12px;
  color: var(--text-faint);
  white-space: nowrap;
  visibility: hidden;
}
/* La densité des abscisses est décidée par le NOMBRE de colonnes, en CSS seul.
   Trente étiquettes côte à côte se chevauchent en bouillie ; une sur cinq se
   lit. Le survol donne la valeur exacte de n'importe quelle barre. */
.chart-cols[data-n="7"] .chart-x { visibility: visible; }
.chart-cols[data-n="24"] .chart-col:nth-child(3n+1) .chart-x { visibility: visible; }
.chart-cols[data-n="30"] .chart-col:nth-child(5n+1) .chart-x { visibility: visible; }
/* QUINCONCE au-delà de vingt colonnes, et ce n'est pas une coquetterie : à
   trente barres une colonne fait ~15 px, donc un nombre à trois chiffres déborde
   sur sa voisine. Mesuré à l'écran : « 128 » et « 22 » côte à côte se lisaient
   « 12822 », c'est-à-dire un chiffre FAUX affiché avec aplomb — pire que pas de
   chiffre du tout. Une ligne sur deux double la place sans en cacher aucun.
   Tronquer aurait menti, masquer aurait rendu la demande initiale. */
.chart-cols[data-n="30"] .chart-num,
.chart-cols[data-n="24"] .chart-num { height: 26px; }
.chart-cols[data-n="30"] .chart-col:nth-child(even) .chart-num,
.chart-cols[data-n="24"] .chart-col:nth-child(even) .chart-num { padding-top: 13px; }

/* Sous 420 px, trente colonnes font moins de 8 px : les nombres deviennent
   illisibles de toute façon, et le survol n'existe pas au doigt. On garde la
   silhouette et les repères d'abscisse. */
@media (max-width: 420px) {
  .chart-cols[data-n="30"] .chart-num,
  .chart-cols[data-n="24"] .chart-num { font-size: 9px; }
}

/* Le second tableau d'une carte : séparé du premier, sans devenir une carte —
   les deux répondent à la même famille de questions. */
.stats-sous-titre {
  margin: 22px 0 4px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
}

/* ---------- Les sections repliables de l'onglet Statistiques ---------- */
.stats-bloc > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  cursor: pointer;
  list-style: none;
  /* La zone cliquable couvre toute la largeur de la carte : viser un titre de
     trois mots au pixel près est un défaut d'accessibilité, pas une exigence. */
  margin: -2px 0;
  padding: 2px 0;
}
.stats-bloc > summary::-webkit-details-marker { display: none; }
.stats-bloc > summary::after {
  content: "";
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--text-faint);
  border-bottom: 2px solid var(--text-faint);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 120ms ease;
}
.stats-bloc[open] > summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.stats-bloc > summary:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; border-radius: 4px; }
.stats-bloc > summary .detail-card-title { margin: 0; }
.stats-bloc[open] > summary { margin-bottom: 12px; }

/* ---------- Le bouton d'actions d'une ligne (···) ----------
   Sans JavaScript, c'est un LIEN vers la page de gestion où tous les gestes
   sont disponibles en formulaire.
   Avec JavaScript, il déclenche un menu contextuel en position: fixed rattaché
   à document.body pour ne jamais être rogné par le conteneur défilant du tableau. */
.row-actions {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 28px;
  padding: 4px 8px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font: 700 15px var(--sans);
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  background: none;
  transition: all .15s ease;
}
.row-actions:hover, .row-actions.active {
  background: var(--bg-muted);
  border-color: var(--border);
  color: var(--text);
}

/* ---------- Menu contextuel d'une ligne (Pop-over fixed) ---------- */
.menu-pop {
  position: fixed;
  z-index: 1000;
  background: #ffffff;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: 6px;
  min-width: 210px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  animation: fade .1s ease-out;
}
.menu-pop a, .menu-pop button {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 8px 10px;
  font-family: var(--sans);
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text);
  border: 0;
  background: none;
  border-radius: var(--radius-sm);
  text-align: left;
  cursor: pointer;
  text-decoration: none;
  box-sizing: border-box;
  transition: background .12s ease, color .12s ease;
}
.menu-pop a:hover, .menu-pop button:hover {
  background: var(--bg-muted);
  color: var(--text);
}
.menu-pop .menu-item-danger {
  color: var(--danger);
}
.menu-pop .menu-item-danger:hover {
  background: var(--danger-light);
  color: var(--danger);
}
.menu-pop hr {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 4px 0;
}
.menu-pop form {
  margin: 0;
  display: block;
  width: 100%;
}
.menu-pop svg {
  flex-shrink: 0;
}

/* ---------- Page Détail d'un Lien ---------- */
.detail-grid {
  display: grid;
  grid-template-columns: 1fr 340px;
  gap: 24px;
  align-items: start;
}
@media (max-width: 860px) {
  .detail-grid {
    grid-template-columns: 1fr;
  }
}
.detail-main, .detail-side {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* Les groupes d'onglets de la page de gestion.
   Chaque panneau devient un élément de la colonne flex, donc il doit reprendre
   à son compte l'espacement que .detail-main donnait aux cartes — sans quoi les
   cartes d'un même onglet se retrouvent collées.

   Le [hidden] explicite n'est pas décoratif : la règle display:flex juste
   au-dessus l'emporterait sur le display:none de la feuille du navigateur, et
   les quatre panneaux resteraient tous visibles.

   Les panneaux sont rendus VISIBLES et c'est le script qui les replie. Sans
   script, la page reste ce qu'elle était : une colonne où tout est atteignable.
   L'inverse — cacher en HTML, montrer en JS — rendrait trois réglages sur
   quatre inaccessibles au premier script en échec, sur la page qui règle qui
   peut lire un document. */
.tab-panel {
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.tab-panel[hidden] { display: none; }
/* La barre d'onglets prend l'espacement de la colonne, pas le sien. */
.detail-main .up-tabs { margin-bottom: 0; }

/* Le tableau des versions déborde, et il faisait déborder TOUTE la page.
   Ses six colonnes ont une largeur minimale de 407 px ; sous 860 px la grille
   passe à une seule colonne, si bien que cette carte imposait sa largeur aux
   deux colonnes et poussait l'écran entier hors du viewport — mesuré à 423 px
   pour 375 px de vue sur un téléphone.

   La classe .table-responsive était POSÉE dans le gabarit mais n'existait que
   dans admin.css : la page du tableau de bord la portait sans qu'aucune règle
   ne s'y applique. Un conteneur de défilement qui n'en est pas un ne se voit
   pas en relisant le HTML — d'où la copie de la règle ici. */
.table-responsive {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* Et l'autre moitié du défaut : un élément de grille ou de flex vaut
   min-width:auto par défaut, donc il REFUSE de rétrécir sous la largeur
   intrinsèque de son contenu. Sans ces trois-là, le conteneur de défilement
   ci-dessus n'aurait rien à quoi se mesurer : la chaîne d'ancêtres se serait
   élargie avant que la barre de défilement n'apparaisse. */
.detail-main, .detail-side, .tab-panel { min-width: 0; }
.detail-card {
  padding: 24px;
}
.detail-card-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 16px;
}
.detail-card-title {
  font-size: 16px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 4px;
}
.detail-card-desc {
  font-size: 13.5px;
  color: var(--text-muted);
  line-height: 1.5;
}
.expiry-status-box {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  margin-bottom: 12px;
  font-size: 13px;
  line-height: 1.4;
}
.expiry-status-box.perm {
  background: var(--primary-light);
  border: 1px solid rgba(13, 148, 136, 0.25);
  color: #0f766e;
}
.expiry-status-box.timed {
  background: #eff6ff;
  border: 1px solid #bfdbfe;
  color: #1e40af;
}
.expiry-status-box svg {
  flex-shrink: 0;
}
.back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 14px;
  text-decoration: none;
  transition: color .15s ease;
}
.back-link:hover {
  color: var(--primary);
}
.back-link svg {
  transition: transform .15s ease;
}
.back-link:hover svg {
  transform: translateX(-3px);
}
.site-hero-url {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 12px;
}
.site-hero-url a,
.site-hero-url code {
  font-family: var(--mono);
  font-size: 14.5px;
  font-weight: 600;
  color: var(--primary);
  /* break-all et non break-word : ici c'est bien le calcul du min-content qu'il
     faut réduire, sans quoi l'élément refuse de rétrécir dans son conteneur
     flex. Le <code> a été ajouté avec la page du jeton : quarante-six
     caractères monospace réclament près de 400 px, pour 272 px utiles à 320 px
     de large — la règle ne valait que pour le <a>, et le jeton débordait. */
  word-break: break-all;
}
.site-hero-url code {
  /* Sans min-width: 0, un élément flex au contenu insécable ne se réduit pas,
     et break-all seul n'y suffirait pas. */
  min-width: 0;
}
.info-list {
  display: grid;
  gap: 12px;
  font-size: 13.5px;
}
.info-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
  gap: 12px;
}
.info-item:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}
.info-label {
  color: var(--text-muted);
  font-weight: 500;
}
.info-val {
  color: var(--text);
  font-weight: 600;
  font-family: var(--mono);
  font-size: 13px;
  text-align: right;
}

/* L'identifiant du site, avec son bouton de copie. C'est la valeur qu'attendent
   l'API et le connecteur MCP : elle doit se prendre d'un geste, pas se relever
   caractère par caractère dans la barre d'adresse. */
.info-id {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.info-id code {
  overflow-wrap: anywhere;
}
/* Un bouton à la taille de la ligne : le padding ordinaire d'un « small »
   doublerait la hauteur de la rangée pour une icône de douze pixels. */
.info-id .btn {
  flex-shrink: 0;
  padding: 3px 6px;
}
.qr-card-body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  text-align: center;
}
.qr-frame {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 12px;
  display: inline-flex;
  justify-content: center;
  align-items: center;
  box-shadow: var(--shadow-sm);
}
.qr-frame img {
  display: block;
  width: 140px;
  height: 140px;
}
.qr-actions {
  display: flex;
  gap: 8px;
  width: 100%;
  justify-content: center;
  flex-wrap: wrap;
}

.slug-row { display: flex; }
.slug-row input { border-radius: var(--radius-sm) 0 0 var(--radius-sm); border-right: 0; }
.slug-row .suffix {
  display: flex;
  align-items: center;
  padding: 0 13px;
  border: 1px solid var(--border);
  border-left: 0;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--bg-muted);
  font: 13px var(--mono);
  color: var(--text-muted);
  white-space: nowrap;
}

.publish-bar {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 24px;
  flex-wrap: wrap;
}

.callout {
  border: 1px solid var(--border);
  background: var(--bg-subtle);
  border-radius: var(--radius-md);
  padding: 16px 20px;
  margin: 20px 0;
}
.callout .tag {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--primary);
  background: var(--primary-light);
  padding: 3px 8px;
  border-radius: 4px;
  display: inline-block;
  margin-bottom: 8px;
}
.callout p {
  margin-bottom: 0;
  font-size: 14px;
  color: var(--text-muted);
  line-height: 1.55;
}

/* ---------- Retour de publication ---------- */
.out {
  margin-top: 24px;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background: #fff;
  padding: 24px;
  display: none;
  box-shadow: var(--shadow-sm);
}
.out.show { display: block; }
.out.ok { border-color: var(--success-border); background: var(--success-light); }
.out.err { border-color: var(--danger-border); background: var(--danger-light); }
/* warn n'est ni ok ni err : l'archive est ACCEPTÉE, elle ne fait probablement
   pas ce qu'on croit. En rouge on lirait un refus, en vert une réussite. */
.out.warn { border-color: var(--amber-border); background: var(--amber-light); }
.out .tag {
  font: 700 11.5px var(--mono);
  letter-spacing: .04em;
  text-transform: uppercase;
  display: inline-block;
  margin-bottom: 10px;
  padding: 3px 8px;
  border-radius: var(--radius-sm);
}
.out.ok .tag { color: var(--success); background: #DCFCE7; }
.out.err .tag { color: var(--danger); background: #FEE2E2; }
.out.warn .tag { color: var(--amber); background: #FEF3C7; }
.out .url {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 4px;
}
.out .url a {
  color: var(--primary);
  font: 700 16px var(--mono);
  word-break: break-all;
  text-decoration: none;
}
.out .url a:hover { text-decoration: underline; }
.out p { font-size: 14.5px; color: var(--text); }
.out .meta { font-size: 13px; color: var(--text-muted); margin-top: 8px; }
.out .detail { font: 12.5px var(--mono); color: var(--text-muted); margin-top: 4px; }
.out pre {
  background: #09090B;
  color: #F4F4F5;
  font: 12.5px var(--mono);
  padding: 14px;
  border-radius: var(--radius-sm);
  margin-top: 12px;
  overflow-x: auto;
  max-height: 230px;
}

/* ---------- Statuts d'un domaine personnalisé ---------- */
.dom-header-box {
  padding: 11px 14px;
  background: var(--bg-subtle, #f9fafb);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin-bottom: 12px;
}
.dom-main-name {
  font-family: var(--mono);
  font-weight: 700;
  font-size: 14.5px;
  color: var(--text);
}
.dom-main-name a {
  color: var(--primary);
  text-decoration: none;
}
.dom-main-name a:hover {
  text-decoration: underline;
}
.dom-checks-wrap {
  margin-top: 10px;
}
.dom-checks-title {
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.dom-status {
  margin: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 2px 12px;
  background: var(--card);
}
.dom-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 0; border-bottom: 1px solid var(--border);
}
.dom-row:last-child { border-bottom: 0; }
.dom-name { font: 600 13px var(--mono); overflow-wrap: anywhere; flex: 1; min-width: 140px; }
.dom-detail { font-size: 12px; }
.dom-chip {
  font: 600 11.5px var(--sans); letter-spacing: .02em;
  padding: 3px 9px; border-radius: 999px; white-space: nowrap;
}
.dom-chip.ok   { background: #ECFDF5; color: #047857; }
.dom-chip.wait { background: #FEF3C7; color: #B45309; }
.dom-chip.off  { background: var(--bg-muted); color: var(--text-muted); }
.dom-chip.ko   { background: #FEF2F2; color: #B3261E; }

.dom-addr-list {
  margin-bottom: 12px;
}
.dom-addr-rows {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--card);
  overflow: hidden;
}
.dom-addr-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 11px 14px;
  border-bottom: 1px solid var(--border);
}
.dom-addr-row:last-child { border-bottom: 0; }
.dom-addr-main { flex: 1; min-width: 0; }
.dom-addr-url {
  display: block;
  font: 600 13.5px var(--mono);
  color: var(--primary);
  text-decoration: none;
  overflow-wrap: anywhere;
}
.dom-addr-url:hover { text-decoration: underline; }
.dom-addr-label {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 3px;
  line-height: 1.35;
}
.dom-addr-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.dom-addr-inline {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
  font-size: 12.5px;
}
.dom-addr-inline a {
  font-family: var(--mono);
  font-weight: 600;
  color: var(--primary);
  text-decoration: none;
  overflow-wrap: anywhere;
}
.dom-addr-inline a:hover { text-decoration: underline; }

.dom-setting {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  margin-top: 14px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-subtle, #f9fafb);
}
.dom-setting-copy { flex: 1; min-width: 0; }
.dom-setting-title {
  display: flex;
  align-items: center;
  gap: 7px;
  font: 600 13.5px var(--sans);
  color: var(--text);
}
.dom-setting-title svg { flex-shrink: 0; color: var(--text-muted); }
.dom-setting-note {
  margin: 5px 0 0;
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-muted);
}
.dom-setting-note-warn {
  display: block;
  margin-top: 4px;
  color: var(--primary);
  font-weight: 500;
}
.dom-switch {
  position: relative;
  flex-shrink: 0;
  margin-top: 2px;
}
.dom-switch input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}
.dom-switch-track {
  display: block;
  position: relative;
  width: 42px;
  height: 24px;
  border-radius: 999px;
  background: var(--border);
  cursor: pointer;
  transition: background .15s ease;
}
.dom-switch-track::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0,0,0,.12);
  transition: transform .15s ease;
}
.dom-switch input:checked + .dom-switch-track { background: var(--primary); }
.dom-switch input:checked + .dom-switch-track::after { transform: translateX(18px); }
.dom-switch input:focus-visible + .dom-switch-track {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
.dom-switch input:disabled + .dom-switch-track {
  opacity: .55;
  cursor: not-allowed;
}

/* ---------- Liste des publications ---------- */
/*
   Une grille plutôt qu'un tableau, pour une raison mesurable : un <table> prend
   la largeur de son contenu le plus long et déborde ; une grille rétrécit ses
   pistes. « overflow-x: auto » sur la carte ne corrigeait pas le débordement,
   il le rendait défilable — donc invisible à qui développe et pénible à qui lit.
   Les pistes sont en minmax(0, …) : sans le 0, une piste refuse de descendre
   sous la largeur de son contenu et le débordement revient par la fenêtre.
*/
.pub-list { --pub-cols: minmax(0, 2.4fr) auto minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) auto; }

.pub-head {
  display: grid;
  grid-template-columns: var(--pub-cols);
  gap: 0 18px;
  padding: 12px 18px;
  background: var(--bg-subtle);
  border-bottom: 1px solid var(--border);
  font: 600 12px var(--sans);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.pub {
  display: grid;
  grid-template-columns: var(--pub-cols);
  gap: 0 18px;
  align-items: center;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
}
.pub:last-child { border-bottom: 0; }
.pub:hover { background: var(--bg-subtle); }

/* display: contents fait disparaître la boîte du groupe : ses trois cellules
   deviennent elles-mêmes des colonnes de la grille. C'est ce qui permet d'écrire
   les données une seule fois pour les deux mises en page. */
.pub-rest { display: contents; }
.pub-act { text-align: right; }
.pub-cell::before { content: none; }

/* Le dépliant n'existe qu'en petite largeur. La case reste dans le flux mais
   invisible : la retirer avec « display: none » la sortirait de l'ordre de
   tabulation, et le dépliant cesserait d'être atteignable au clavier. */
.pub-toggle { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.pub-more { display: none; }

/* L'adresse peut se couper. C'est elle qui imposait la largeur minimale du
   tableau : un slug de 26 caractères en chasse fixe, en « nowrap ». */
.pub .site-name { flex-wrap: wrap; gap: 8px; }
.pub .site-name a { white-space: normal; overflow-wrap: anywhere; }

@media (max-width: 860px) {
  .pub-head { display: none; }

  /* Deux colonnes : ce qu'on lit, et ce sur quoi on agit. */
  .pub {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 10px 12px;
    align-items: start;
    padding: 16px;
  }
  .pub-addr  { grid-column: 1; }
  .pub-badge { grid-column: 2; justify-self: end; }
  .pub-act   { grid-column: 2; justify-self: end; }

  /* Les détails passent derrière le dépliant, replié par défaut. */
  .pub-rest { display: none; grid-column: 1 / -1; }
  .pub-toggle:checked ~ .pub-rest { display: block; }
  .pub-cell { padding: 3px 0; }
  .pub-cell::before {
    content: attr(data-k) " : ";
    color: var(--text-muted);
    font-size: 12.5px;
  }
  .pub-cell .site-sub { display: inline; margin-left: 4px; }

  .pub-more {
    display: inline-block;
    grid-column: 1;
    justify-self: start;
    font: 600 13px var(--sans);
    color: var(--primary);
    cursor: pointer;
    padding: 6px 0;
    min-height: 32px;
  }
  .pub-more-close { display: none; }
  .pub-toggle:checked ~ .pub-more .pub-more-open { display: none; }
  .pub-toggle:checked ~ .pub-more .pub-more-close { display: inline; }
  .pub-toggle:focus-visible ~ .pub-more { outline: 2px solid var(--primary); outline-offset: 3px; border-radius: 4px; }
}

/* ---------- Tableaux ---------- */
.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th {
  font: 600 12px var(--sans);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-align: left;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-subtle);
}
.table td { padding: 14px 18px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.table tr:last-child td { border-bottom: 0; }
.table tr:hover td { background: var(--bg-subtle); }
.site-name { display: flex; align-items: center; gap: 10px; }
.site-name a { color: var(--text); font: 600 14px var(--mono); text-decoration: none; white-space: nowrap; }
.site-name a:hover { color: var(--primary); text-decoration: underline; }
/* La ligne secondaire d'une cellule : poids, date de publication, dernière
   consultation. En gris et en petit — ces données servent à arbitrer une
   suppression, pas à être lues à chaque passage.

   En sans et sans nowrap, contrairement aux adresses juste au-dessus : une date
   en chasse fixe est sensiblement plus large qu'en proportionnelle, et six
   colonnes qui refusent toutes de se replier forçaient le tableau à 1150 px
   dans une colonne de 980 — soit un défilement horizontal sur un écran de
   1280 px, là où il y a la place. */
.site-sub { font-size: 11.5px; color: var(--text-faint); margin-top: 3px; line-height: 1.45; }
/* Le compteur de consultations est le seul chiffre du tableau : il est aligné
   sur les autres cartes (tabular-nums) et pèse plus que le texte autour. */
.hits-num { font: 700 15px var(--mono); color: var(--text); font-variant-numeric: tabular-nums; }
.hits-none { color: var(--text-faint); }
.copy {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 3px 8px;
  cursor: pointer;
  font: 500 11.5px var(--sans);
  color: var(--text-muted);
  display: none;
  transition: all .15s;
}
.copy:hover { border-color: var(--primary); color: var(--primary); }
.copy.ready { display: inline-block; }

/* Les deux états que copyURL rend au clic, sur les DEUX formes de bouton qui
   l'appellent. Seul « .copy.done » existait, si bien que les sept boutons
   « .btn ghost small » — dont ceux des jetons d'API — ne changeaient que de
   libellé, sans jamais de couleur. Et « echec » n'existait pas du tout, parce
   que l'échec lui-même était silencieux.

   La largeur est figée pendant le retour : le libellé d'échec est plus long que
   « Copier », et sans ça le bouton s'élargit puis rétrécit sous le curseur. */
.copy.done, .btn.done { color: var(--success); border-color: var(--success-border); background: var(--success-light); }
.copy.echec, .btn.echec { color: var(--danger); border-color: var(--danger-border); background: var(--danger-light); }
.copy.done, .copy.echec, .btn.done, .btn.echec { white-space: nowrap; }
.dim { color: var(--text-muted); font-size: 13.5px; }
.gone-soft { font: 600 14px var(--mono); color: var(--text-muted); }
.gone { font: 13.5px var(--mono); color: var(--text-muted); text-decoration: line-through; text-decoration-color: var(--text-faint); white-space: nowrap; }
.nowrap { white-space: nowrap; }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 11.5px;
  font-weight: 600;
  padding: 3px 8px;
  border-radius: var(--radius-sm);
  white-space: nowrap;
}
.badge.live { color: var(--success); background: var(--success-light); border: 1px solid var(--success-border); }
.badge.quarantine, .badge.draft { color: var(--amber); background: var(--amber-light); border: 1px solid var(--amber-border); }
.badge.deleted, .badge.expired { color: var(--text-muted); background: var(--bg-muted); border: 1px solid var(--border); }
.badge.disabled { color: var(--text-muted); background: var(--bg-muted); border: 1px solid var(--border); }

/* L'état vide est la PREMIÈRE page que voit un compte neuf. Un texte centré sur
   fond blanc n'y disait ni quoi faire ni où : la boîte d'icône donne un point
   de fixation, et le bouton renvoie à la zone de dépôt plus haut. */
.empty {
  padding: 56px 24px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
.empty-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: var(--radius-md);
  background: var(--primary-light);
  color: var(--primary);
  margin-bottom: 8px;
}
.empty strong { display: block; font-size: 16px; font-weight: 600; color: var(--text); }
.empty p { color: var(--text-muted); font-size: 14.5px; max-width: 44ch; margin: 0; }
.empty .btn { margin-top: 12px; }

details.history { margin-top: 20px; }
details.history summary {
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-muted);
  padding: 10px 2px;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 8px;
  transition: color .15s;
}
details.history summary::-webkit-details-marker { display: none; }
details.history summary::before { content: "▸"; color: var(--text-faint); transition: transform .15s; display: inline-block; font-size: 12px; }
details.history[open] summary::before { transform: rotate(90deg); }
details.history summary:hover { color: var(--text); }

/* ---------- Flash messages ---------- */
.flash {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 14px 18px;
  border-radius: var(--radius-md);
  font-size: 14.5px;
  margin-bottom: 24px;
  border: 1px solid;
}
.flash.good { border-color: var(--success-border); background: var(--success-light); color: var(--success); }
.flash.bad { border-color: var(--danger-border); background: var(--danger-light); color: var(--danger); }
.flash .ico { flex: 0 0 auto; margin-top: 1px; }

/* ---------- Modale ---------- */
.overlay {
  position: fixed;
  inset: 0;
  background: rgba(9, 9, 11, 0.5);
  backdrop-filter: blur(6px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  z-index: 100;
  animation: fade .12s ease-out;
}
/* Un enregistrement DNS à recopier : un bloc par entrée, un champ par ligne,
   nommés comme le formulaire du registrar les nomme. Un tableau à trois colonnes
   forçait à faire le lien soi-même entre « Nom » et « Sous-domaine », et c'est
   exactement là que le premier utilisateur réel s'est trompé. */
.dns-rec {
  border: 1px solid var(--line, #e5e7eb);
  border-radius: 10px;
  padding: 12px 14px;
  margin: 10px 0;
  background: #fbfbfd;
}
.dns-field { display: flex; gap: 10px; align-items: baseline; padding: 3px 0; flex-wrap: wrap; }
.dns-k {
  min-width: 108px; font-size: 12px; letter-spacing: .02em;
  text-transform: uppercase; color: #6b7280;
}
.dns-field code { font-size: 14px; word-break: break-all; }

/* Le témoin du bouton « Vérifier ». */
/* [hidden] pose display:none dans la feuille du navigateur, qu'une règle
   d'auteur écrase. Sans cette ligne, le témoin tourne en permanence : il l'a
   fait, et il annonçait une vérification qui n'avait pas commencé. */
/* L'ancre du panneau : quelques pixels de marge pour que le titre ne colle pas
   au bord haut de la fenêtre après un saut. */
#domaine { scroll-margin-top: 24px; }

.dom-spin[hidden] { display: none; }
.dom-spin {
  display: inline-block; width: 13px; height: 13px; margin-right: 7px;
  border: 2px solid currentColor; border-right-color: transparent;
  border-radius: 50%; vertical-align: -2px;
  animation: dom-spin .7s linear infinite;
}
@keyframes dom-spin { to { transform: rotate(360deg); } }
.dom-ok { color: #047857; }
.dom-ko { color: #b3261e; }

@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

.card:has(table.table) { overflow-x: auto; }

@media (max-width: 480px) {
  .wrap { padding: 0 16px; }
  .files-list div, .out, code { overflow-wrap: anywhere; }
  .table td, .table th, .table td *, .table th * { overflow-wrap: break-word; }
  .drop { padding: 28px 14px; }
  .slug-row { flex-direction: column; align-items: stretch; gap: 4px; }
  .slug-row .suffix { text-align: left; }
  .btn, .alt-pick button, .mast-nav a { min-height: 44px; }
  .btn.small { min-height: 36px; }

  /* Les indicateurs restent en 2×2, héritée du palier de 720 px : les empiler
     ferait défiler un écran entier pour quatre chiffres. Seule la respiration
     se resserre. */
  .stat-card { padding: 14px 14px 13px; }
  .stat-num { font-size: 24px; }
  .stat-when { font-size: 17px; }
}

/* Le survol d'une offre ou d'un bouton lève l'élément de 2 px. C'est du
   mouvement, et quelqu'un qui l'a désactivé au niveau du système a demandé à ne
   pas en voir : l'ombre et la bordure suffisent alors à marquer le survol. */
@media (prefers-reduced-motion: reduce) {
  .overlay, .menu-pop { animation: none; }
  .btn, .plan, .drop, .tag-up, .back-link svg { transition: none; }
  .btn:hover, .plan:hover, .drop:hover, .tag-up:hover, .back-link:hover svg { transform: none; }
}
.modal {
  background: #fff;
  border-radius: var(--radius-lg);
  max-width: 480px;
  width: 100%;
  padding: 28px;
  box-shadow: var(--shadow-lg);
  border: 1px solid var(--border);
}
.modal h3 { font-size: 19px; font-weight: 700; margin-bottom: 12px; color: var(--text); }
.modal p { font-size: 14.5px; color: var(--text-muted); margin-bottom: 14px; }
/* Un bloc de code court : une commande, une variable d'environnement, une
   adresse. Le visuel existait déjà mais restait enfermé dans les modales, si
   bien qu'une page qui voulait montrer une commande n'avait rien à sa
   disposition — et .info-list, conçu pour des valeurs courtes alignées à
   droite, envoyait la commande à l'autre bout de la carte, loin de son
   libellé. */
/* Les trois lignes de « ce qu'un jeton permet » : le libellé porte la nuance,
   pas du gras. Trois gras d'affilée dans une carte ne hiérarchisent plus rien. */
.pouvoir + .pouvoir { margin-top: 14px; }
.pouvoir-quoi {
  display: block;
  font-size: 12px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  margin-bottom: 2px;
}

.snippet,
.modal .target {
  font: 13.5px var(--mono);
  background: var(--bg-muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 9px 12px;
  margin-bottom: 16px;
  word-break: break-all;
  color: var(--text);
}
.modal ul { list-style: none; font-size: 14px; color: var(--text-muted); margin-bottom: 22px; }
.modal ul li { padding-left: 20px; position: relative; margin-bottom: 6px; }
.modal ul li::before { content: "•"; position: absolute; left: 6px; color: var(--primary); font-weight: 700; }
/* Une rangée de boutons hors modale. Il n'en existait pas : .modal-actions
   aligne à droite, ce qui est juste dans une modale et faux dans une carte. */
.cta-row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-top: 14px; }
.cta-row form { display: flex; }
.modal-actions { display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; }
.modal-actions form { display: flex; }

/* Le focus de la modale doit se VOIR, et c'est « :focus » et non
   « :focus-visible » — délibérément, à l'inverse du reste de la feuille.
   Le script pose le focus sur Annuler à l'ouverture ; or un focus posé par
   script ne satisfait pas :focus-visible, que les navigateurs réservent au
   clavier. Mesuré : element.focus() donnait bien activeElement = Annuler, et
   AUCUN anneau. Un focus qu'on ne voit pas est un focus qu'on ne peut pas
   utiliser — la personne ignore que taper Entrée annule. */
.modal-actions a.btn:focus, .modal-actions button:focus {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* ---------- PRICING / ABONNEMENT ---------- */
.plans {
  display: grid;
  gap: 24px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
  align-items: stretch;
  margin-top: 24px;
}
.plan {
  position: relative;
  padding: 32px 26px 28px;
  border: 1px solid var(--border);
  background: #fff;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.plan:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.plan--hi {
  border-color: var(--primary);
  box-shadow: 0 0 0 1px var(--primary), var(--shadow-md);
}
.ribbon {
  position: absolute;
  top: -12px;
  left: 24px;
  background: var(--primary);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: var(--radius-full);
}
.plan-name {
  font-size: 22px;
  font-weight: 700;
  color: var(--text);
}
.plan-tag {
  margin-top: 6px;
  color: var(--text-muted);
  font-size: 14.5px;
  min-height: 42px;
  line-height: 1.5;
}
.price {
  margin-top: 16px;
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.amount {
  font-size: 36px;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--text);
}
.per {
  color: var(--text-muted);
  font-size: 14px;
}
.feats {
  margin: 24px 0 28px;
  padding: 0;
  list-style: none;
  flex: 1;
}
.feats li {
  position: relative;
  padding-left: 24px;
  margin-bottom: 12px;
  font-size: 14px;
  color: var(--text);
  line-height: 1.45;
}
.feats li::before {
  content: "✓";
  position: absolute;
  left: 0;
  color: var(--success);
  font-weight: 700;
}

/* ---------- Pied de page Signature ---------- */
footer {
  border-top: 1px solid var(--border);
  background: var(--bg-subtle);
  padding: 44px 0 52px;
  margin-top: 64px;
}
.sig {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 32px;
  flex-wrap: wrap;
  font-size: 13.5px;
  color: var(--text-muted);
}
.sig b {
  color: var(--text);
}
.sig-links {
  text-align: right;
  line-height: 1.8;
}
.sig-links a {
  color: var(--primary);
  text-decoration: none;
}
.sig-links a:hover {
  text-decoration: underline;
}
@media (max-width: 640px) {
  .sig-links {
    text-align: left;
  }
}

/* ---------- Cartes et éléments de la page Jetons ---------- */
.token-cards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 360px), 1fr));
  gap: 24px;
  align-items: stretch;
}
.token-card {
  display: flex;
  flex-direction: column;
  padding: 24px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.15s ease, border-color 0.15s ease;
}
.token-card:hover {
  border-color: var(--border-hover);
  box-shadow: var(--shadow-md);
}
.token-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}
.token-card-title-group {
  display: flex;
  align-items: center;
  gap: 12px;
}
.token-icon-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: var(--radius-md);
  background: var(--primary-light);
  color: var(--primary);
  flex-shrink: 0;
}
.token-icon-badge.mcp {
  background: #F5F3FF;
  color: #7C3AED;
}
.token-card-title {
  font-size: 17px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.25;
}
.token-card-sub {
  font-size: 13px;
  color: var(--text-muted);
  margin-top: 2px;
}
.token-meta-box {
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  margin: 16px 0;
  display: grid;
  gap: 10px;
  font-size: 13.5px;
}
.token-meta-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.token-meta-label {
  color: var(--text-muted);
  font-size: 13px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.token-meta-label svg {
  flex-shrink: 0;
}
.token-meta-val {
  font-family: var(--mono);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text);
  text-align: right;
  overflow-wrap: anywhere;
}
.token-meta-val.active {
  color: var(--success);
}
.badge-dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  margin-right: 5px;
}
.badge-dot.pulse {
  animation: pulse-dot 2s infinite;
}
@keyframes pulse-dot {
  0% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.4; transform: scale(0.85); }
  100% { opacity: 1; transform: scale(1); }
}
.token-card-actions {
  margin-top: auto;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.token-card-actions form {
  display: flex;
}

/* Secret Hero Card (Freshly Issued Secret) */
.secret-hero-card {
  padding: 24px;
  border: 1px solid var(--primary-border);
  background: linear-gradient(180deg, var(--primary-light) 0%, #FFFFFF 100%);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  margin-bottom: 32px;
}
.secret-hero-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
}
.secret-hero-badge {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: #DCFCE7;
  color: var(--success);
  border: 1px solid var(--success-border);
  padding: 3px 8px;
  border-radius: var(--radius-full);
}

/* Matrice de sécurité */
.security-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: 16px;
  margin-top: 16px;
}
.security-item {
  padding: 18px 20px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--card);
}
.security-item.allow {
  border-color: var(--success-border);
  background: var(--success-light);
}
.security-item.deny {
  border-color: var(--danger-border);
  background: var(--danger-light);
}
.security-item.warn {
  border-color: var(--amber-border);
  background: var(--amber-light);
}
.security-item-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  font-size: 13.5px;
  margin-bottom: 6px;
}
.security-item.allow .security-item-head { color: var(--success); }
.security-item.deny .security-item-head { color: var(--danger); }
.security-item.warn .security-item-head { color: var(--amber); }
.security-item p {
  font-size: 13px;
  color: var(--text-muted);
  line-height: 1.5;
  margin: 0;
}

/* ---------- Le détail des consultations ----------
   La barre est relative au MAXIMUM de sa tranche, pas au total : on compare
   des pages entre elles, pas une page à l'ensemble. Largeur calculée côté
   serveur (statsRowsFrom) — un gabarit qui divise est un gabarit qu'on ne peut
   pas tester. */
.stats-bar {
  height: 3px;
  margin-top: 6px;
  border-radius: 2px;
  background: var(--primary);
  min-width: 2px;
  max-width: 100%;
}
/* Les filtres de fenêtre de la courbe. Segmenté plutôt que trois boutons
   séparés : les trois valeurs sont exclusives et couvrent tout le domaine, la
   forme doit le dire. */
.stats-filtres {
  display: flex;
  flex-shrink: 0;
  border: 1px solid var(--border);
  border-radius: 7px;
  overflow: hidden;
}
.stats-filtre {
  padding: 5px 11px;
  font-size: 12px;
  line-height: 1.2;
  color: var(--text-muted);
  text-decoration: none;
  white-space: nowrap;
  background: var(--card);
}
.stats-filtre + .stats-filtre { border-left: 1px solid var(--border); }
.stats-filtre:hover { background: var(--bg-muted); color: var(--text); }
.stats-filtre.on {
  background: var(--primary);
  color: #fff;
  font-weight: 600;
}
/* Le focus reste visible : ce sont des liens, ils se parcourent au clavier. */
.stats-filtre:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }

.stats-triple {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  margin-top: 4px;
}
.stats-line {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  padding: 3px 0;
  border-bottom: 1px solid var(--border-subtle, #f0f0f0);
}
@media (max-width: 640px) {
  .stats-triple { grid-template-columns: 1fr; }
}
