/*
 * Console d'administration — direction « Relecture », arrêtée le 7 septembre 2026.
 *
 * Prémisse : la politique est un document versionné, et le vrai risque de cette
 * console est de publier une modification qu'on n'avait pas vue. Tout est donc
 * composé comme une épreuve à corriger — une gouttière de relecture porte en
 * marge le compte des modifications non publiées, et l'en-tête ne quitte jamais
 * la version en vigueur des yeux.
 *
 * S'y ajoute le tapis de parc : un poste, une cellule. À deux cents sièges un
 * tableau ne se lit plus, alors qu'une grille de couleurs se lit d'un coup.
 *
 * Deux écarts assumés au §10.1 de specs/SITE_SPECS.md, qui demande à la console
 * de reprendre la charte du site :
 *
 *   1. Fond clair. Le site est sombre ; une console qu'on garde ouverte la
 *      journée dans un bureau éclairé ne l'est pas.
 *   2. Des couleurs d'état — vert, ambre — distinctes de la couleur de risque.
 *      Le site n'a qu'un rouge, réservé au blocage ; un parc a quatre états, et
 *      les distinguer par la seule densité serait illisible. Le rouge, lui,
 *      garde ici son sens exact : un poste révoqué.
 *
 * Aucune requête sortante : IBM Plex Mono est servie depuis wwwroot, déposée là
 * par `npm run brand`. Le texte courant prend la pile système — un éditeur de
 * sécurité ne fait pas chercher ses polices chez un tiers.
 *
 * Tous les contrastes texte/fond sont mesurés au-dessus de 4,5:1.
 */

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/ibm-plex-mono.ttf") format("truetype");
}

:root {
  color-scheme: light;

  --bg: #fbfcfd;
  --panel: #ffffff;
  --ink: #16202b;
  --dim: #4b5a69;
  --muted: #637386;
  --line: #dde5ed;
  --strong: #9fb1c2;

  --mark: #14508c;
  --on-mark: #ffffff;

  /* Les cinq états d'un poste. Le rouge ne sort pas de son emploi. */
  --ok: #1f7a5a;
  --idle: #c3cfda;
  --warn: #8f5a0d;
  --bad: #a32b1c;
  /* Un poste qui a refusé la politique publiée : ni révoqué, ni muet, mais
     hors de la configuration que l'administrateur croit lui appliquer. */
  --drift: #6c3fb5;

  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;

  /* Un intitulé de champ, une en-tête de colonne, un tampon : toujours la même
     capitale espacée, en mono. C'est ce qui tient l'écran ensemble. */
  --label: 400 10px/1.5 var(--mono);
}

* { box-sizing: border-box; }

[hidden] { display: none !important; }

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--ink);
  font: 400 14px/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0; letter-spacing: -.015em; }
h1 { font: 400 20px/1.1 var(--mono); letter-spacing: -.01em; }
h2 { font-size: 20px; font-weight: 700; }
h3 { font-size: 15px; font-weight: 700; }
p { margin: 0; }

.eyebrow {
  margin: 0 0 6px;
  color: var(--muted);
  font: var(--label);
  letter-spacing: .15em;
  text-transform: uppercase;
}

a { color: var(--mark); }

:focus-visible {
  outline: 2px solid var(--mark);
  outline-offset: 2px;
}

/* ── En-tête : l'identité à gauche, le document en cours à droite ─────────── */

header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
  padding: 18px max(20px, calc((100% - 1240px) / 2));
  border-bottom: 2px solid var(--ink);
}

header h1 { text-transform: uppercase; letter-spacing: .02em; }

.session {
  display: flex;
  align-items: center;
  gap: 16px;
}

#connection-state {
  color: var(--muted);
  font: 400 12px/1 var(--mono);
}

/* Le sélecteur de langue se tient à côté de l’état de session : c’est une
   préférence d’affichage, pas une commande. */
.locale select {
  padding: 6px 8px;
  border-color: var(--strong);
  background: transparent;
  color: var(--dim);
  font: 400 11px/1 var(--mono);
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Fermer sa session n'est pas l'action principale de l'écran : le bouton est
   creux, à la taille d'un intitulé, et ne se dispute rien avec le reste. */
#sign-out {
  padding: 7px 11px;
  border-color: var(--strong);
  background: transparent;
  color: var(--dim);
  font: 400 11px/1 var(--mono);
  letter-spacing: .1em;
  text-transform: uppercase;
}

#sign-out:hover { border-color: var(--ink); background: transparent; color: var(--ink); }

main {
  margin: 0 auto;
  max-width: 1800px;
  padding: 0 max(20px, calc((100% - 1800px) / 2)) 64px;
}

/* ── Connexion ───────────────────────────────────────────────────────────── */

.auth-panel {
  margin: 64px auto;
  max-width: 420px;
  padding: 30px 32px 34px;
  background: var(--panel);
  border: 1px solid var(--strong);
  border-top: 2px solid var(--ink);
  border-radius: 2px;
}

.auth-panel h2 { margin-bottom: 4px; }

/* ── La console : rail de navigation, puis la feuille ────────────────────── */

#console {
  display: grid;
  grid-template-columns: 168px minmax(0, 1fr);
  align-items: start;
}

#console > nav {
  /* Le rail longe toute la colonne, pas seulement la première rangée : sans
     cette portée, chaque vue commencait sous le dernier onglet. */
  grid-column: 1;
  grid-row: 1 / span 20;
  display: grid;
  align-content: start;
  padding: 26px 0 0;
  border-right: 1px solid var(--line);
}

#console > nav button {
  margin-right: -1px;
  padding: 11px 18px 11px 0;
  border: 0;
  border-right: 2px solid transparent;
  background: none;
  color: var(--dim);
  cursor: pointer;
  font: 500 13.5px/1 var(--sans);
  text-align: left;
}

#console > nav button:hover:not(:disabled) { color: var(--ink); }

#console > nav button.active {
  border-right-color: var(--mark);
  color: var(--mark);
  font-weight: 700;
}

#console > nav button:disabled { color: var(--strong); cursor: not-allowed; }

#console > [data-view],
#console > #tenant-suspended,
#console > #tenant-unknown,
#console > #status { grid-column: 2; }

/* Le filet reste dans la marge et le texte tombe sur la colonne de contenu :
   13 px de marge plus les 13 px de retrait commun font les 26 px des vues. */
#console > #status { margin-left: 13px; }

/* La suspension se lit avant tout le reste de la feuille, et dans sa colonne. */
#console > #tenant-suspended,
#console > #tenant-unknown { margin: 26px 0 0 13px; }

/* La feuille : tout ce qui suit le rail respire du même retrait. */
[data-view] { padding: 26px 0 0 26px; }

/* ── Retours et messages ─────────────────────────────────────────────────── */

#status, .feedback {
  margin: 0 0 20px;
  padding: 3px 0 3px 13px;
  border-left: 3px solid var(--mark);
  color: var(--dim);
  font-size: 13px;
  min-height: 20px;
}

#status:empty { border-left-color: transparent; }

#status.error, .feedback.error {
  border-left-color: var(--bad);
  color: var(--bad);
}

.feedback { margin-top: 18px; }

/* ── Chiffres de tête ────────────────────────────────────────────────────── */

.grid.metrics {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.metrics article {
  padding: 15px 22px 17px;
  border-right: 1px solid var(--line);
}

.metrics article:first-child { padding-left: 0; }
.metrics article:last-child { border-right: 0; }

.metrics span {
  display: block;
  font: 400 30px/1 var(--sans);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
}

.metrics small {
  display: block;
  margin-top: 7px;
  color: var(--muted);
  font: var(--label);
  letter-spacing: .13em;
  text-transform: uppercase;
}

/* ── Le tapis de parc ────────────────────────────────────────────────────── */

/*
 * Un poste, une cellule. C'est la seule vue qui traite le parc comme une
 * population plutôt qu'une liste : à deux cents sièges, on voit les révoqués
 * sans lire une ligne. Chaque cellule porte son intitulé en `title`, et la
 * légende dit ce que veut dire chaque couleur — une couleur seule ne suffit
 * jamais à porter une information.
 */
.carpet { margin-top: 22px; }

.carpet-cells {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14px, 1fr));
  gap: 4px;
  margin-top: 12px;
}

.carpet-cells i {
  display: block;
  aspect-ratio: 1;
  border-radius: 2px;
  background: var(--idle);
}

.carpet-cells i.is-active { background: var(--ok); }
.carpet-cells i.is-stale { background: var(--warn); }
.carpet-cells i.is-revoked { background: var(--bad); }
.carpet-cells i.is-drift { background: var(--drift); }

.carpet-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin-top: 13px;
  color: var(--muted);
  font: 400 11.5px/1 var(--mono);
}

.carpet-legend span { display: flex; align-items: center; gap: 7px; }

.carpet-legend i {
  display: block;
  width: 9px;
  height: 9px;
  border-radius: 2px;
}

/* Les couleurs de la légende, en classes et non en attributs style : la politique de sécurité
   des pages n'admet aucun style inline (PageSecurityHeaders). */
.carpet-legend i.legend-hour { background: var(--ok); }
.carpet-legend i.legend-week { background: var(--idle); }
.carpet-legend i.legend-silent { background: var(--warn); }
.carpet-legend i.legend-revoked { background: var(--bad); }
.carpet-legend i.legend-drift { background: var(--drift); }

.carpet-empty { margin-top: 12px; color: var(--muted); font-size: 13px; }

/* ── Panneaux et gouttière de relecture ──────────────────────────────────── */

.panel {
  margin-top: 24px;
  padding: 0 0 0 26px;
  border-left: 2px solid var(--line);
}

.panel > h2,
.panel > h3 { margin-bottom: 14px; }

/*
 * La gouttière. Un panneau qui porte des modifications non publiées passe au
 * bleu et affiche leur compte en marge, comme une correction sur épreuve. Le
 * compte vient de `data-changes`, posé par admin.js.
 */
.panel.is-dirty {
  position: relative;
  border-left-color: var(--mark);
}

.panel.is-dirty::before {
  content: attr(data-changes);
  position: absolute;
  top: 1px;
  left: -2px;
  padding-left: 7px;
  color: var(--mark);
  font: 400 10px/1.4 var(--mono);
  letter-spacing: .06em;
  white-space: nowrap;
}

.section-heading {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 14px;
}

.section-heading small,
.form-section small {
  display: block;
  margin-top: 4px;
  color: var(--muted);
  font-size: 12.5px;
}

.policy-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin-top: 0;
}

.actions { display: flex; flex-wrap: wrap; gap: 10px; }

/* ── Formulaires ─────────────────────────────────────────────────────────── */

form { display: grid; gap: 16px; margin-top: 16px; }

label {
  display: grid;
  gap: 6px;
  color: var(--dim);
  font: 700 11.5px/1.3 var(--sans);
}

label.check {
  grid-auto-flow: column;
  justify-content: start;
  align-items: center;
  gap: 8px;
  font-weight: 500;
}

input, select, textarea {
  padding: 9px 10px;
  border: 1px solid var(--strong);
  border-radius: 2px;
  background: var(--panel);
  color: var(--ink);
  font: 400 13.5px/1.4 var(--sans);
}

input:read-only { background: var(--bg); color: var(--dim); }

input[type="number"], .limit-minutes { font-family: var(--mono); font-variant-numeric: tabular-nums; }

textarea, .domain-list {
  min-height: 240px;
  resize: vertical;
  font: 400 13px/1.6 var(--mono);
}

button {
  padding: 10px 15px;
  border: 1px solid var(--mark);
  border-radius: 2px;
  background: var(--mark);
  color: var(--on-mark);
  cursor: pointer;
  font: 700 12.5px/1 var(--sans);
}

button:hover:not(:disabled) { background: #10406f; border-color: #10406f; }

button:disabled { cursor: not-allowed; opacity: .4; }

/* Une action destructrice se distingue par la forme autant que par la couleur :
   elle est creuse, jamais pleine, pour ne pas se cliquer par habitude. */
button.danger,
.icon-button {
  background: transparent;
  border-color: var(--bad);
  color: var(--bad);
}

button.danger:hover:not(:disabled),
.icon-button:hover:not(:disabled) { background: #f7e8e5; }

.icon-button { min-width: 40px; padding: 9px; }

.inline {
  grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
  align-items: end;
}

.form-grid {
  display: grid;
  gap: 16px;
  max-width: 720px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.form-section { margin-top: 22px; }

.editor-list { display: grid; gap: 10px; margin-top: 14px; }

.editor-row {
  display: grid;
  gap: 10px;
  align-items: center;
  grid-template-columns: 2fr 1fr 1fr auto;
}

.service-row { grid-template-columns: 1.2fr 1.5fr 1fr .7fr 1.5fr auto; }

.editor-row > *,
.editor-row input,
.editor-row select { width: 100%; min-width: 0; }

/* ── Tableaux et listes de postes ────────────────────────────────────────── */

.table { margin-top: 6px; }

.device-row {
  display: grid;
  gap: 10px 16px;
  align-items: center;
  grid-template-columns: 1.2fr 1fr 1fr auto;
  padding: 11px 0;
  border-bottom: 1px solid var(--line);
}

.device-row strong { font-weight: 600; }

.device-row span { color: var(--dim); font-size: 13px; }

.device-row small {
  color: var(--muted);
  font: var(--label);
  letter-spacing: .1em;
  text-transform: uppercase;
}

.device-row small.is-revoked { color: var(--bad); }
.device-row small.is-drift { color: var(--drift); }
/* Le sélecteur porte `.device-row small` : `.device-row small` pèse 0,1,2 et
   poserait `var(--muted)` par-dessus un `.is-unsupported` seul, qui ne pèse
   que 0,1,0. La ligne se serait affichée en gris, et rien n'aurait rougi. */
.device-row small.is-unsupported { color: var(--warn); }

/* ── Blocs de sortie ─────────────────────────────────────────────────────── */

output, pre {
  display: block;
  margin: 16px 0 0;
  padding: 13px 15px;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 2px;
  background: var(--panel);
  color: var(--dim);
  font: 400 12.5px/1.7 var(--mono);
  white-space: pre-wrap;
  word-break: break-word;
}

output:empty, pre:empty { display: none; }

/* ── Second facteur ──────────────────────────────────────────────────────── */

.mfa-setup {
  display: grid;
  align-items: start;
  gap: 24px;
  grid-template-columns: 240px minmax(0, 1fr);
  margin-top: 20px;
}

.mfa-setup img {
  width: 240px;
  height: 240px;
  padding: 10px;
  border: 1px solid var(--strong);
  background: #fff;
  image-rendering: pixelated;
}

.mfa-setup pre { grid-column: 1 / -1; }

details { margin-top: 14px; }
summary { cursor: pointer; font-weight: 600; }

/* ── Petites largeurs ────────────────────────────────────────────────────── */

@media (max-width: 860px) {
  #console { grid-template-columns: minmax(0, 1fr); }

  #console > nav {
    display: flex;
    flex-wrap: wrap;
    padding: 18px 0 0;
    border-right: 0;
    border-bottom: 1px solid var(--line);
  }

  #console > nav button {
    margin: 0 0 -1px;
    padding: 10px 14px;
    border-right: 0;
    border-bottom: 2px solid transparent;
  }

  #console > nav button.active { border-right-color: transparent; border-bottom-color: var(--mark); }

  #console > [data-view],
  #console > #tenant-suspended,
  #console > #tenant-unknown,
  #console > #status { grid-column: 1; }

  #console > #status,
  #console > #tenant-suspended,
  #console > #tenant-unknown { margin-left: 0; }

  [data-view] { padding-left: 0; }

  .grid.metrics { grid-template-columns: minmax(0, 1fr); }
  .metrics article { padding-left: 0; border-right: 0; border-bottom: 1px solid var(--line); }
  .metrics article:last-child { border-bottom: 0; }

  .policy-header, .section-heading { flex-direction: column; align-items: stretch; }
  .inline, .form-grid, .editor-row, .service-row, .mfa-setup { grid-template-columns: minmax(0, 1fr); }
  .device-row { grid-template-columns: minmax(0, 1fr); }
  .mfa-setup pre { grid-column: 1; }
  .mfa-setup img { justify-self: center; }
}
