/* Polices auto-hébergées (voir docs/DECISIONS.md : système fermé, pas de
   dépendance réseau au runtime — déjà pourquoi socket.io est servi en local). */
@font-face {
  font-family: 'Bebas Neue';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('assets/fonts/bebas-neue-v16-latin-regular.woff2') format('woff2');
}
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('assets/fonts/open-sans-v44-latin.woff2') format('woff2');
}

/* DA Herde Holding : or pris sur le logo, sur fond sombre (conservé : lisibilité à
   distance dans un bureau éclairé, cohérent avec un tableau de suivi "TV board").
   Le rouge sombre reste réservé aux lignes en alerte. */
:root {
  --herde-gold: #e0b43a;
  --alert-bg: #4a1015;
  --bg: #161616;
  --border: #2e2a2a;
  --text-muted: #9b9b9b;
}

/* Écran kiosk : jamais de scroll (personne pour scroller), donc une hauteur figée et un
   pied de page toujours visible. La taille du texte suit la largeur de l'écran, mais
   moins vite qu'elle (formule "a·vw + b") : en 4K (3840 px, écran de 45 à 55" chez
   Rémy) le texte est 1,5× plus grand qu'en 1080p au lieu d'être plafonné à la même
   taille en pixels, qui le rendait deux fois plus petit à l'œil (NEATODO-10). */
html, body { height: 100%; overflow: hidden; }
body {
  font-family: 'Open Sans', sans-serif; background: var(--bg); color: #eee; margin: 0;
  display: flex; flex-direction: column;
}

/* overflow-x en secours : en dessous de la largeur minimale du tableau (cas hors kiosk,
   ex. fenêtre de navigateur très étroite), on défile plutôt que d'écraser les colonnes
   texte libre à 0px. Le kiosk réel ne descend jamais sous ce seuil. */
#board-wrap { flex: 1 1 auto; min-height: 0; overflow: auto hidden; padding: clamp(24px, 1.25vw, 48px) clamp(24px, 1.25vw, 48px) 0; }
table { width: 100%; min-width: 1000px; border-collapse: collapse; table-layout: fixed; font-size: clamp(20px, calc(0.85vw + 16px), 60px); }
th, td { padding: 0.6em; border-bottom: 1px solid var(--border); overflow: hidden; text-overflow: ellipsis; }
td { text-align: left; }
th {
  color: var(--herde-gold); font-size: clamp(17px, calc(0.6vw + 11px), 40px); text-align: center;
  font-family: 'Bebas Neue', 'Open Sans', sans-serif; font-weight: 400; letter-spacing: 0.06em;
}

/* Largeurs mesurées sur le contenu réel le plus long (voir commit) : Type/Statut/Posté
   par/Date sont des valeurs closes qui ne débordent jamais de leur colonne ("En cours",
   "PROBAT26", "ET2", "02/09" + le padding ci-dessus). Le reste (texte libre) se
   partage l'espace ainsi libéré ; Mission n'a pas de largeur fixe : elle reçoit tout ce
   qui reste, car c'est le texte le plus long à lire.
   Les tailles en "ch" suivent la taille de police (donc l'écran), pas les "%". */
.col-destinataire { width: 16%; }
.col-contact { width: 20%; }
.col-type { width: 11.5ch; } /* PROBAT26 / NEASTAGE en capitales : 10,8ch mesurés */
.col-statut { width: 9.5ch; }
/* Initiales d'un compte (jusqu'à "ET10") ou nom saisi par un invité : un prénom court
   tient en entier, un nom plus long est coupé avec "…". */
.col-poste-par { width: 9ch; }
/* white-space sur un <col> ne s'applique pas aux cellules : il faut le poser sur le td,
   sinon un nom long passe sur plusieurs lignes et agrandit toute la ligne. */
td.poste-par { white-space: nowrap; }
/* Jour/mois seulement (pas d'année) : le tableau ne montre que les missions en cours,
   jamais d'un exercice précédent, donc l'année n'apporte rien à l'écran. */
.col-date { width: 7ch; }
.col-type, .col-statut, .col-poste-par, .col-date { white-space: nowrap; }

tr.overdue { animation: blink 1.4s ease-in-out infinite; background: var(--alert-bg); }
@keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }

/* Flash vert puis disparition quand une mission vient d'être validée (voir app.js) :
   la ligne reste visible un court instant avant le rafraîchissement normal qui la
   retire du tableau, au lieu de disparaître d'un coup au prochain load(). */
tr.just-validated { animation: validated 900ms ease forwards; }
@keyframes validated {
  0% { background: #2e7d32; opacity: 1; }
  65% { background: #2e7d32; opacity: 1; }
  100% { background: #2e7d32; opacity: 0; }
}
/* Une teinte par type (liste de Rémy du 03/11/2026), choisie pour rester lisible et
   distincte des autres sur le fond sombre, à plusieurs mètres de l'écran. HERDE reprend
   l'or du logo Herde Holding. */
.type-2ef { color: #d7a86e; }
.type-neastage { color: #f48fb1; }
.type-probat26 { color: #b39ddb; }
.type-greenie { color: #7ed957; }
.type-herde { color: #f2c94c; }
.type-capeb { color: #6fa8ff; }
.type-pompiers { color: #ff6b6b; }
.type-perso { color: #f0f0f0; }
.type-reseaux { color: #4dd0c8; }
.type-autres { color: #a0a0a0; }

/* Bascule entre les pages : fondu rapide, pas un effet qui mange le temps de lecture. */
#board-body { transition: opacity 220ms ease; }
#board-body.fade { opacity: 0; }

/* Pied de page : hauteur fixe, jamais recouvert par le tableau (voir #board-wrap ci-dessus) */
#status-bar {
  flex: 0 0 auto; display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: clamp(16px, 1vw, 40px);
  padding: clamp(16px, 0.85vw, 32px) clamp(24px, 1.25vw, 48px); border-top: 1px solid var(--border);
}
/* Logo centré sur l'écran ; de chaque côté, la météo (entre l'heure et le logo) et
   l'éphéméride (entre le logo et le QR code) sont centrées dans l'espace qui reste
   (NEATODO-11) : flex: 1 leur donne cet espace, puis leur contenu y est centré. */
.footer-side { display: flex; align-items: center; gap: clamp(16px, 1vw, 40px); min-width: 0; }
#clock { display: flex; flex-direction: column; gap: 2px; color: var(--text-muted); flex: 0 0 auto; }
#meteo, #ephemeride { flex: 1 1 0; min-width: 0; font-size: clamp(13px, calc(0.42vw + 8px), 28px); color: var(--text-muted); }
#meteo { display: flex; align-items: center; justify-content: center; gap: 0.5em; }
#meteo[hidden], #ephemeride[hidden] { display: none; }
.meteo-icone {
  width: clamp(40px, calc(1.6vw + 24px), 110px); height: auto; aspect-ratio: 1; flex: 0 0 auto;
  fill: none; stroke: var(--herde-gold); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}
.meteo-texte { display: flex; flex-direction: column; gap: 2px; }
.meteo-temp { font-variant-numeric: tabular-nums; font-size: clamp(20px, calc(0.8vw + 15px), 50px); color: #eee; }
.meteo-detail { white-space: nowrap; }
#ephemeride { display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center; }
.eph-fete { font-size: clamp(20px, calc(0.8vw + 15px), 50px); color: #eee; white-space: nowrap; }
.eph-soleil { display: flex; align-items: center; gap: 0.35em; white-space: nowrap; font-variant-numeric: tabular-nums; }
.eph-icone {
  width: 1.5em; height: auto; aspect-ratio: 1; margin-left: 0.4em;
  fill: none; stroke: var(--herde-gold); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.eph-icone:first-child { margin-left: 0; }
#clock-date { font-size: clamp(13px, calc(0.42vw + 8px), 28px); text-transform: capitalize; }
#clock-time { font-variant-numeric: tabular-nums; font-size: clamp(20px, calc(0.8vw + 15px), 50px); color: #eee; }

#brand { display: flex; flex-direction: column; align-items: center; gap: 10px; }
/* aspect-ratio fixe (pas seulement height:auto) : la hauteur du pied de page est connue dès
   le premier rendu, avant même que l'image ait fini de charger. Sans ça, la mesure de
   pagination (app.js) pourrait s'exécuter avec un pied de page provisoirement plus bas
   (déjà vu avec le QR — voir plus bas). */
#brand-logo { width: clamp(150px, calc(4vw + 80px), 320px); aspect-ratio: 800 / 220; height: auto; }
#page-dots { display: flex; gap: 8px; }
#page-dots span { width: 10px; height: 10px; border-radius: 50%; background: var(--border); }
#page-dots span.active { background: var(--herde-gold); }

#invite-qr { flex: 0 0 auto; margin-left: auto; display: flex; align-items: center; justify-content: flex-end; gap: 16px; }
#invite-qr img { width: clamp(90px, calc(3vw + 58px), 200px); aspect-ratio: 1 / 1; height: auto; background: #fff; border-radius: 6px; }
#invite-qr p { margin: 0; color: var(--text-muted); font-size: clamp(16px, calc(0.55vw + 10px), 32px); }

/* Mode PC (/affichage/?pc, NEATODO-9) : même tableau, mais on défile au lieu de faire
   tourner des pages, et un bandeau en haut indique qui est connecté. */
body.mode-pc, html:has(body.mode-pc) { height: auto; overflow: auto; }
body.mode-pc { min-height: 100vh; }
body.mode-pc #board-wrap { overflow: visible; }
body.mode-pc #status-bar { position: sticky; bottom: 0; background: var(--bg); }
#pc-session {
  display: flex; align-items: center; justify-content: flex-end; gap: 16px; flex-wrap: wrap;
  padding: 10px clamp(24px, 1.25vw, 48px); border-bottom: 1px solid var(--border);
  color: var(--text-muted); font-size: 15px;
}
#pc-session[hidden] { display: none; }
#pc-session strong { color: #eee; }
#pc-session a, #pc-session button {
  color: var(--herde-gold); background: none; border: 1px solid var(--herde-gold); border-radius: 6px;
  padding: 6px 12px; font: inherit; cursor: pointer; text-decoration: none;
}
#pc-session .pc-error { color: #ff8a80; margin-right: auto; }
.statut-select {
  font: inherit; font-size: 0.85em; color: #eee; background: #222; border: 1px solid var(--herde-gold);
  border-radius: 6px; padding: 0.15em 0.2em; max-width: 100%; cursor: pointer;
}
body.mode-pc .col-statut { width: 11ch; }
