/* Accueil — feuille du widget « Horloges ».

   UN WIDGET = UN FICHIER, ici aussi : ce style vivait dans le monolithe
   css/components.css, à rebours de la règle du projet. Il est chargé par sa
   propre balise <link> dans index.html, à côté du <script> du widget, et
   inscrit dans le socle du Service Worker (sw.js) — sans quoi il
   manquerait hors ligne. */

/* ---------- Widget « Horloges » ----------------------------------------
   Une rangée par compteur, tenue par une grille : l'icône et les boutons ont
   une largeur fixe, le nom et la valeur se partagent le reste. Un simple
   `flex` laisserait les valeurs se décaler d'une rangée à l'autre selon la
   longueur du nom, et une colonne de chiffres qui ne s'aligne pas se lit mal. */
.hor { display: flex; flex-direction: column; gap: 8px;
  overflow-y: auto; overflow-x: hidden; }
/* La liste EST la grille ; chaque rangée n'en reprend que les colonnes. Sans
   ça, chaque rangée formait sa propre grille et ne savait rien des autres :
   les champs de nom avaient des largeurs différentes selon ce que la rangée
   d'à côté affichait, et la colonne d'état, dimensionnée pour un bouton,
   rognait « manquée » en « MAN… ». Avec `subgrid`, une seule colonne d'état
   sert toutes les rangées et se dimensionne sur la plus bavarde. */
/* Les colonnes de bouton font 27 px pour un bouton de 24 : chacun garde ainsi
   trois pixels à sa gauche, ce qui les espace entre eux ET détache le premier
   des chiffres. Un `column-gap` plus large aurait écarté aussi le nom de son
   pictogramme, qu'on venait justement de rapprocher. */
.hor__liste { display: grid; align-content: start; row-gap: 5px; flex: 1 1 auto;
  grid-template-columns: 17px minmax(0, 1fr) auto auto 27px 27px 27px; }
.hor__vide { margin: auto 0; grid-column: 1 / -1; text-align: center;
  font: 400 11px/1.5 var(--mono); color: var(--text-5); }

/* La MÊME grille pour les trois types, alarme comprise. Toutes les colonnes
   ont une largeur fixe sauf le nom, qui prend ce qui reste : les champs de nom
   font donc exactement la même largeur d'une rangée à l'autre, et les chiffres
   s'alignent en colonne. Avec des colonnes « auto », chaque rangée se calait
   sur son propre contenu et plus rien ne s'alignait. */
.hor__item { display: grid; grid-column: 1 / -1;
  grid-template-columns: subgrid; align-items: center; column-gap: 5px;
  padding: 4px 6px 4px 4px; border-radius: var(--r-md);
  background: var(--glass-inner); border: 1px solid var(--glass-inner-border); }
.hor__type { display: inline-flex; color: var(--text-5); }
.hor__type .ico { font-size: 15px; }
/* TROIS emplacements de bouton, tous de 24 px, pour les trois types : les
   commandes ont ainsi la même taille et le même écartement d'une rangée à
   l'autre. Une alarme n'a pas de bouton de réinitialisation ; sa place reste
   vide plutôt que d'être comblée, sinon sa corbeille remonterait d'un cran et
   ne serait plus alignée avec celle du dessus.

   L'état, lui, est rangé AVANT la valeur — « manquée 17:00 » se lit comme une
   phrase — au lieu de s'intercaler entre les boutons, où il déformait leur
   écartement selon ce qu'il avait à dire. */
.hor__etat { grid-column: 3 / 4; }
.hor__item > .hor__valeur { grid-column: 4 / 5; }
.hor__item[data-type="alarme"] > .hor__b--arme { grid-column: 5 / 6; }
.hor__item > .hor__b--danger { grid-column: 7 / 8; }
/* TOUS les boutons se calent à droite de leur colonne, pas seulement ceux qui
   se suivent. Le sélecteur par adjacence n'atteignait pas la corbeille d'une
   rangée d'alarme — l'état s'intercale entre la cloche et elle — et elle se
   retrouvait 9 px plus à droite que celle de la rangée voisine. */
.hor__item > .hor__b { justify-self: end; }
.hor__etat:empty { display: none; }

/* Le nom et la valeur sont des champs SANS cadre : la rangée porte déjà le
   sien, et six cadres imbriqués dans une carte étroite font une grille de
   formulaire là où on veut lire l'heure. */
.hor__nom {
  background: none; border: 0; padding: 2px 3px; border-radius: var(--r-sm);
  color: var(--text-2); font: 400 12px var(--sans); min-width: 0; }
.hor__nom::placeholder { color: var(--text-6); }
.hor__nom:hover, .hor__valeur--saisie:hover { background: rgba(255, 255, 255, .05); }
.hor__nom:focus, .hor__valeur--saisie:focus { outline: none;
  background: rgba(var(--accent-rgb), .1); color: var(--text-strong); }

/* La valeur : chasse fixe et chiffres tabulaires, sinon elle sautille à chaque
   seconde — la largeur d'un « 1 » n'est pas celle d'un « 8 ».

   Une taille FIXE, aussi, pas proportionnelle à la carte. C'est un compteur :
   on le lit de loin, et une police qui rétrécit avec la carte finit par rendre
   illisible la seule chose que le widget ait à montrer.

   Et surtout, LA MÊME BOÎTE pour le champ et pour le texte. Un rebours au repos
   est un champ de saisie ; lancé, il devient un texte. Deux boîtes différentes,
   et les chiffres sautaient de quelques pixels au moment précis où on clique —
   pour la même raison, ceux du chronomètre ne s'alignaient pas sur ceux du
   rebours d'à côté. Même largeur, même marge intérieure, même alignement, et
   plus rien ne bouge. */
.hor__valeur { font-family: var(--mono); font-weight: 500;
  font-variant-numeric: tabular-nums; font-size: 15px;
  color: var(--text-strong); text-align: right; white-space: nowrap;
  width: 8.5ch; padding: 2px 3px; box-sizing: border-box; justify-self: end;
  margin-right: 2px;
  background: none; border: 0; border-radius: var(--r-sm); }
/* Ce qui dort s'écrit en gris : la durée d'un rebours au repos, un chrono qui
   n'a pas encore servi, une alarme désarmée. Ce qui est allumé doit se voir
   d'un coup d'œil. */
.hor__valeur--repos { color: var(--text-3); font-weight: 400; }

.hor__etat { font: 400 9.5px var(--mono); color: var(--text-5);
  text-transform: uppercase; letter-spacing: .04em; white-space: nowrap;
  text-align: right; }
.hor__etat--manquee { color: var(--warning); }

.hor__b { display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; flex: none; padding: 0; cursor: pointer;
  border-radius: var(--r-sm); background: none; border: 1px solid transparent;
  color: var(--text-4); }
.hor__b:hover { background: rgba(255, 255, 255, .1); color: var(--text-strong); }
/* Le pictogramme remplit son bouton : c'est LUI qu'on vise, et un triangle de
   13 px au milieu d'un carré de 24 laissait une cible molle entourée de vide.
   Le bouton, lui, ne bouge pas — toute la rangée serait sinon à recalculer. */
.hor__b .ico { font-size: 18px; }
.hor__b--go { color: var(--accent-soft); }
/* Un compteur qui tourne, une alarme armée : la commande porte l'accent. L'état
   se lit alors sur le bouton, au lieu de se déduire en comparant deux chiffres
   à une seconde d'intervalle. */
.hor__b--actif { color: var(--accent); background: rgba(var(--accent-rgb), .16);
  border-color: rgba(var(--accent-rgb), .45); }
.hor__b--actif:hover { background: rgba(var(--accent-rgb), .26);
  color: var(--accent-soft); }
/* Le rouge est écrit en clair, comme partout ailleurs dans cette feuille :
   `--danger` porte une couleur, pas un triplet, et ne passe donc pas dans
   `rgba()`. */
.hor__b--danger:hover { background: rgba(248, 113, 113, .16); color: var(--danger); }
/* Muet, pas absent : le bouton garde sa place, sinon la colonne des valeurs se
   décale d'une rangée à l'autre selon qu'un compteur a déjà tourné ou non. */
.hor__b--muet { opacity: .28; pointer-events: none; }

/* Ce qui vient de sonner se voit — c'est le canal garanti, celui qui ne dépend
   pas de l'autorisation du navigateur. Un nombre d'itérations FINI : une
   pulsation perpétuelle deviendrait un décor qu'on ne remarque plus. */
@keyframes hor-pulse {
  0%, 100% { background: var(--glass-inner); border-color: var(--glass-inner-border); }
  50% { background: rgba(var(--accent-rgb), .22); border-color: rgba(var(--accent-rgb), .6); }
}
/* La sonnerie dure cinq secondes, l'animation aussi : elle bat tant qu'elle
   sonne, et la rangée entière devient un bouton d'arrêt. */
.hor__item--sonne { animation: hor-pulse .8s ease-in-out infinite; cursor: pointer; }
.hor__item--sonne .hor__valeur { color: var(--accent); }
.hor__item--manquee .hor__valeur,
.hor__item--fini .hor__valeur { color: var(--text-4); }
@media (prefers-reduced-motion: reduce) {
  .hor__item--sonne { animation: none;
    background: rgba(var(--accent-rgb), .18);
    border-color: rgba(var(--accent-rgb), .5); }
}

/* Le pied porte les trois ajouts et le plein écran. Le pointillé de la version
   précédente annonçait un emplacement à remplir — c'est le vocabulaire de
   « Ajouter une section » — là où ce sont des commandes ordinaires. Elles
   reprennent donc le verre des boutons du gestionnaire de liens. */
.hor__pied { display: flex; flex-wrap: wrap; gap: 5px; flex: none; }
.hor__add { flex: 1 1 0; display: inline-flex; align-items: center;
  justify-content: center; gap: 6px; height: 28px; padding: 0 8px; cursor: pointer;
  border-radius: var(--r-md); font: 400 11.5px var(--sans); color: var(--text-2);
  background: var(--glass-inner); border: 1px solid var(--glass-inner-border); }
.hor__add:hover { background: rgba(255, 255, 255, .1); color: var(--text-strong);
  border-color: rgba(255, 255, 255, .2); }
.hor__add .ico { font-size: 15px; color: var(--text-4); }
.hor__add:hover .ico { color: var(--accent-soft); }
/* Le plein écran prend sa propre rangée, pleine largeur : c'est la place qu'il
   occupe dans le gestionnaire de liens, et ce n'est pas une commande d'ajout —
   la mettre en bout de file avec les trois autres la donnait pour telle. */
.hor__add--fs { flex: 1 0 100%; }
/* Carte étroite : les libellés s'effacent, les icônes suffisent. */
.hor--serre .hor__add > span { display: none; }
.hor--serre .hor__add { padding: 0; }
.hor--serre .hor__etat { display: none; }

/* ---------- Horloges · vue projecteur ----------------------------------
   Le CSS ne sait pas compter ses propres enfants : le widget pose donc le
   nombre de COLONNES et de RANGÉES, et la taille des chiffres s'en déduit.
   Diviser par le nombre de compteurs, comme je l'avais d'abord écrit, était
   faux — huit compteurs sur trois rangées ne tiennent pas huit fois moins de
   hauteur, ils en tiennent trois fois moins. */
.horfs { display: grid; gap: 4vh 4vw; align-content: center; justify-items: center;
  grid-template-columns: repeat(var(--horfs-c, 1), minmax(0, 1fr));
  width: min(94vw, 1600px); position: relative; }
/* Un voile propre à cette vue. Le fond d'écran flouté de la page suffit
   derrière un QR — un carré blanc se détache de tout — mais pas derrière des
   chiffres, qui se confondaient avec les cartes restées visibles dessous. */
.horfs::before { content: ""; position: fixed; inset: 0; z-index: -1;
  background: rgba(8, 9, 13, .58); }
.horfs__vide { margin: 0; font: 400 clamp(14px, 2.6vh, 26px) var(--mono);
  color: rgba(255, 255, 255, .6); }
.horfs__case { display: flex; flex-direction: column; align-items: center; gap: .6vh; }
.horfs__nom { margin: 0; max-width: 90%; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap;
  font: 500 clamp(12px, 2.2vh, 22px)/1.2 var(--sans);
  color: rgba(255, 255, 255, .74); letter-spacing: .02em; }
.horfs__val { margin: 0; font-family: var(--mono); font-weight: 600;
  font-variant-numeric: tabular-nums; line-height: 1;
  color: #fff; text-shadow: 0 3px 26px rgba(0, 0, 0, .65);
  /* Trois grandeurs, et il faut les trois. La HAUTEUR se partage entre les
     rangées ; la LARGEUR entre les colonnes ; et dans une colonne, entre les
     CARACTÈRES — c'est celle que j'avais oubliée, et « 01:36,81 » débordait de
     l'écran alors que le calcul le disait à l'aise. 0,62 em est la chasse des
     chiffres de la police monospace, mesurée. */
  font-size: clamp(24px, min(calc(30vh / var(--horfs-r, 1)),
    calc(86vw / (var(--horfs-c, 1) * 0.62 * var(--horfs-ch, 8)))), 260px); }
.horfs__etat { margin: 0; font: 400 clamp(9px, 1.5vh, 14px) var(--mono);
  text-transform: uppercase; letter-spacing: .08em;
  color: rgba(255, 255, 255, .45); }
.horfs__val--repos { color: rgba(255, 255, 255, .5); }
/* Le temps restant avant qu'une alarme ne sonne. Assez grand pour se lire du
   fond de la salle — c'est un chiffre sur lequel on décide — mais GRIS : à
   l'accent, il rivalisait avec l'heure au-dessus alors qu'il la commente. Et
   posé un peu plus bas, pour qu'on voie qu'il en dépend. */
.horfs__reste { margin: .9vh 0 0; font-family: var(--mono); font-weight: 500;
  font-variant-numeric: tabular-nums; line-height: 1.1;
  font-size: clamp(14px, 2.9vh, 34px); color: rgba(255, 255, 255, .5);
  text-shadow: 0 2px 16px rgba(0, 0, 0, .6); }

/* Les commandes en projection. Sans elles il faudrait quitter la vue pour
   relancer un chrono — exactement le geste qu'on ne veut pas faire devant une
   salle. Elles restent discrètes au repos et s'allument au survol. */
.horfs__cmd { display: flex; gap: 1.4vh; margin-top: .8vh; }
.horfs__b { display: inline-flex; align-items: center; justify-content: center;
  width: clamp(30px, 4.4vh, 52px); height: clamp(30px, 4.4vh, 52px);
  padding: 0; cursor: pointer; border-radius: 50%;
  background: rgba(255, 255, 255, .1); border: 1px solid rgba(255, 255, 255, .2);
  color: rgba(255, 255, 255, .8); }
.horfs__b:hover { background: rgba(255, 255, 255, .2); color: #fff; }
.horfs__b .ico { font-size: clamp(15px, 2.4vh, 28px); }
.horfs__b--actif { color: var(--accent);
  background: rgba(var(--accent-rgb), .22);
  border-color: rgba(var(--accent-rgb), .55); }

/* UNE ALARME QUI SONNE SE VOIT DE LOIN. C'est tout l'écran qui bat, pas la
   seule case concernée : en projection, le regard n'est pas forcément sur le
   compteur au moment où il sonne. Le voile est en `fixed` et couvre la fenêtre
   entière, y compris ce que la grille ne recouvre pas. */
/* Le voile ne s'éteint jamais complètement : il BAT entre deux intensités.
   Une pulsation qui passe par zéro laisse, une fois sur deux, un écran
   parfaitement normal — et c'est précisément à cet instant-là qu'on regarde. */
@keyframes horfs-flash {
  0%, 100% { opacity: .45; }
  50% { opacity: 1; }
}
.horfs--sonne::after { content: ""; position: fixed; inset: 0; z-index: 2;
  pointer-events: none;
  background: radial-gradient(ellipse at center,
    rgba(var(--accent-rgb), .10) 0%, rgba(var(--accent-rgb), .30) 100%);
  /* Une LUEUR qui s'estompe vers l'intérieur, plus un bandeau net. Le bandeau
     ne déplaçait rien — mesuré, la grille et ses cases restaient au pixel près
     aux mêmes coordonnées — mais il recouvrait franchement le pourtour de
     l'écran, ce qui se lit comme un cadre qui rogne l'image. Une lueur dit la
     même chose sans rien masquer. */
  box-shadow: inset 0 0 clamp(30px, 7vh, 90px) clamp(6px, 1.4vh, 18px)
    rgba(var(--accent-rgb), .55);
  animation: horfs-flash .8s ease-in-out infinite; }
/* Les cases restent au-dessus du voile, et cliquable pour faire taire. */
.horfs--sonne .horfs__case { position: relative; z-index: 3; }
.horfs__case--sonne { cursor: pointer; }
.horfs__case--sonne .horfs__val { color: var(--accent); }
.horfs__case--sonne .horfs__etat { color: var(--accent-soft); }
@media (prefers-reduced-motion: reduce) {
  .horfs--sonne::after { animation: none; opacity: .85; }
}
