@import url('https://fonts.googleapis.com/css2?family=Zen+Kaku+Gothic+New:wght@400;500;700&family=Shippori+Mincho:wght@500;700&family=IBM+Plex+Mono:wght@400;500&display=swap');

:root {
  --bg-0: #0d1422;
  --bg-1: #101a2d;
  --panel: rgba(18, 29, 45, 0.68);
  --line: rgba(164, 208, 190, 0.28);
  --text: #f2f6f7;
  --text-soft: #c8d7d6;
  --text-muted: #93aaa8;
  --matcha: #8fc7ab;
  --sakura: #f3b8b1;
  --amber: #d7b984;
  --danger: #f1a6a1;
  --ok: #98d6b5;
  --radius: 18px;
  --shadow: 0 24px 48px rgba(4, 8, 14, 0.46);
  --font-ui: 'Zen Kaku Gothic New', sans-serif;
  --font-title: 'Shippori Mincho', serif;
  --font-mono: 'IBM Plex Mono', monospace;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  min-height: 100%;
}

body.hub-body {
  font-family: var(--font-ui);
  color: var(--text);
  background: var(--bg-0);
  line-height: 1.6;
}

.hub-bg {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: -1;
}

.hub-bg-gradient {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at 10% 10%, rgba(143, 199, 171, 0.18), transparent 42%),
    radial-gradient(circle at 85% 5%, rgba(243, 184, 177, 0.16), transparent 38%),
    radial-gradient(circle at 50% 90%, rgba(215, 185, 132, 0.16), transparent 46%),
    linear-gradient(160deg, var(--bg-0), var(--bg-1) 55%, #0b1220);
}

.hub-bg-grain {
  position: absolute;
  inset: 0;
  opacity: 0.08;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160' viewBox='0 0 160 160'%3E%3Cg fill='%23ffffff' fill-opacity='0.16'%3E%3Ccircle cx='20' cy='12' r='1.2'/%3E%3Ccircle cx='90' cy='54' r='1.1'/%3E%3Ccircle cx='143' cy='80' r='1.3'/%3E%3Ccircle cx='48' cy='112' r='1.2'/%3E%3Ccircle cx='126' cy='138' r='1.1'/%3E%3C/g%3E%3C/svg%3E");
}

.hub-bg-lines {
  position: absolute;
  inset: 0;
  opacity: 0.2;
  background: repeating-linear-gradient(
    0deg,
    rgba(255, 255, 255, 0) 0,
    rgba(255, 255, 255, 0) 2px,
    rgba(255, 255, 255, 0.03) 3px
  );
}

.hub-kanji {
  position: absolute;
  font-family: var(--font-title);
  font-size: clamp(7rem, 12vw, 12rem);
  color: rgba(201, 238, 219, 0.09);
  user-select: none;
  animation: float-y 7s ease-in-out infinite;
  display: none;
}

.hub-kanji-top {
  top: -1.2rem;
  right: 0.8rem;
}

.hub-kanji-bottom {
  bottom: 1.4rem;
  left: 0.8rem;
  animation-delay: -3s;
}

body.hub-body::before,
body.hub-body::after {
  position: fixed;
  z-index: 0;
  pointer-events: none;
  font-family: var(--font-title);
  font-size: clamp(7rem, 12vw, 12rem);
  color: rgba(201, 238, 219, 0.09);
  line-height: 1;
  animation: float-y 7s ease-in-out infinite;
}

body.hub-body::before {
  content: '\4F98';
  top: -1.2rem;
  right: 0.8rem;
}

body.hub-body::after {
  content: '\5BC2';
  bottom: 1.4rem;
  left: 0.8rem;
  animation-delay: -3s;
}

.hub-topbar,
.hub-main,
.hub-login-shell {
  width: min(1120px, 92vw);
  margin-inline: auto;
}

.hub-topbar {
  padding: 2.2rem 0 1rem;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  align-items: flex-end;
}

.hub-title-group h1,
.hub-panel h2,
.hub-login-card h1 {
  margin: 0;
  font-family: var(--font-title);
  font-weight: 700;
  letter-spacing: 0.02em;
}

.hub-title-group h1 {
  font-size: clamp(1.55rem, 2.4vw, 2.05rem);
}

.hub-kicker {
  margin: 0 0 0.3rem;
  letter-spacing: 0.19em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 0.72rem;
}

.hub-topbar-actions {
  display: flex;
  gap: 0.7rem;
  align-items: center;
}

.hub-user-badge {
  border: 1px solid rgba(152, 214, 181, 0.45);
  border-radius: 999px;
  padding: 0.35rem 0.85rem;
  background: rgba(152, 214, 181, 0.1);
  color: var(--ok);
  font-size: 0.85rem;
}

.hub-main {
  display: grid;
  /* minmax(0, 1fr) et non `auto` : une piste de grille automatique ne descend
     pas sous le min-content de ses éléments. Un tableau large (le suivi de
     positions quand un site est choisi ajoute ses colonnes concurrents)
     élargissait donc le PANNEAU, qui élargissait toute la page — au lieu de
     défiler dans son cadre. Mesuré : panneau à 1257px dans une page de 884. */
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
  padding-bottom: 2.5rem;
}

.hub-panel,
.hub-login-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  backdrop-filter: blur(14px);
  box-shadow: var(--shadow);
}

.hub-panel {
  padding: 1.2rem 1.2rem 1.3rem;
  min-width: 0;
}

.hub-panel.hub-nav {
  padding: 0.85rem 1rem;
}

.hub-panel.hub-nav {
  display: flex;
  align-items: center;
}

.hub-panel.hub-nav .hub-inline-actions {
  align-items: center;
  justify-content: center;
  margin: 0;
  width: 100%;
}

.hub-panel.hub-nav .hub-inline-actions {
  gap: 0.55rem;
}

.hub-panel.hub-nav .hub-inline-actions > .hub-btn {
  flex: 0 0 auto;
  justify-content: center;
  text-align: center;
  padding-left: 1.4rem;
  padding-right: 1.4rem;
}

/* Sépare les boutons par groupe de 3 (séparateur visuel après le 3e, 6e, etc.) */
.hub-panel.hub-nav .hub-inline-actions > .hub-btn:nth-child(3n):not(:last-child) {
  position: relative;
  margin-right: 1.8rem;
}

.hub-panel.hub-nav .hub-inline-actions > .hub-btn:nth-child(3n):not(:last-child)::after {
  content: "";
  position: absolute;
  right: -1.15rem;
  top: 15%;
  bottom: 15%;
  width: 1px;
  background: rgba(255, 255, 255, 0.18);
  pointer-events: none;
}

.hub-panel h2 {
  margin: 0 0 0.9rem;
  font-size: clamp(1.2rem, 2vw, 1.45rem);
}

.hub-subtitle {
  margin: 0.4rem 0 1rem;
  color: var(--text-soft);
}

.hub-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.85rem;
}

/* Deux colonnes au lieu de trois, pour les sections dont les cartes ont besoin
   de largeur sans occuper les deux tiers de l'ecran chacune. Sur mobile, la
   regle generale des grilles reprend la main et tout repasse en colonne. */
.hub-grid-2 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.hub-stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 0.75rem;
}

.hub-stat-card {
  border: 1px solid rgba(160, 204, 187, 0.26);
  border-radius: 14px;
  padding: 0.9rem 1rem;
  background:
    linear-gradient(145deg, rgba(143, 199, 171, 0.1), rgba(243, 184, 177, 0.06)),
    rgba(12, 20, 32, 0.56);
  display: grid;
  gap: 0.15rem;
}

.hub-stat-value {
  font-family: var(--font-title);
  font-size: clamp(1.2rem, 2vw, 1.5rem);
  line-height: 1.2;
  color: var(--text);
}

.hub-stat-label {
  color: var(--text-soft);
  font-size: 0.88rem;
}

.hub-site-card {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  border: 1px solid rgba(160, 204, 187, 0.26);
  border-radius: 14px;
  padding: 1rem;
  background:
    linear-gradient(145deg, rgba(143, 199, 171, 0.08), rgba(243, 184, 177, 0.06)),
    rgba(12, 20, 32, 0.56);
  transition: transform 0.26s ease, border-color 0.26s ease, box-shadow 0.26s ease;
}

.hub-card-span-2 {
  grid-column: span 2;
}

.hub-card-row-span-2 {
  grid-row: span 2;
}

.hub-card-row-span-3 {
  grid-row: span 3;
}

.hub-site-card:hover {
  transform: translateY(-2px);
  border-color: rgba(205, 230, 218, 0.45);
  box-shadow: 0 14px 28px rgba(2, 7, 13, 0.34);
}

.hub-site-head {
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: nowrap;
}

.hub-site-head h3 {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-size: 1.04rem;
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.hub-site-head .hub-btn {
  flex: 0 0 auto;
}

.hub-site-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.55rem;
  margin-top: 0.15rem;
}

.hub-site-stat {
  border: 1px solid rgba(160, 204, 187, 0.22);
  border-radius: 10px;
  padding: 0.58rem 0.62rem;
  background: rgba(8, 15, 25, 0.42);
  display: grid;
  gap: 0.06rem;
}

.hub-site-stat-value {
  font-family: var(--font-title);
  font-size: 1.03rem;
  line-height: 1.25;
}

.hub-site-stat-label {
  font-size: 0.8rem;
  color: var(--text-soft);
}

.hub-site-status {
  font-size: 0.82rem;
  color: var(--amber);
}

.hub-site-options-state {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  justify-content: center;
}

.hub-site-options-state.align-left {
  justify-content: flex-start;
}

.hub-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 999px;
  padding: 0.35rem 0.6rem 0.35rem 0.68rem;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-family: var(--font-mono);
}

.hub-chip.ext {
  color: var(--sakura);
  border-color: rgba(243, 184, 177, 0.5);
  background: rgba(243, 184, 177, 0.12);
}

.hub-chip.ok {
  color: var(--ok);
  border-color: rgba(143, 199, 171, 0.5);
  background: rgba(143, 199, 171, 0.14);
}

.hub-chip.warn {
  color: var(--amber);
  border-color: rgba(215, 185, 132, 0.5);
  background: rgba(215, 185, 132, 0.14);
}

.hub-site-card p {
  margin: 0.55rem 0;
  color: var(--text-soft);
}

.hub-site-meta {
  display: grid;
  gap: 0.45rem;
  color: var(--text-muted);
  font-size: 0.88rem;
}

.hub-site-meta code,
.hub-code,
code {
  font-family: var(--font-mono);
  color: #e8f0f4;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 10px;
  background: rgba(0, 0, 0, 0.22);
  padding: 0.2rem 0.5rem;
  overflow-wrap: anywhere;
}

.hub-btn,
.hub-btn:link,
.hub-btn:visited,
.hub-btn:active {
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  padding: 0.52rem 0.95rem;
  font-family: var(--font-ui);
  font-size: 0.9rem;
  color: var(--text);
  background: rgba(255, 255, 255, 0.08);
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
  white-space: nowrap;
  text-align: center;
  line-height: 1.2;
  vertical-align: middle;
}

.hub-btn:hover {
  transform: translateY(-1px);
  border-color: rgba(255, 255, 255, 0.46);
}

.hub-btn.primary {
  border-color: rgba(143, 199, 171, 0.65);
  background: linear-gradient(135deg, rgba(143, 199, 171, 0.35), rgba(215, 185, 132, 0.3));
}

.hub-btn.ghost {
  background: rgba(255, 255, 255, 0.04);
}

.hub-inline-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55rem;
  margin-top: 0.55rem;
}

.hub-inline-actions form {
  margin: 0;
  display: inline-flex;
  align-items: center;
}

/* Un champ et son bouton, sur UNE ligne. .hub-inline-actions ne convient pas :
   .hub-input pose width:100%, donc le champ mange la ligne entière et le bouton
   passe dessous. Ici le champ prend la place restante et le bouton reste à côté. */
.hub-form-row {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 0.5rem;
}

.hub-form-row .hub-input {
  flex: 1 1 auto;
  width: auto;
}

.hub-form-row .hub-btn {
  flex: 0 0 auto;
}

.hub-site-options-form {
  margin-top: 0.35rem;
  padding-top: 0.55rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  display: grid;
  gap: 0.55rem;
}

.hub-form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.55rem;
}

.hub-form-grid-stack {
  grid-template-columns: 1fr;
  gap: 0.7rem;
}

.hub-field {
  display: grid;
  gap: 0.28rem;
  min-width: 0;
}

.hub-field-label {
  color: var(--text-soft);
  font-size: 0.82rem;
  letter-spacing: 0.02em;
}

.hub-field-help {
  margin: 0.2rem 0 0.45rem;
  color: var(--text-muted);
  font-size: 0.83rem;
}

.hub-checkline {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--text-soft);
  font-size: 0.9rem;
}

.hub-checkline input[type='checkbox'] {
  width: 1rem;
  height: 1rem;
}

.hub-code {
  margin: 0.4rem 0 0;
  padding: 0.8rem;
  white-space: pre-wrap;
  line-height: 1.45;
}

.hub-login-shell {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem 0;
}

.hub-login-card {
  width: min(460px, 100%);
  padding: 1.3rem;
}

.hub-login-card h1 {
  font-size: clamp(1.4rem, 2.8vw, 1.9rem);
}

.hub-login-card .hub-subtitle {
  margin-top: 0.35rem;
}

.hub-form {
  display: grid;
  gap: 0.85rem;
}

.hub-form label {
  display: grid;
  gap: 0.35rem;
  color: var(--text-soft);
  font-size: 0.93rem;
}

.hub-input {
  border: 1px solid rgba(255, 255, 255, 0.23);
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.24);
  color: var(--text);
  font-size: 1rem;
  padding: 0.7rem 0.76rem;
  outline: none;
  width: 100%;
  min-width: 0;
  transition: border-color 0.18s ease, box-shadow 0.18s ease, background-color 0.18s ease;
}

.hub-input:hover:not(:focus):not(:disabled) {
  border-color: rgba(255, 255, 255, 0.36);
}

.hub-input:focus {
  border-color: rgba(143, 199, 171, 0.8);
  box-shadow: 0 0 0 3px rgba(143, 199, 171, 0.19);
}

select.hub-input {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'><path d='M1 1.5L6 6.5L11 1.5' stroke='rgba(230,238,232,0.7)' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  background-size: 12px 8px;
  padding-right: 2.2rem;
  cursor: pointer;
  line-height: 1.2;
}

select.hub-input::-ms-expand { display: none; }

select.hub-input:focus {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'><path d='M1 1.5L6 6.5L11 1.5' stroke='rgba(143,199,171,1)' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/></svg>");
}

select.hub-input:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

select.hub-input option {
  background: #1a1f2e;
  color: var(--text);
  padding: 6px 10px;
}

select.hub-input.hub-input-sm {
  padding-right: 2rem;
  background-position: right 0.7rem center;
}

.hub-notice {
  margin: 0.7rem 0 0.8rem;
  padding: 0.62rem 0.75rem;
  border-radius: 10px;
  border: 1px solid transparent;
  font-size: 0.92rem;
}

.hub-notice.error {
  border-color: rgba(241, 166, 161, 0.65);
  color: var(--danger);
  background: rgba(241, 166, 161, 0.11);
}

.hub-notice.warn {
  border-color: rgba(215, 185, 132, 0.65);
  color: var(--amber);
  background: rgba(215, 185, 132, 0.13);
}

.hub-notice.ok {
  border-color: rgba(152, 214, 181, 0.65);
  color: var(--ok);
  background: rgba(152, 214, 181, 0.12);
}

.hub-meta {
  margin: 0.9rem 0 0;
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 0.76rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.hub-textarea {
  min-height: 180px;
  resize: vertical;
}

.hub-textarea-compact {
  min-height: 120px;
}

.hub-table-wrap {
  margin-top: 0.7rem;
  border: 1px solid rgba(160, 204, 187, 0.22);
  border-radius: 12px;
  overflow: auto;
  background: rgba(8, 15, 25, 0.42);
}

.hub-table {
  width: 100%;
  border-collapse: collapse;
  min-width: 780px;
}

.hub-table th,
.hub-table td {
  padding: 0.58rem 0.62rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  vertical-align: top;
  text-align: left;
}

.hub-table th {
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-family: var(--font-mono);
  background: rgba(0, 0, 0, 0.18);
}

.hub-table tr:last-child td {
  border-bottom: none;
}

/* Un groupe de boutons dans une cellule ne doit pas hériter du décalage
   vertical de .hub-inline-actions : la cellule fait déjà la marge. Et il reste
   sur une ligne — deux boutons empilés font une ligne deux fois plus haute que
   son contenu, ce qui décale tout le reste de la ligne. */
.hub-table td > .hub-inline-actions {
  margin-top: 0;
  flex-wrap: nowrap;
}

/* Lignes dont la hauteur est dictée par un bouton (colonnes d'actions) : le
   texte des autres colonnes se centre au lieu de flotter en haut. */
.hub-table-middle th,
.hub-table-middle td {
  vertical-align: middle;
}

/* Une pastille est une étiquette : « en attente » sur deux lignes double la
   hauteur de la ligne pour rien. */
.hub-table .hub-chip {
  white-space: nowrap;
}

.hub-cell-sub {
  color: var(--text-muted);
  font-size: 0.8rem;
}

.hub-row-actions {
  display: flex;
  gap: 0.4rem;
  align-items: center;
  flex-wrap: wrap;
}

.hub-input-sm {
  padding: 0.45rem 0.55rem;
  font-size: 0.86rem;
  min-height: 2rem;
}

.hub-th-link {
  color: inherit;
  text-decoration: none;
}

.hub-th-link:hover {
  text-decoration: underline;
}

/* Texte long rendu depuis du Markdown (plans IA). L'admin n'a nulle part
   ailleurs de prose à lire au kilomètre : sans ces règles, les titres et les
   listes héritent des marges nulles du reste de l'interface et le plan sort en
   un seul bloc illisible. */
.hub-prose {
  max-width: 78ch;
  line-height: 1.6;
}

.hub-prose h3,
.hub-prose h4,
.hub-prose h5 {
  margin: 1.2rem 0 0.4rem;
  font-size: 1rem;
  letter-spacing: 0.01em;
}

.hub-prose h3:first-child,
.hub-prose h4:first-child {
  margin-top: 0;
}

.hub-prose p {
  margin: 0 0 0.7rem;
}

.hub-prose ul {
  margin: 0 0 0.8rem;
  padding-left: 1.2rem;
}

.hub-prose li {
  margin-bottom: 0.3rem;
}

.hub-prose code {
  font-size: 0.88em;
  padding: 0.1em 0.3em;
  border-radius: 4px;
  background: rgba(127, 127, 127, 0.14);
}

.hub-focus-banner {
  margin-top: 0.7rem;
  margin-bottom: 1rem;
  border: 1px solid rgba(143, 199, 171, 0.45);
  border-radius: 12px;
  padding: 0.85rem 0.95rem;
  background: linear-gradient(145deg, rgba(143, 199, 171, 0.14), rgba(215, 185, 132, 0.12));
}

.hub-focus-banner strong {
  display: block;
  margin-bottom: 0.25rem;
}

.hub-focus-list {
  margin: 0;
  padding-left: 1.1rem;
}

.hub-focus-list li {
  color: var(--text-soft);
  margin: 0.18rem 0;
}

.hub-settings-grid {
  margin-top: 1.15rem;
  gap: 1rem;
  grid-auto-flow: row dense;
  align-items: stretch;
}

.hub-settings-grid .hub-site-card {
  justify-content: center;
  gap: 0.8rem;
  padding: 1.1rem 1.05rem;
}

.hub-settings-grid .hub-site-card form {
  display: grid;
  gap: 0.75rem;
  width: 100%;
}

.hub-settings-grid .hub-site-card h3 {
  margin: 0;
}

.hub-settings-grid .hub-site-card .hub-inline-actions {
  margin-top: 0.1rem;
}

.hub-hero {
  display: grid;
  gap: 0.95rem;
}

.hub-hero-head {
  display: flex;
  justify-content: space-between;
  gap: 0.9rem;
  align-items: flex-start;
  flex-wrap: wrap;
}

.hub-kpi-strip {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 0.55rem;
  width: 100%;
  flex: 1 1 100%;
}

.hub-kpi {
  border: 1px solid rgba(160, 204, 187, 0.22);
  border-radius: 10px;
  padding: 0.56rem 0.62rem;
  background: rgba(8, 15, 25, 0.42);
  display: grid;
  gap: 0.05rem;
}

.hub-kpi-value {
  font-family: var(--font-title);
  font-size: 1.05rem;
  line-height: 1.2;
}

.hub-kpi-label {
  color: var(--text-soft);
  font-size: 0.76rem;
}

.hub-split {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: 0.85rem;
}

/* align-content: start est structurel, pas cosmétique. Sans lui, la grille
   hérite de `normal` (= stretch) : quand une colonne de .hub-split est plus
   haute que l'autre, la colonne courte répartit l'écart entre ses lignes auto.
   Le titre h3 gonflait alors de 27px à 165px et le tableau ne commençait plus
   en haut du bloc. */
.hub-stack {
  display: grid;
  gap: 0.6rem;
  min-width: 0;
  align-content: start;
}

.hub-stack h3 {
  margin: 0;
  font-size: 1rem;
}

.hub-project-picker {
  margin-top: 0;
}

/* Pas de largeur plancher chiffrée : elle serait arbitraire, et un tableau qui
   dépasse de 20px se paierait une barre de défilement pour rien. La largeur
   minimale se déduit du contenu — nowrap sur les colonnes courtes, min-width
   sur les colonnes de texte long (voir plus bas). Le tableau ne déborde donc
   que lorsqu'il en a vraiment besoin, et c'est là que la barre apparaît. */
.hub-table-compact {
  min-width: 0;
}

.hub-table-compact th,
.hub-table-compact td {
  padding: 0.5rem 0.55rem;
}

/* Ce qui ne doit jamais passer à la ligne : positions, dates, compteurs,
   intitulés de colonne. Un « hors top 100 » coupé en trois ne se lit pas, et un
   en-tête « 7 j » cassé entre le 7 et le j encore moins.
   Les rares en-têtes vraiment longs portent .hub-cell-wrap : en capitales, ils
   sont plus larges que les nombres qu'ils chapeautent, et les garder d'un seul
   tenant imposait une barre de défilement à des tableaux qui tiennent. */
.hub-table-compact td,
.hub-table-compact th {
  white-space: nowrap;
}

/* Deux exceptions au nowrap, deux intentions distinctes.

   .hub-cell-wrap — texte moyen (nom de site, domaine, en-tête long) : il a le
   droit de s'enrouler, mais ne réclame aucune largeur. */
.hub-table-compact .hub-cell-wrap {
  white-space: normal;
}

/* .hub-cell-long — texte long (mot-clé, URL) : il s'enroule ET réclame de la
   place. Le min-width est ce qui le fait RESPIRER : sans lui, le navigateur
   donne 115px à la colonne « Mot-clé » et le texte tombe sur six lignes, ce qui
   faisait des lignes de 145px de haut. */
.hub-table-compact .hub-cell-long {
  white-space: normal;
  min-width: 16rem;
}

/* Colonne de .hub-split : moitié moins de place, on demande moins. */
.hub-split .hub-table-compact .hub-cell-long {
  min-width: 11rem;
}

.fade-up {
  opacity: 0;
  transform: translateY(12px);
  animation: fade-up 560ms ease forwards;
  animation-delay: var(--delay, 0ms);
}

@keyframes fade-up {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes float-y {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(18px);
  }
}

@media (max-width: 800px) {
  .hub-topbar {
    align-items: flex-start;
    flex-direction: column;
    padding-top: 1.5rem;
  }

  .hub-title-group h1 {
    font-size: 1.5rem;
  }

  .hub-topbar-actions {
    width: 100%;
    justify-content: space-between;
  }

  .hub-kpi-strip {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .hub-split {
    grid-template-columns: 1fr;
  }

  .hub-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 520px) {
  .hub-topbar,
  .hub-main,
  .hub-login-shell {
    width: min(1120px, 94vw);
  }

  .hub-login-card,
  .hub-panel {
    padding: 1rem;
  }

  .hub-user-badge {
    display: none;
  }

  .hub-site-stats {
    grid-template-columns: 1fr;
  }

  .hub-form-grid {
    grid-template-columns: 1fr;
  }

  .hub-card-span-2 {
    grid-column: span 1;
  }

  .hub-kpi-strip {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .hub-grid {
    grid-template-columns: 1fr;
  }
}

.hub-chart-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 8px;
}

.hub-chart-head h2 {
  margin: 0;
}

.hub-chart-legend {
  display: flex;
  gap: 14px;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--text-soft);
}

.hub-chart-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.hub-chart-swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 2px;
}

.hub-chart-svg-wrap {
  width: 100%;
  margin-top: 4px;
  color: var(--text);
}

.hub-chart-svg {
  width: 100%;
  height: auto;
  display: block;
  font-family: var(--font-mono);
}

.hub-integrations {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  margin-bottom: 1rem;
}

.hub-integration-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.6rem;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: rgba(8, 15, 25, 0.42);
}

.hub-integration-info {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.55rem;
}

.hub-integration-name {
  font-family: var(--font-title);
  font-size: 0.95rem;
}

.hub-integration-hint {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-soft);
}

.hub-integration-row .hub-inline-actions {
  margin: 0;
}

.hub-filter-row {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
}

.hub-filter-row .hub-input {
  min-width: 200px;
}

/* ===========================================================
 * Themed scrollbars (matcha-on-ink)
 * =========================================================== */
* {
  scrollbar-width: thin;
  scrollbar-color: rgba(143, 199, 171, 0.42) rgba(255, 255, 255, 0.04);
}

*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

*::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.04);
  border-radius: 10px;
}

*::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, rgba(143, 199, 171, 0.55), rgba(143, 199, 171, 0.32));
  border: 2px solid transparent;
  background-clip: padding-box;
  border-radius: 10px;
  transition: background-color 0.18s ease;
}

*::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(180deg, rgba(143, 199, 171, 0.85), rgba(143, 199, 171, 0.55));
  background-clip: padding-box;
}

*::-webkit-scrollbar-corner {
  background: transparent;
}

.hub-scroll-y {
  overflow-y: auto;
  /* auto et non hidden : .hub-scroll-y est déclaré après .hub-table-wrap et
     écrasait son `overflow: auto`. Un tableau plus large que son panneau (le
     suivi de positions avec ses colonnes concurrents) perdait ses dernières
     colonnes sans aucun moyen de les atteindre. */
  overflow-x: auto;
  padding-right: 2px;
}

.hub-scroll-y > table {
  margin: 0;
}

/* En-tête figé : dans une fenêtre de 560px, une liste longue défile sous des
   colonnes qu'on ne voit plus. Fond opaque obligatoire — celui de .hub-table th
   est translucide et laisserait passer les lignes qui défilent dessous. */
.hub-scroll-y thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: #131d2c;
}

/* ---------- Alerts emphasis ---------- */
.hub-alert-row .hub-alert-message {
  font-weight: 600;
  font-size: 1rem;
  color: var(--text);
}

.hub-alert-row.is-unread {
  background: rgba(215, 185, 132, 0.08);
  box-shadow: inset 3px 0 0 var(--amber, #d7b984);
}

.hub-alert-row.is-unread .hub-alert-message {
  color: var(--amber, #d7b984);
}

.hub-alert-row.is-read .hub-alert-message {
  font-weight: 500;
  color: var(--text-soft);
}

/* ---------- Hub alerts hero ---------- */
.hub-alerts-hero {
  padding: 0.75rem 0.95rem 0.85rem;
}

.hub-alerts-hero-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}

.hub-alerts-hero h2 {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  color: var(--text-soft);
}

.hub-alerts-hero-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 0.4rem;
  border-radius: 999px;
  background: rgba(215, 185, 132, 0.18);
  border: 1px solid rgba(215, 185, 132, 0.45);
  color: var(--amber);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 600;
  line-height: 1;
}

.hub-alerts-hero-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.55rem;
}

.hub-alerts-hero-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.65rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid rgba(215, 185, 132, 0.22);
  border-left: 2px solid rgba(215, 185, 132, 0.6);
  border-radius: 8px;
  background: rgba(215, 185, 132, 0.12);
}

.hub-alerts-hero-item-main {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem;
  min-width: 0;
  flex: 1 1 auto;
}

.hub-alerts-hero-item-message {
  font-weight: 500;
  font-size: 0.88rem;
  color: var(--text);
  line-height: 1.3;
}

.hub-alerts-hero-item-meta {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem;
  color: var(--text-muted);
  font-size: 0.74rem;
}

.hub-alerts-hero-item-site {
  color: var(--text-soft);
  font-weight: 500;
}

.hub-alerts-hero-item-date {
  font-family: var(--font-mono);
}

.hub-alerts-hero-item-action {
  flex: 0 0 auto;
  margin: 0;
  display: inline-flex;
}

@media (max-width: 640px) {
  .hub-alerts-hero-item {
    flex-direction: column;
    align-items: stretch;
  }
  .hub-alerts-hero-item-action {
    width: 100%;
  }
  .hub-alerts-hero-item-action .hub-btn {
    width: 100%;
  }
}

/* ---------- Alerts page (cards layout) ---------- */
.hub-alerts-header-info {
  display: flex;
  align-items: baseline;
  gap: 0.85rem;
  flex-wrap: wrap;
}

.hub-alerts-header-info h2 {
  margin: 0;
}

.hub-alerts-summary {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  color: var(--text-muted);
  font-size: 0.88rem;
  font-family: var(--font-mono);
}

.hub-alerts-summary-item strong {
  color: var(--amber);
  font-weight: 600;
}

.hub-alerts-summary-sep {
  opacity: 0.5;
}

.hub-alerts-section-title {
  margin: 0 0 0.7rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.hub-alerts-cards-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.55rem;
}

.hub-alert-card {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.7rem 0.85rem;
  border: 1px solid rgba(160, 204, 187, 0.18);
  border-radius: 12px;
  background: rgba(8, 15, 25, 0.42);
  transition: border-color 0.2s ease, transform 0.2s ease;
}

.hub-alert-card:hover {
  border-color: rgba(205, 230, 218, 0.32);
  transform: translateY(-1px);
}

.hub-alert-card.is-unread {
  background: rgba(215, 185, 132, 0.12);
  border-color: rgba(215, 185, 132, 0.32);
  border-left: 3px solid var(--amber);
  padding-left: calc(0.85rem - 2px);
}

.hub-alert-card-icon {
  flex: 0 0 auto;
  width: 2.2rem;
  height: 2.2rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: rgba(215, 185, 132, 0.18);
  color: var(--amber);
  font-size: 1.1rem;
  line-height: 1;
}

.hub-alert-card.is-read .hub-alert-card-icon {
  background: rgba(160, 204, 187, 0.12);
  color: var(--text-muted);
}

.hub-alert-card-body {
  flex: 1 1 auto;
  min-width: 0;
  display: grid;
  gap: 0.3rem;
}

.hub-alert-card-message {
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--text);
  line-height: 1.35;
}

.hub-alert-card.is-read .hub-alert-card-message {
  font-weight: 500;
  color: var(--text-soft);
}

.hub-alert-card-meta {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.45rem;
  color: var(--text-muted);
  font-size: 0.78rem;
}

.hub-alert-card-site {
  color: var(--text-soft);
  font-weight: 500;
}

.hub-alert-card-date {
  font-family: var(--font-mono);
}

.hub-alert-card-actions {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.hub-alert-card-actions form {
  margin: 0;
  display: inline-flex;
}

.hub-alert-card-actions .hub-btn[aria-label="Supprimer"] {
  padding: 0.42rem 0.7rem;
  font-size: 1.05rem;
  line-height: 1;
}

.hub-alerts-empty {
  text-align: center;
  padding: 2rem 1rem;
  display: grid;
  gap: 0.4rem;
  justify-items: center;
}

.hub-alerts-empty-icon {
  width: 3.2rem;
  height: 3.2rem;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(152, 214, 181, 0.18);
  color: var(--ok);
  font-size: 1.4rem;
  margin-bottom: 0.3rem;
}

.hub-alerts-empty-title {
  margin: 0;
  font-weight: 600;
  color: var(--text);
}

.hub-alerts-empty-sub {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.88rem;
}

@media (max-width: 640px) {
  .hub-alert-card {
    flex-wrap: wrap;
  }
  .hub-alert-card-actions {
    width: 100%;
    justify-content: flex-end;
  }
}

/* ===========================================================
 * Outils IA — carte de résultat
 * =========================================================== */
.hub-outil-result {
  margin-top: 1.25rem;
  border: 1px solid rgba(160, 204, 187, 0.32);
  border-radius: 16px;
  background:
    linear-gradient(155deg, rgba(143, 199, 171, 0.1), rgba(243, 184, 177, 0.05)),
    rgba(8, 15, 25, 0.52);
  box-shadow: 0 16px 34px rgba(2, 7, 13, 0.34);
  overflow: hidden;
  animation: outil-reveal 440ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

@keyframes outil-reveal {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.992);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.hub-outil-result-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
  padding: 0.7rem 0.95rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.22), rgba(0, 0, 0, 0.08));
}

.hub-outil-result-title {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--font-title);
  font-size: 1rem;
  letter-spacing: 0.02em;
  min-width: 0;
}

.hub-outil-result-icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 999px;
  background: rgba(143, 199, 171, 0.16);
  border: 1px solid rgba(143, 199, 171, 0.4);
  color: var(--matcha);
  font-size: 1rem;
  line-height: 1;
}

.hub-outil-lang-flow {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.hub-outil-lang-arrow {
  color: var(--matcha);
  opacity: 0.7;
  font-size: 0.9rem;
}

.hub-outil-result-actions {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  flex: 0 0 auto;
}

.hub-outil-result-body {
  margin: 0;
  padding: 1.05rem 1.1rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-family: var(--font-ui);
  font-size: 1.04rem;
  line-height: 1.72;
  color: var(--text);
  max-height: 460px;
  overflow-y: auto;
}

.hub-outil-result-body::selection {
  background: rgba(143, 199, 171, 0.35);
}

.hub-outil-result-foot {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  flex-wrap: wrap;
  padding: 0.55rem 1.1rem 0.7rem;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  color: var(--text-muted);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

.hub-outil-result-foot-stat {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

.hub-outil-result-foot-stat strong {
  color: var(--text-soft);
  font-weight: 600;
}

.hub-outil-result-foot-sep {
  opacity: 0.4;
}

/* Bascule segmentée Résultat / Modifications */
.hub-outil-view-toggle {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.24);
}

.hub-outil-seg {
  border: 0;
  margin: 0;
  background: transparent;
  color: var(--text-soft);
  font-family: var(--font-ui);
  font-size: 0.8rem;
  line-height: 1.2;
  padding: 0.32rem 0.72rem;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease;
}

.hub-outil-seg:hover {
  color: var(--text);
}

.hub-outil-seg.is-active {
  color: var(--text);
  background: linear-gradient(135deg, rgba(143, 199, 171, 0.35), rgba(215, 185, 132, 0.3));
}

/* Surlignage du diff mot-à-mot */
.hub-diff-ins {
  color: var(--ok);
  background: rgba(143, 199, 171, 0.2);
  border-radius: 4px;
  padding: 0 0.14em;
  box-shadow: inset 0 -1px 0 rgba(143, 199, 171, 0.55);
}

.hub-diff-del {
  color: var(--danger);
  background: rgba(241, 166, 161, 0.13);
  border-radius: 4px;
  padding: 0 0.14em;
  text-decoration: line-through;
  text-decoration-color: rgba(241, 166, 161, 0.75);
}

.hub-diff-count-ins,
.hub-diff-count-ins strong {
  color: var(--ok);
}

.hub-diff-count-del,
.hub-diff-count-del strong {
  color: var(--danger);
}

#outil-stat-changes .hub-diff-count-del {
  margin-left: 0.1rem;
}

/* Lien en ligne — le seul de la console, et il lui manquait.
   Toutes les autres pages n'affichent que des boutons ; le sujet d'une
   conversation est pourtant un lien, et on en montre quarante d'affilée. Sans
   règle, ils tombaient sur le bleu et le violet du navigateur, qui n'existent
   nulle part ailleurs dans cette interface. */
.hub-link {
  color: var(--text-strong, #dbe9e2);
  text-decoration: none;
  border-bottom: 1px solid rgba(160, 204, 187, 0.32);
  transition: color 0.15s ease, border-color 0.15s ease;
}

.hub-link:hover,
.hub-link:focus-visible {
  color: #a0ccbb;
  border-bottom-color: #a0ccbb;
}

/* Un fil non lu se lit d'abord au poids du nom ; son sujet n'a pas besoin d'en
   rajouter. */
.hub-table tr.is-selected .hub-link {
  color: #a0ccbb;
}

/* -----------------------------------------------------------------------
 * AJOUT PROPRE À VISITEURS — ne vient pas de la feuille de la console.
 *
 * ⚠️ SI CETTE FEUILLE EST UN JOUR RECOPIÉE DEPUIS LA CONSOLE, CE BLOC DOIT
 * ÊTRE REPORTÉ. Sans lui, `hub-field-hint` n'est plus qu'un nom de classe
 * sans règle : les notes des écrans s'affichent alors en texte ordinaire,
 * indistinguables du contenu qu'elles commentent. Rien ne casse, rien ne
 * s'affiche en erreur — c'est exactement pourquoi ça peut durer longtemps.
 * --------------------------------------------------------------------- */
.hub-field-hint {
  color: var(--text-soft);
  font-size: 0.82rem;
  line-height: 1.5;
  margin: 0.35rem 0 0;
}

/* Une explication qui PRÉCÈDE un formulaire, et non qui suit un champ.
   La marge de base est en haut seulement — logique sous un champ, mais elle
   collait le texte au bouton dans l'autre sens (« Inactif… » sur l'écran
   Sécurité). On desserre ici plutôt que d'ajouter une marge basse à toutes
   les explications, y compris celles qui closent un bloc. */
.hub-field-hint + .hub-form,
.hub-field-hint + .hub-form-row {
  margin-top: 0.9rem;
}

/* Le crochet du journal : « confirmé par un vrai navigateur », en un signe.
   `--ok` est déjà la couleur des états positifs de la palette. */
.hub-ok-mark {
  color: var(--ok);
  font-weight: 700;
  margin-left: 0.35rem;
}
