/* ============================================================
   SYSTÈME DE DESIGN
   Un seul jeu de variables décrit toute l'apparence. Le thème
   clair est la référence ; le thème sombre ne redéfinit que les
   valeurs qui changent. La bascule se fait sur <html data-theme>.
   ============================================================ */
:root {
  color-scheme: light;

  /* Fonds */
  --fond-page:      #EFECE6;
  --fond-voute:     radial-gradient(120% 90% at 12% -10%, #FFFFFF 0%, #F3F0EA 42%, #E8E4DC 100%);
  --surface:        #FFFFFF;
  --surface-douce:  #F7F5F1;
  --surface-haute:  #FFFFFF;
  --surface-creuse: rgba(28, 26, 24, 0.045);
  --surface-survol: #FBFAF7;

  /* Texte */
  --texte:       #191715;
  --texte-doux:  rgba(25, 23, 21, 0.58);
  --texte-faible:rgba(25, 23, 21, 0.40);

  /* Traits et reliefs */
  --trait:        rgba(25, 23, 21, 0.10);
  --trait-fort:   rgba(25, 23, 21, 0.18);
  --ombre-1: 0 1px 2px rgba(25,23,21,.05), 0 2px 8px rgba(25,23,21,.045);
  --ombre-2: 0 2px 6px rgba(25,23,21,.06), 0 12px 28px rgba(25,23,21,.09);
  --ombre-3: 0 8px 20px rgba(25,23,21,.10), 0 32px 64px rgba(25,23,21,.16);

  /* Couleurs fonctionnelles */
  --accent:        #2E7D63;
  --accent-fort:   #256A53;
  --accent-doux:   rgba(46, 125, 99, 0.12);
  --accent-contraste: #FFFFFF;
  --danger:        #C0503A;
  --danger-doux:   rgba(192, 80, 58, 0.12);
  --succes:        #2E7D63;
  --succes-contraste: #FFFFFF;
  --danger-contraste: #FFFFFF;
  --alerte:        #B37514;
  --alerte-doux:   rgba(179, 117, 20, 0.16);
  /* Clarté des couleurs de ressenti : assez sombre pour rester lisible
     sur fond clair (voir couleurRessenti). */
  --clarte-ressenti: 38%;

  /* Accents par catégorie : teinte + fond de pastille */
  --cat-volets:    #3E6FA8;  --cat-volets-fond:    rgba(62, 111, 168, 0.13);
  --cat-eclairage: #DDAB00;  --cat-eclairage-fond: rgba(221, 171, 0, 0.18);
  --cat-energie:   #6A4DB8;  --cat-energie-fond:   rgba(106, 77, 184, 0.13);
  --cat-vehicule:  #2E7D63;  --cat-vehicule-fond:  rgba(46, 125, 99, 0.13);
  --cat-meteo:     #1D7F94;  --cat-meteo-fond:     rgba(29, 127, 148, 0.13);
  /* Couleurs des symboles météo : chaque élément garde la sienne. */
  --meteo-soleil: #E0A81C;  --meteo-nuage: #7C868F;
  --meteo-nuage-fonce: #5E6871;  --meteo-pluie: #2C7CC0;
  --meteo-neige: #9FB6CB;
  --cat-securite:  #C0503A;  --cat-securite-fond:  rgba(192, 80, 58, 0.13);
  --cat-chauffage: #C2703E;  --cat-chauffage-fond: rgba(194, 112, 62, 0.14);
  --cat-autres:    #6B655D;  --cat-autres-fond:    rgba(107, 101, 93, 0.13);
  /* « Air intérieur » (27/09/2026) : un bleu ciel, plus vif et plus clair
     que le bleu acier des volets, plus bleu que le cyan de la météo. */
  --cat-air:       #2A8BC9;  --cat-air-fond:       rgba(42, 139, 201, 0.13);
  /* Teintes supplémentaires, proposées au choix pour une catégorie ou un
     appareil. Choisies pour se distinguer les unes des autres ET des sept
     ci-dessus : une couleur qu'on ne sait pas nommer d'un coup d'œil ne
     sert à rien sur une tuile. Chacune a sa version sombre plus bas. */
  --cat-orange:    #C2701C;  --cat-orange-fond:    rgba(194, 112, 28, 0.15);
  --cat-rose:      #B8436F;  --cat-rose-fond:      rgba(184, 67, 111, 0.13);
  --cat-prune:     #94459B;  --cat-prune-fond:     rgba(148, 69, 155, 0.13);
  --cat-indigo:    #4A55B0;  --cat-indigo-fond:    rgba(74, 85, 176, 0.13);
  --cat-vert:      #3F8A46;  --cat-vert-fond:      rgba(63, 138, 70, 0.13);
  --cat-olive:     #6D8A1E;  --cat-olive-fond:     rgba(109, 138, 30, 0.15);
  --cat-ardoise:   #56707F;  --cat-ardoise-fond:   rgba(86, 112, 127, 0.13);

  /* Sens du flux d'énergie : ambre pour ce qui est consommé, vert pour
     ce qui est reçu (production, injection). */
  --flux-conso: #E0A63A;  --flux-conso-fond: rgba(224, 166, 58, 0.18);
  --flux-recu:  #2E7D63;  --flux-recu-fond:  rgba(46, 125, 99, 0.16);

  /* Formes */
  --r-xs: 8px; --r-sm: 12px; --r-md: 16px; --r-lg: 22px; --r-xl: 28px; --r-pilule: 999px;

  /* Mouvement : trois durées, une seule courbe. Tout ce qui bouge dans
     le tableau de bord pioche ici -- c'est ce qui fait qu'une pression,
     un survol et l'arrivée d'une page se ressemblent au lieu d'avoir
     chacun son tempo. La courbe démarre vite et finit doucement : le
     geste répond tout de suite, la fin se pose. Les rotations et les
     pulsations gardent « linear » et « ease-in-out » : une roue qui
     accélère et ralentit n'est plus une roue. */
  --vite:  .12s;   /* pressions, survols, bascules d'état */
  --moyen: .2s;    /* apparitions, glissements courts */
  --lent:  .32s;   /* panneaux, arrivées de page */
  --courbe: cubic-bezier(.2, .7, .2, 1);

  /* Typographie : une échelle fermée. Toute taille écrite à la main
     avait fini par diverger d'une page à l'autre -- 10,5 ici, 11,5 là,
     12,5 ailleurs, pour le même rôle. Les voici ramenées aux barreaux
     ci-dessous ; aucune n'a bougé de plus de 8 %, donc rien ne se
     recompose, mais il n'y a plus de tailles intermédiaires. Une
     nouvelle règle pioche dans cette liste, et nulle part ailleurs. */
  --t-9:  9px;    /* graduations d'un graphique en SVG */
  --t-10: 10px;   /* mentions minuscules */
  --t-11: 11px;   /* badges, légendes */
  --t-12: 12px;   /* texte d'appoint */
  --t-13: 13px;   /* texte courant secondaire */
  --t-15: 15px;   /* texte courant */
  --t-17: 17px;   /* titres de tuile */
  --t-19: 19px;   /* titres de section */
  --t-21: 21px;   /* Chiffres mis en vedette : une valeur seule qui porte la page. */
  --t-24: 24px; --t-27: 27px; --t-30: 30px; --t-40: 40px; --t-46: 46px; --t-68: 68px; --t-82: 82px;

  /* Rythme */
  --gouttiere: 14px;
  --largeur-max: 1240px;
}

html[data-theme="sombre"] {
  color-scheme: dark;

  --fond-page:      #14130F;
  --fond-voute:     radial-gradient(120% 90% at 12% -10%, #26241E 0%, #1A1815 45%, #100F0D 100%);
  --surface:        #211F1B;
  --surface-douce:  #1A1815;
  --surface-haute:  #2A2723;
  --surface-creuse: rgba(255, 255, 255, 0.06);
  --surface-survol: #2A2723;

  --texte:        #F3F0EA;
  --texte-doux:   rgba(243, 240, 234, 0.62);
  --texte-faible: rgba(243, 240, 234, 0.42);

  --trait:      rgba(255, 255, 255, 0.10);
  --trait-fort: rgba(255, 255, 255, 0.20);
  --ombre-1: 0 1px 2px rgba(0,0,0,.30);
  --ombre-2: 0 2px 8px rgba(0,0,0,.35), 0 14px 32px rgba(0,0,0,.35);
  --ombre-3: 0 10px 26px rgba(0,0,0,.45), 0 36px 72px rgba(0,0,0,.55);

  --accent:      #63C6A2;
  --accent-fort: #7BD5B4;
  --accent-doux: rgba(99, 198, 162, 0.16);
  --accent-contraste: #10281F;
  --danger:      #E58A70;
  --danger-doux: rgba(229, 138, 112, 0.16);
  --succes:      #63C6A2;
  --succes-contraste: #10281F;
  --danger-contraste: #2A100A;
  --alerte:      #E0B057;
  --alerte-doux: rgba(224, 176, 87, 0.20);
  --clarte-ressenti: 68%;   /* sur fond sombre, il faut éclaircir */

  --cat-volets:    #7FAAE0;  --cat-volets-fond:    rgba(127, 170, 224, 0.16);
  --cat-eclairage: #F5CF4B;  --cat-eclairage-fond: rgba(245, 207, 75, 0.18);
  --cat-energie:   #AE97F0;  --cat-energie-fond:   rgba(174, 151, 240, 0.16);
  --cat-vehicule:  #63C6A2;  --cat-vehicule-fond:  rgba(99, 198, 162, 0.16);
  --cat-meteo:     #6FC6D8;  --cat-meteo-fond:     rgba(111, 198, 216, 0.16);
  --meteo-soleil: #F2C744;  --meteo-nuage: #9AA4AE;
  --meteo-nuage-fonce: #C2CBD4;  --meteo-pluie: #62A8E6;
  --meteo-neige: #FFFFFF;
  --cat-securite:  #E58A70;  --cat-securite-fond:  rgba(229, 138, 112, 0.16);
  --cat-chauffage: #E8A06E;  --cat-chauffage-fond: rgba(232, 160, 110, 0.18);
  --cat-autres:    #ACA69C;  --cat-autres-fond:    rgba(172, 166, 156, 0.16);
  --cat-air:       #6CBCEF;  --cat-air-fond:       rgba(108, 188, 239, 0.16);
  --cat-orange:    #E9A55E;  --cat-orange-fond:    rgba(233, 165, 94, 0.17);
  --cat-rose:      #F08CAE;  --cat-rose-fond:      rgba(240, 140, 174, 0.16);
  --cat-prune:     #D68FDB;  --cat-prune-fond:     rgba(214, 143, 219, 0.16);
  --cat-indigo:    #939BEF;  --cat-indigo-fond:    rgba(147, 155, 239, 0.16);
  --cat-vert:      #7FCB86;  --cat-vert-fond:      rgba(127, 203, 134, 0.16);
  --cat-olive:     #B4CE63;  --cat-olive-fond:     rgba(180, 206, 99, 0.17);
  --cat-ardoise:   #9BB5C4;  --cat-ardoise-fond:   rgba(155, 181, 196, 0.16);

  --flux-conso: #E5B75A;  --flux-conso-fond: rgba(229, 183, 90, 0.18);
  --flux-recu:  #63C6A2;  --flux-recu-fond:  rgba(99, 198, 162, 0.18);
}

/* ============================================================
   BASE
   ============================================================ */
* { box-sizing: border-box; }
html, body {
  margin: 0; padding: 0; height: 100%;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior: none;
}
@supports (height: 100dvh) { html, body { height: 100dvh; } }
@supports (height: 100lvh) { html, body { height: 100lvh; } }
/* Le fond du document, et non celui du corps, est celui qu'iOS
   utilise pour peindre ce qui déborde de la zone de rendu (barre
   d'accueil de l'iPhone/iPad). En lui donnant la voûte, une éventuelle
   bande résiduelle se confond avec la page. */
html { background: var(--fond-voute); background-attachment: fixed; }
:root {
  /* Hauteur réservée en haut de l'écran (encoche, barre d'état).
     Tout ce qui se positionne par rapport au haut de l'écran s'en
     sert, pour que la barre du haut, l'horloge et les pages
     descendent ensemble et ne se chevauchent jamais. */
  --haut-sur: env(safe-area-inset-top);
  /* Position commune AUX DEUX barres flottantes : le menu principal
     (Favoris, Pièces, Catégories, Graphiques, Actualiser) et la barre du
     mode réglage. Elles descendent en bas de l'écran sans en toucher le
     bord, et restent au-dessus de la barre d'accueil iOS pour ne pas lui
     céder les appuis. */
  --bas-flottant: max(10px, calc(env(safe-area-inset-bottom) - 12px));
}
body {
  background: var(--fond-voute);
  background-attachment: fixed;
  color: var(--texte);
  transition: background-color var(--lent) var(--courbe), color var(--lent) var(--courbe);
  /* Ni padding haut ni padding bas : toutes les zones (barre du haut,
     accueil, pages, barres flottantes) se positionnent elles-mêmes par
     rapport à l'écran. Un padding ici compterait la zone sûre deux fois
     et réservait au passage une bande inerte au ras de l'écran. */
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}
/* Image de fond optionnelle : posée sous un voile qui garantit la
   lisibilité du texte quel que soit le cliché choisi. */
body.avec-image::before, body.avec-image::after {
  content: ""; position: fixed; z-index: 0;
  top: 0; left: 0; right: 0; bottom: 0;
  height: 100vh;
  height: 100lvh;   }
body.avec-image::before {
  background-image: var(--image-fond);
  background-size: cover; background-position: var(--position-fond, center);
}
/* Fond uni choisi dans le nuancier : il remplace la voûte du thème
   clair. Le thème sombre garde la sienne, une teinte pastel n'y a pas
   sa place. */
html.fond-uni-choisi:not([data-theme="sombre"]) {
  --fond-page: var(--fond-uni-choisi);
  --fond-voute: var(--fond-uni-choisi);
}
/* Le voile est réglable (Réglages → Image de fond → « Voile ») : à 0 la
   photo est nue, à 90 % elle s'efface sous le fond du thème. Un peu plus
   dense vers le bas, là où les tuiles sont les plus serrées. */
body.avec-image::after {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--fond-page) calc(var(--voile-fond, .25) * 100%), transparent) 0%,
    color-mix(in srgb, var(--fond-page) calc(var(--voile-fond, .25) * 100% + 10%), transparent) 100%);
}
button, input, select, textarea { font-family: inherit; }
button { color: inherit; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.masque { display: none !important; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--trait-fort); border-radius: 999px; border: 3px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-track { background: transparent; }

/* ============================================================
   BARRE DU HAUT
   ============================================================ */
.barre-haut {
  /* « fixed » et non « absolute » : le repère est alors l'écran
     visible. Avec « absolute », c'est le bloc conteneur initial qui
     sert de repère, et iOS le dimensionne parfois plus court que
     l'écran -- d'où une bande morte en bas et une pilule de menu qui
     ne descendait pas jusqu'en bas. La barre du mode réglage, elle,
     était déjà en « fixed » : elle, elle touchait le bas. */
  position: fixed; top: 0; left: 0; right: 0; z-index: 20;
  display: flex; align-items: center; gap: 12px;
  padding: 6px 26px;
  padding-top: calc(6px + var(--haut-sur));
  /* Sans le logo, la barre n'est plus qu'une paire de boutons posés en
     haut à droite : elle ne doit pas intercepter les appuis sur le
     contenu qui passe maintenant dessous. */
  pointer-events: none;
}
/* Le nom de la maison et son icône ne portaient aucune information :
   on est chez soi, on le sait. La place gagnée sert à faire remonter le
   contenu de toutes les pages d'une bonne cinquantaine de pixels. Les
   éléments restent dans la page (du code s'y réfère), simplement
   invisibles. */
.logo { display: none; }
.logo-rond {
  width: 42px; height: 42px; border-radius: var(--r-sm); flex-shrink: 0;
  background: var(--surface); border: 1px solid var(--trait);
  box-shadow: var(--ombre-1);
  display: flex; align-items: center; justify-content: center;
  color: var(--texte); cursor: pointer;
  transition: background var(--vite), transform var(--vite), border-color var(--vite);
}
.logo-rond:hover { background: var(--surface-survol); border-color: var(--trait-fort); }
.logo-rond:active { transform: scale(.94); }
.logo-texte {
  font-size: var(--t-17); font-weight: 700; letter-spacing: .08em;
  color: var(--texte); text-transform: uppercase; white-space: nowrap;
}
.icones-haut { display: flex; gap: 8px; margin-left: auto; pointer-events: auto; }
/* Les alertes des tuiles, à gauche des deux boutons : une pastille par
   appareil dont la règle est remplie, et un rond « +N » quand la place
   manque. */
.alertes-haut { display: flex; align-items: center; gap: 6px; margin-left: auto; pointer-events: auto; flex-wrap: nowrap; }
.alertes-haut[hidden] { display: none; }
.alertes-haut:not([hidden]) + .icones-haut { margin-left: 0; }
.alerte-haut {
  display: inline-flex; align-items: center; gap: 6px; height: 34px; padding: 0 10px 0 5px;
  border-radius: var(--r-pilule); border: 1px solid var(--danger); background: var(--surface);
  box-shadow: var(--ombre-1); color: var(--texte); font: inherit; font-size: var(--t-12); cursor: pointer;
  max-width: 240px; white-space: nowrap;
}
.alerte-haut .chip-icone { width: 24px; height: 24px; border-radius: 7px; flex: none; background: var(--danger-doux, var(--surface-creuse)); color: var(--danger); }
.alerte-haut .chip-icone svg { width: 14px; height: 14px; }
.alerte-haut-nom { font-weight: 650; overflow: hidden; text-overflow: ellipsis; }
.alerte-haut-etat { color: var(--danger); font-weight: 650; overflow: hidden; text-overflow: ellipsis; }
.alerte-haut:active { transform: scale(.97); }
.alertes-plus {
  flex: none; width: 34px; height: 34px; border-radius: 50%; border: none;
  background: var(--danger); color: #FFF; font: inherit; font-size: var(--t-13); font-weight: 750;
  box-shadow: var(--ombre-1); cursor: pointer;
}
.menu-alertes { z-index: 62; }
/* La tuile d'une alerte, par-dessus la page : centrée sous la barre du
   haut, avec sa croix. Elle prend la hauteur de son contenu. */
.tuile-alerte {
  position: fixed; z-index: 63; top: calc(var(--haut-sur) + 62px); left: 50%; transform: translateX(-50%);
  width: min(330px, calc(100vw - 32px));
}
.tuile-alerte[hidden] { display: none; }
.tuile-alerte .tuile { width: 100%; height: auto; min-height: 136px; box-shadow: var(--ombre-3); }
.tuile-alerte .poignee-redim { display: none; }
.fermer-tuile-alerte {
  position: absolute; top: -12px; right: -12px; width: 30px; height: 30px; border-radius: 50%;
  border: 1px solid var(--trait); background: var(--surface); color: var(--texte); box-shadow: var(--ombre-2);
  font-size: var(--t-17); line-height: 1; cursor: pointer; z-index: 2;
}
.retour-alertes {
  position: fixed; z-index: 30; top: calc(var(--haut-sur) + 58px); left: 50%; transform: translateX(-50%);
  padding: 8px 14px; border-radius: var(--r-pilule); border: 1px solid var(--trait);
  background: var(--surface); box-shadow: var(--ombre-2); color: var(--texte);
  font: inherit; font-size: var(--t-12); font-weight: 650; cursor: pointer;
}
.retour-alertes[hidden] { display: none; }
@keyframes signaler-tuile { 0%, 100% { box-shadow: 0 0 0 0 transparent; } 30% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 55%, transparent); } }
.tuile.tuile-signalee { animation: signaler-tuile 1.3s ease-out 2; }
/* La règle d'alerte, sur les tuiles en mode réglage : en bas à gauche,
   sans gêner la poignée. */
/* Le bouton « Affichage conditionnel » : en bleu, en plus gros, pour
   qu'on le voie du premier coup d'œil (26/09/2026, demande de Fred). */
/* Un surlignage au stabilo (26/09/2026, demande de Fred) : bleu clair
   translucide aux bords diffus, et le texte garde la couleur normale de
   la tuile -- lisible en thème clair comme en sombre. */
body.en-edition .tuile .condition-pastille {
  left: 8px; right: 30px; bottom: 6px; z-index: 3;
  background: var(--stabilo); border: 1px solid transparent; border-radius: 8px;
  padding: 5px 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--texte); font-size: var(--t-12); font-weight: 650; letter-spacing: 0;
  box-shadow: 0 0 0 3px var(--stabilo-halo), 0 0 12px var(--stabilo-halo);
}
body.en-edition .tuile .condition-pastille:hover { background: var(--stabilo-fort); }
/* Sans condition : plus de stabilo, un simple cadre discret et le texte
   adouci ; l'œil barré dit le reste. */
body.en-edition .tuile .condition-pastille.sans-regle {
  background: transparent; border-color: var(--trait); box-shadow: none;
  color: var(--texte-doux); font-weight: 600;
}
body.en-edition .tuile .condition-pastille.sans-regle:hover { background: var(--stabilo-doux); }
.condition-pastille .cp-oeil { width: 14px; height: 14px; vertical-align: -3px; margin-right: 5px; flex: none; }
/* Les titres de page passent maintenant à hauteur des deux boutons :
   on leur réserve la largeur qu'ils occupent. */
.page-titre, .horloge-interieur { padding-right: 104px; }
.icone-ronde {
  width: 42px; height: 42px; border-radius: var(--r-sm);
  background: var(--surface); border: 1px solid var(--trait);
  box-shadow: var(--ombre-1);
  display: flex; align-items: center; justify-content: center;
  color: var(--texte); cursor: pointer;
  transition: background var(--vite), color var(--vite), border-color var(--vite), transform var(--vite);
}
.icone-ronde:hover { background: var(--surface-survol); border-color: var(--trait-fort); }
.icone-ronde:active { transform: scale(.94); }
.icone-ronde.actif {
  background: var(--accent); border-color: var(--accent);
  color: var(--accent-contraste); box-shadow: var(--ombre-2);
}

/* ============================================================
   ACCUEIL : entête horloge + bandeau de résumé
   ============================================================ */
.horloge-zone { position: static; padding: 0; pointer-events: none; }
.horloge-interieur {
  max-width: var(--largeur-max); margin: 0 auto;
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 28px; flex-wrap: wrap;
}
.horloge-bloc { text-align: left; }
.horloge-date {
  font-size: var(--t-13); font-weight: 600; letter-spacing: .04em;
  color: var(--texte-doux); margin-bottom: 2px;
}
.horloge-heure {
  font-size: var(--t-68); font-weight: 700; letter-spacing: -0.035em; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--texte);
}

/* Bandeau de résumé : l'état de la maison en une ligne, sans clic. */
.bandeau-resume {
  display: flex; gap: 10px; flex-wrap: wrap;
  pointer-events: auto;
}
.puce-resume {
  display: flex; align-items: center; gap: 10px;
  background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r-md); padding: 10px 14px 10px 11px;
  box-shadow: var(--ombre-1); min-width: 132px;
  transition: transform var(--vite), box-shadow var(--vite), border-color var(--vite);
}
.puce-resume:hover { box-shadow: var(--ombre-2); border-color: var(--trait-fort); }
.puce-resume .chip-icone { width: 32px; height: 32px; border-radius: 10px; }
.puce-resume .chip-icone svg { width: 17px; height: 17px; }
.puce-resume-textes { display: flex; flex-direction: column; min-width: 0; }
.puce-resume-valeur {
  font-size: var(--t-17); font-weight: 700; line-height: 1.15;
  font-variant-numeric: tabular-nums; color: var(--texte);
}
.puce-resume-libelle {
  font-size: var(--t-11); font-weight: 500; color: var(--texte-doux);
  letter-spacing: .02em; white-space: nowrap;
}
.puce-resume.alerte { border-color: var(--danger); background: var(--danger-doux); }
.puce-resume.alerte .puce-resume-valeur { color: var(--danger); }
.puce-resume-sigle {
  display: inline-block; margin-right: 6px; padding: 1px 5px;
  border-radius: 5px; font-size: var(--t-10); font-weight: 700;
  letter-spacing: .04em; vertical-align: middle;
  background: var(--surface-creuse); color: var(--texte-doux);
}
/* Une tuile porte sa teinte dans deux variables, et rien d'autre ne la
   connaît. « data-cat » donne la couleur d'usine de la catégorie ;
   « data-teinte », posé seulement quand quelqu'un a choisi une couleur,
   passe après dans la feuille et l'emporte donc. Ajouter une couleur à
   la palette, c'est une ligne ici -- pas une par endroit coloré. */
[data-cat] { --cat: var(--cat-autres); --cat-fond: var(--cat-autres-fond); }
[data-cat="volets"]    { --cat: var(--cat-volets);    --cat-fond: var(--cat-volets-fond); }
[data-cat="eclairage"] { --cat: var(--cat-eclairage); --cat-fond: var(--cat-eclairage-fond); }
[data-cat="energie"]   { --cat: var(--cat-energie);   --cat-fond: var(--cat-energie-fond); }
[data-cat="vehicule"]  { --cat: var(--cat-vehicule);  --cat-fond: var(--cat-vehicule-fond); }
[data-cat="meteo"]     { --cat: var(--cat-meteo);     --cat-fond: var(--cat-meteo-fond); }
[data-cat="securite"]  { --cat: var(--cat-securite);  --cat-fond: var(--cat-securite-fond); }
[data-cat="chauffage"] { --cat: var(--cat-chauffage); --cat-fond: var(--cat-chauffage-fond); }
[data-cat="air"]       { --cat: var(--cat-air);       --cat-fond: var(--cat-air-fond); }
[data-cat="autres"]    { --cat: var(--cat-autres);    --cat-fond: var(--cat-autres-fond); }
/* Les tuiles d'étiquette (page Catégories, 27/09/2026) : une teinte à
   elles, prise dans la palette, pour ne pas se confondre avec « autres ». */
[data-cat="etiquette"] { --cat: var(--cat-indigo);    --cat-fond: var(--cat-indigo-fond); }
[data-teinte="volets"]    { --cat: var(--cat-volets);    --cat-fond: var(--cat-volets-fond); }
[data-teinte="eclairage"] { --cat: var(--cat-eclairage); --cat-fond: var(--cat-eclairage-fond); }
[data-teinte="energie"]   { --cat: var(--cat-energie);   --cat-fond: var(--cat-energie-fond); }
[data-teinte="chauffage"] { --cat: var(--cat-chauffage); --cat-fond: var(--cat-chauffage-fond); }
[data-teinte="vehicule"]  { --cat: var(--cat-vehicule);  --cat-fond: var(--cat-vehicule-fond); }
[data-teinte="meteo"]     { --cat: var(--cat-meteo);     --cat-fond: var(--cat-meteo-fond); }
[data-teinte="securite"]  { --cat: var(--cat-securite);  --cat-fond: var(--cat-securite-fond); }
[data-teinte="air"]       { --cat: var(--cat-air);       --cat-fond: var(--cat-air-fond); }
[data-teinte="autres"]    { --cat: var(--cat-autres);    --cat-fond: var(--cat-autres-fond); }
[data-teinte="orange"]    { --cat: var(--cat-orange);    --cat-fond: var(--cat-orange-fond); }
[data-teinte="rose"]      { --cat: var(--cat-rose);      --cat-fond: var(--cat-rose-fond); }
[data-teinte="prune"]     { --cat: var(--cat-prune);     --cat-fond: var(--cat-prune-fond); }
[data-teinte="indigo"]    { --cat: var(--cat-indigo);    --cat-fond: var(--cat-indigo-fond); }
[data-teinte="vert"]      { --cat: var(--cat-vert);      --cat-fond: var(--cat-vert-fond); }
[data-teinte="olive"]     { --cat: var(--cat-olive);     --cat-fond: var(--cat-olive-fond); }
[data-teinte="ardoise"]   { --cat: var(--cat-ardoise);   --cat-fond: var(--cat-ardoise-fond); }

[data-cat="meteo"]    .puce-resume-sigle,
[data-cat="energie"]  .puce-resume-sigle,
[data-cat="vehicule"] .puce-resume-sigle,
[data-cat="volets"]   .puce-resume-sigle { background: var(--cat-fond); color: var(--cat); }
[data-teinte] .puce-resume-sigle { background: var(--cat-fond); color: var(--cat); }

/* ============================================================
   PASTILLE ICÔNE — le repère couleur commun à tout le tableau
   ============================================================ */
.chip-icone {
  width: 30px; height: 30px; border-radius: 9px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--cat-autres-fond); color: var(--cat-autres);
}
/* Les symboles Loxone sont plus détaillés et d'un trait plus fin que
   des icônes dessinées à gros traits : ils ont besoin d'un peu plus de
   place pour rester lisibles. */
.chip-icone svg { width: 17px; height: 17px; display: block; }
[data-cat] .chip-icone, [data-teinte] .chip-icone { background: var(--cat-fond); color: var(--cat); }
/* Une pièce reste neutre tant que personne ne lui a donné de couleur :
   c'est un lieu, pas une famille d'appareils. */
[data-cat="piece"]:not([data-teinte]) .chip-icone { background: var(--surface-creuse); color: var(--texte); }
[data-cat="piece"]     .chip-icone svg { width: 24px; height: 24px; }

/* L'accueil est une colonne qui défile : horloge, résumé, puis la
   grille de pastilles. Même structure sur les trois supports. */
.accueil {
  position: fixed; inset: 0; z-index: 3;
  display: flex; flex-direction: column; gap: 22px;
  padding: calc(16px + var(--haut-sur)) 26px calc(84px + env(safe-area-inset-bottom));
  overflow-y: auto; -webkit-overflow-scrolling: touch;
}
.zone-cartes { position: static; }
/* En mode réglage, les boutons flottants (Annuler / Enregistrer / Sortir)
   couvrent le bas de l'écran, et le mode réglage fait justement
   apparaître des pastilles en plus : la dernière rangée se retrouvait
   sous eux, sans moyen de la dégager. La réserve est posée sur la grille
   elle-même et non sur la page : la marge intérieure de fin d'un
   conteneur défilant n'est pas comptée dans sa hauteur de défilement, un
   travers de longue date des navigateurs. */
body.en-edition .zone-cartes {
  padding-bottom: calc(76px + env(safe-area-inset-bottom));
}
/* Et surtout : la grille ne doit pas se laisser comprimer. En tant
   qu'élément flexible d'une page à hauteur fixe, elle était écrasée
   jusqu'à tenir dans l'écran -- ses pastilles débordaient alors par le
   bas sans que la page devienne défilable, donc sans aucun moyen de les
   atteindre. Elle garde maintenant sa hauteur, et c'est la page qui
   défile. */
.zone-cartes { flex: none; }

/* ============================================================
   GRILLE AIMANTÉE
   Un seul système de mise en page pour l'accueil et les pages
   internes : chaque pastille occupe un rectangle entier de cases.
   Le nombre de colonnes suit la largeur disponible, la hauteur
   d'une case est fixe -- c'est ce qui rend deux pastilles de même
   taille rigoureusement identiques.
   ============================================================ */
.grille-pastilles {
  --colonnes: 40;
  --hauteur-case: 25.6px;
  --marge-case: 6px;
  display: grid;
  grid-template-columns: repeat(var(--colonnes), minmax(0, 1fr));
  grid-auto-rows: var(--hauteur-case);
  gap: 0;
  width: 100%; max-width: var(--largeur-max); margin: 0 auto;
  position: relative; align-content: start;
}
/* La grille étant très fine, l'espace entre deux pastilles ne peut plus
   être une gouttière de grille : il devient une marge interne à chaque
   pastille. Le résultat visuel est identique, mais le pas de réglage
   n'est plus lié à l'espacement. */
.grille-pastilles > .carte,
.grille-pastilles > .tuile,
.grille-pastilles > .fantome-grille { margin: var(--marge-case); }
/* En mode édition, quelques rangées vides en réserve : on peut poser
   une pastille plus bas que le contenu actuel. */
body.en-edition .grille-pastilles { min-height: var(--reserve, 0px); }

.fantome-grille {
  border-radius: var(--r-lg); pointer-events: none;
  background: var(--accent-doux);
  border: 2px dashed var(--accent);
  z-index: 1;
}

.carte.deplacement, .tuile.deplacement {
  animation: none; z-index: 60; opacity: .96; cursor: grabbing;
  box-shadow: var(--ombre-3); pointer-events: none;
}

.carte {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--trait);
  border-radius: var(--r-lg);
  box-shadow: var(--ombre-1);
  padding: 12px 15px; color: var(--texte);
  display: flex; flex-direction: column; justify-content: center; cursor: pointer;
  transition: box-shadow var(--moyen), border-color var(--moyen), transform var(--vite), background var(--vite);
  user-select: none;
}
.carte:hover { box-shadow: var(--ombre-2); border-color: var(--trait-fort); }
.carte:active { transform: scale(.985); }
/* Trois colonnes : l'icône, le nom, et une cale de la largeur de
   l'icône. Sans cette cale le nom serait centré sur la place restante,
   donc décalé vers la droite -- pas centré dans le cadre. */
.carte-entete, .tuile-haut {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; gap: 8px; flex-shrink: 0;
}
/* Cale qui compense l'icône pour que le nom tombe au milieu du cadre.
   Sur un cadre étroit elle est sacrifiée : mieux vaut un nom lisible
   légèrement décalé qu'un nom centré et minuscule. */
.cale-entete { width: var(--cale-entete, 30px); height: 1px; }
.carte-nom, .tuile-nom {
  text-align: center; min-width: 0;
  font-size: calc(var(--taille-nom, var(--t-21)) * var(--echelle-nom, 1));
  font-weight: 700; line-height: 1.15;
  letter-spacing: -0.015em; overflow-wrap: anywhere;
}
/* Un nom trop long est d'abord rétréci pour tenir sur une ligne ;
   la classe est retirée quand même le plus petit corps n'y suffit pas,
   et le nom revient alors à la ligne. */
.carte-nom.nom-une-ligne, .tuile-nom.nom-une-ligne {
  white-space: nowrap; overflow: hidden;
}
/* La pièce se range en bas à droite : l'information est utile mais
   secondaire, elle ne doit pas concurrencer la valeur. */
.carte-pied, .tuile-pied {
  margin-top: auto; padding-top: 4px; text-align: right; flex-shrink: 0;
  font-size: calc(var(--t-11) * var(--echelle, 1)); font-weight: 600;
  color: var(--texte-doux); letter-spacing: .03em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Le texte occupe toute la place restante et s'y centre dans les deux
   sens. Sa taille est ajustée après coup par ajusterTextes() : une
   règle CSS ne peut pas savoir si « Véhicule connecté » tient dans une
   pastille d'une case de large. */
.carte-corps > *, .tuile-corps > * { flex-shrink: 0; }
.carte-corps, .tuile-corps {
  flex: 0 1 auto; min-height: 0; min-width: 0; overflow: hidden;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; text-align: center;
  padding-top: 12px;
}
.carte-valeur {
  font-size: calc(var(--t-21) * var(--echelle, 1)); font-weight: 650;
  font-variant-numeric: tabular-nums; line-height: 1.15;
  letter-spacing: -0.015em; overflow-wrap: anywhere; max-width: 100%;
}
.carte-soustitre {
  font-size: calc(var(--t-13) * var(--echelle, 1)); font-weight: 500;
  color: var(--texte-doux); margin-top: 2px; line-height: 1.25;
  overflow-wrap: anywhere; max-width: 100%;
}

/* ============================================================
   TUILES (pages Pièces / Catégories / détail)
   ============================================================ */
.page-liste {
  position: fixed; inset: 0; z-index: 4;
  padding: calc(16px + var(--haut-sur)) 26px calc(84px + env(safe-area-inset-bottom)); overflow-y: auto; display: none;
}
.page-liste.visible { display: block; }
.page-titre {
  max-width: var(--largeur-max); margin: 0 auto 20px;
  display: flex; align-items: center; gap: 12px;
}
.page-titre h1 {
  font-size: var(--t-30); margin: 0; font-weight: 700; letter-spacing: -0.02em;
}
.bouton-retour {
  width: 38px; height: 38px; border-radius: var(--r-sm); flex-shrink: 0;
  background: var(--surface); border: 1px solid var(--trait);
  box-shadow: var(--ombre-1); color: var(--texte); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background var(--vite), transform var(--vite);
}
.bouton-retour:hover { background: var(--surface-survol); }
.bouton-retour:active { transform: scale(.94); }

.tuile {
  position: relative;
  background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r-md); padding: 12px 14px;
  color: var(--texte); cursor: pointer; text-align: left; width: 100%;
  box-shadow: var(--ombre-1);
  display: flex; flex-direction: column; justify-content: center; min-height: 0;
  transition: box-shadow var(--moyen), border-color var(--moyen), transform var(--vite);
}
.tuile:hover { box-shadow: var(--ombre-2); border-color: var(--trait-fort); }
.tuile:active { transform: scale(.985); }

/* ------------------------------------------------------------
   VALEURS PAS ENCORE LUES
   Tant qu'un appareil n'a pas répondu, sa valeur est « … ». Plutôt que
   trois points, une barre qui miroite : la place est prise, la mesure
   arrive. Et les dernières valeurs connues, restaurées au démarrage
   avant la première lecture, sont ternies jusqu'à confirmation.
   ------------------------------------------------------------ */
.carte-valeur.inconnue, .tuile-etat.inconnue, .puce-resume-valeur.inconnue, .meteo-capteur-valeur.inconnue {
  color: transparent !important; position: relative;
}
.carte-valeur.inconnue::after, .tuile-etat.inconnue::after, .puce-resume-valeur.inconnue::after,
.meteo-capteur-valeur.inconnue::after {
  content: ""; position: absolute; left: 0; top: .18em; height: .72em; width: 3em; max-width: 100%;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--surface-creuse) 20%, var(--trait) 50%, var(--surface-creuse) 80%);
  background-size: 200% 100%;
  animation: miroitement 1.6s linear infinite;
}
@keyframes miroitement { from { background-position: 150% 0; } to { background-position: -150% 0; } }
body.valeurs-perimees .carte-valeur, body.valeurs-perimees .tuile-etat,
body.valeurs-perimees .puce-resume-valeur { opacity: .5; transition: opacity var(--lent); }

.tuile-etat {
  font-size: calc(var(--t-21) * var(--echelle, 1)); font-weight: 650;
  font-variant-numeric: tabular-nums; letter-spacing: -0.01em;
  line-height: 1.15; overflow-wrap: anywhere; max-width: 100%;
}

/* ------------------------------------------------------------
   CHAUFFAGE
   La tuile d'une pièce dit deux chiffres -- ce qu'il fait, ce qu'on
   veut -- et rien ne doit les confondre : la consigne est en couleur
   d'accent, la température mesurée garde la taille des autres valeurs.
   ------------------------------------------------------------ */
.chauffage-apercu { display: flex; flex-direction: column; gap: 4px; max-width: 100%; }
.tuile.sans-icone .chip-icone { display: none; }

/* La couronne de réglage d'une pièce : un anneau ouvert par le bas, une
   poignée qu'on fait glisser du pouce. Sa couleur suit la consigne --
   bleu en dessous de 17°, rouge au-delà de 23°. Le petit repère plein
   marque la température qu'il fait vraiment : on voit d'un coup d'œil
   si la pièce est en retard sur ce qu'on lui demande. */
/* La couronne EST la tuile : elle prend toute la place que le nom et
   les deux touches lui laissent, et c'est elle qui grandit quand on
   agrandit la tuile. Rien d'autre ne doit gagner de hauteur. */
.jauge-chauffage {
  position: relative; align-self: center;
  flex: 1 1 auto; min-height: 76px; max-height: 100%; max-width: 100%;
  aspect-ratio: 1; margin: 0 auto;
  touch-action: none;                 /* le glissement règle, il ne fait pas défiler */
  container-type: inline-size;        /* le chiffre du centre suit la taille de la couronne */
}
.tuile-chauffage .chauffage-apercu {
  flex: 1 1 auto; min-height: 0; width: 100%; gap: 5px;
  display: flex; flex-direction: column; align-items: center; justify-content: stretch;
}
/* Le nom d'une pièce chauffée se lit en passant : il ne vole pas la
   place de la couronne, qui, elle, se manipule. */
.tuile-chauffage { padding: 8px 10px; }
.tuile-chauffage .tuile-nom {
  font-size: calc(var(--t-13) * var(--echelle-nom, 1)); font-weight: 650;
}
.tuile-chauffage .tuile-haut { flex: 0 0 auto; }
.tuile-chauffage .cale-entete { display: none; }
.tuile-chauffage .tuile-corps { padding-top: 2px; flex: 1 1 auto; justify-content: stretch; }
.jauge-svg { width: 100%; height: 100%; display: block; overflow: visible; cursor: grab; }
.jauge-chauffage.en-cours .jauge-svg { cursor: grabbing; }
.jauge-fond {
  fill: none; stroke: var(--surface-creuse); stroke-width: 11.5; stroke-linecap: round;
}
.jauge-actif {
  fill: none; stroke: var(--thermo); stroke-width: 11.5; stroke-linecap: round;
  transition: stroke var(--vite);
}
/* Le point plein marque la température de la pièce, au bout de l'arc.
   Son liséré clair le détache de l'arc, et le laisse lisible quand il
   vient se loger dans la poignée. */
.jauge-point {
  fill: var(--thermo); stroke: var(--surface); stroke-width: 1.6;
  transition: fill var(--vite);
}
/* La poignée marque la consigne : grise, pour ne pas se confondre avec
   l'arc, et creuse -- un fond plein aurait coupé la couleur en deux
   quand la pièce dépasse sa consigne et que l'arc la traverse. */
.jauge-poignee {
  fill: none; stroke: #5A5650; stroke-width: 2.6;
}
html[data-theme="sombre"] .jauge-poignee { stroke: #9A948B; }
.jauge-chauffage.en-cours .jauge-poignee { stroke-width: 3.6; }
/* La consigne s'écrit contre sa poignée, dehors : au centre, elle
   disputait la place à la mesure. */
.jauge-etiquette {
  fill: #5A5650; font-size: 11px; font-weight: 750; text-anchor: middle;
  dominant-baseline: middle; font-variant-numeric: tabular-nums;
  paint-order: stroke; stroke: var(--surface); stroke-width: 3; stroke-linejoin: round;
}
html[data-theme="sombre"] .jauge-etiquette { fill: #B9B2A7; }
.jauge-chauffage.en-cours .jauge-etiquette { fill: var(--texte); font-size: 13px; }
.jauge-chauffage.chauffe .jauge-actif {
  filter: drop-shadow(0 0 4px color-mix(in srgb, var(--thermo) 55%, transparent));
}
.jauge-centre {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 2px; pointer-events: none;
  /* les touches occupent le bas de l'anneau : le texte remonte d'autant */
  padding-bottom: 20%;
}
/* Au centre : la température de la pièce en grand, la consigne dessous. */
.jauge-mesuree { display: flex; align-items: flex-start; gap: 1px; color: var(--texte); }
/* Tout le centre se mesure sur la couronne : sur une tuile basse elle
   descend à 84 px, et des tailles fixes y auraient débordé du cercle. */
.jauge-mesuree b {
  font-size: clamp(16px, 22cqw, 31px); font-weight: 750; line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
}
.jauge-mesuree span { font-size: clamp(8px, 9cqw, 12px); font-weight: 650; margin-top: 2px; }
/* Pendant le glissement, c'est la consigne qu'on règle : son étiquette
   grossit, et la mesure du centre s'efface un instant. */
.jauge-chauffage.en-cours .jauge-mesuree { opacity: .5; }
.jauge-muette {
  font-size: clamp(8px, 9cqw, 11px); color: var(--danger);
  font-weight: 650; white-space: nowrap;
}

.touche-volet.actif { border-color: var(--cat, var(--accent)); color: var(--cat, var(--accent)); }
/* Deux touches basses, sur une seule ligne : l'icône puis le mot. Elles
   ne servent qu'à changer de mode -- le réglage, lui, est dans la
   couronne, et c'est à elle que revient la hauteur. */
/* Les touches tiennent dans l'ouverture du bas de l'anneau : rien ne
   rogne alors la hauteur de la couronne. */
.touches-chauffage {
  position: absolute; left: 50%; bottom: 0; transform: translateX(-50%);
  width: 78%; margin: 0; gap: 5px; flex: 0 0 auto;
}
.touches-chauffage .touche-volet {
  display: flex; flex-direction: row; align-items: center; justify-content: center;
  gap: 4px; padding: 0 5px; height: 26px; min-height: 0;
  color: var(--texte-doux); border-radius: 8px; background: var(--surface);
}
.touches-chauffage .touche-volet svg { width: 13px; height: 13px; flex: 0 0 auto; }
.touches-chauffage .touche-volet em {
  font-style: normal; font-size: var(--t-10); font-weight: 650;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.touches-chauffage .touche-volet em {
  font-style: normal; font-size: var(--t-10); font-weight: 650; letter-spacing: .01em;
}
/* La durée d'une consigne manuelle : deux touches et le temps qui reste. */
.chauffage-duree {
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  margin-top: 0; width: 100%; flex: 0 0 auto;
}
.chauffage-duree .duree-texte {
  flex: 1 1 auto; text-align: center; font-size: var(--t-11);
  color: var(--texte-doux); font-variant-numeric: tabular-nums;
}
.touche-duree {
  flex: 0 0 auto; width: 28px; height: 22px; border-radius: 7px;
  border: 1px solid var(--trait); background: var(--surface-creuse);
  color: var(--texte); font-size: var(--t-15); font-weight: 700; line-height: 1;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.touche-duree:active { background: var(--trait); }
.chauffage-mode {
  padding: 1px 6px; border-radius: 999px; font-size: var(--t-10); font-weight: 650;
  background: var(--surface-creuse); color: var(--texte-doux); white-space: nowrap;
}
.chauffage-mode.manuel { background: var(--cat-fond, var(--surface-creuse)); color: var(--cat, var(--texte)); }
.chauffage-mode.arret { background: var(--danger-doux); color: var(--danger); }
.chauffage-chauffe {
  font-size: var(--t-10); font-weight: 650; color: var(--succes);
  padding: 1px 6px; border-radius: 999px; background: var(--succes-doux, var(--surface-creuse));
}
.chauffage-details {
  font-size: var(--t-11); color: var(--texte-doux); line-height: 1.3;
  overflow-wrap: anywhere;
}
.touches-chauffage .touche-volet { font-size: var(--t-17); font-weight: 700; }
.touches-chauffage .touche-volet svg { width: 17px; height: 17px; }

/* La fiche : le gros réglage au doigt, moins et plus de part et d'autre. */
.chauffage-reglage {
  display: flex; align-items: center; justify-content: center; gap: 16px;
  margin: 14px 0 6px;
}
.chauffage-cible-geante { text-align: center; min-width: 110px; }
.chauffage-cible-geante > span:first-child {
  display: block; font-size: var(--t-32, 30px); font-weight: 750;
  font-variant-numeric: tabular-nums; line-height: 1.1;
}
.bouton.rond {
  width: 46px; height: 46px; border-radius: 50%; padding: 0;
  font-size: var(--t-21); font-weight: 700; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-creuse); border: 1px solid var(--trait); color: var(--texte);
}
.bouton.rond:active { background: var(--trait); }
.chauffage-boutons { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.chauffage-boutons .bouton { flex: 1 1 140px; }
.chauffage-boutons .bouton.actif {
  border-color: var(--accent); color: var(--accent); font-weight: 650;
}
.tuile-sous {
  font-size: calc(var(--t-13) * var(--echelle, 1)); color: var(--texte-faible);
  margin-top: 2px; line-height: 1.25; overflow-wrap: anywhere; max-width: 100%;
}

/* Pas d'enfoncement de la tuile entière sur une tuile de volet : on y
   appuie sur des commandes, pas sur la tuile. Et surtout, un ancêtre
   transformé devient le référentiel des positions fixes : avec ce
   `scale`, le rail agrandi se retrouvait à l'autre bout de l'écran. */
.tuile.tuile-volets:active { transform: none; }
.tuile.tuile-volets:hover { box-shadow: var(--ombre-1); border-color: var(--trait); }
body.en-edition .tuile.tuile-volets { cursor: grab; }
/* Quatre colonnes, trois rangées : l'icône, le texte, la plume et le
   rail se partagent le haut de la tuile ; les trois gestes prennent
   toute la largeur en bas. Le rail s'arrête donc au-dessus d'eux au lieu
   de leur voler leur colonne de droite. */
.tuile.tuile-volets {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  grid-template-rows: auto 1fr auto;
  column-gap: 10px; align-items: stretch;
  cursor: default;      /* rien à ouvrir : la tuile n'est plus cliquable */
}
.tuile-volets .colonne-gauche {
  grid-column: 2; grid-row: 1 / span 2;
  min-width: 0; display: flex; flex-direction: column; justify-content: center;
}
.tuile-volets .colonne-icone {
  grid-column: 1; grid-row: 1 / span 2;
  display: flex; flex-direction: column; align-items: center; gap: 9px; padding-top: 1px;
}
/* La plume se range en haut, contre le rail : c'est un réglage de
   vitesse, il appartient au curseur plus qu'aux boutons. */
.tuile-volets .touche-volet.silence { grid-column: 3; grid-row: 1; align-self: start; }
.tuile-volets .touches-volet { grid-column: 1 / span 4; grid-row: 3; }
.tuile-volets .rail-place {
  grid-column: 4; grid-row: 1 / span 2; width: 34px;
  margin-left: 10px; margin-right: 6px;
}
/* Le rail se détache du bord. Sa case lui réserve dix pixels de marge à
   gauche et six à droite ; ajoutés à la gouttière de la grille et au
   rembourrage de la tuile, cela fait vingt pixels de chaque côté --
   autant entre lui et la plume qu'entre lui et le bord. */
.tuile-volets .rail-volet { grid-column: 4; grid-row: 1 / span 2; right: 19px; }

/* Le texte cède un peu de corps : la place ainsi rendue va aux trois
   boutons, qui restent des boutons plutôt que des barrettes. */
.tuile-volets .tuile-nom { font-size: calc(var(--t-15) * var(--echelle, 1)); }
.tuile-volets .tuile-etat { font-size: calc(var(--t-17) * var(--echelle, 1)); }
.tuile-volets .tuile-corps { padding-top: 6px; }
.tuile-volets .cale-entete { display: none; }
.tuile-volets .tuile-haut { grid-template-columns: minmax(0, 1fr); }
/* Le rail est détaché du flux et posé sur la tuile ; une case vide lui
   réserve sa place dans la grille. C'est ce qui lui permet de s'élargir
   sous le doigt SANS pousser quoi que ce soit : la mise en page ne bouge
   pas, il passe simplement par-dessus le reste. */

.rail-volet {
  position: absolute; top: 0; bottom: 0; right: 0; width: 34px; z-index: 2;
  border-radius: 11px; border: 1px solid var(--trait); background: var(--surface-creuse);
  overflow: hidden; cursor: ns-resize; touch-action: none;
  transition: top var(--moyen) var(--courbe),
              left var(--moyen) var(--courbe),
              height var(--moyen) var(--courbe),
              box-shadow var(--moyen), background-color var(--moyen);
}
/* Sous le doigt, le rail s'ALLONGE -- il double de hauteur, garde sa
   largeur -- et se déporte franchement vers la gauche pour sortir de
   dessous la main. Il passe en position fixe le temps du geste : c'est
   ce qui lui permet de dépasser de la tuile, qui autrement le rognerait.
   Sa géométrie est calculée en JavaScript (voir ouvrirZoomRail) pour que
   la valeur saisie reste exactement sous le doigt pendant qu'il grandit. */
.rail-volet.saisi {
  z-index: 60; background: var(--surface); box-shadow: var(--ombre-3);
  border-color: var(--trait-fort);
}
/* Le chiffre s'écrit dans le rail, qui ne fait que 34 px de large : il
   se passe donc de l'espace avant le %, sans quoi « 100 % » déborderait. */
.rail-valeur {
  position: absolute; left: 0; right: 0; text-align: center;
  font-size: var(--t-11); font-weight: 700; color: var(--cat-volets);
  font-variant-numeric: tabular-nums; letter-spacing: -0.03em;
  opacity: 0; pointer-events: none; transition: opacity var(--vite);
}
.rail-volet.saisi .rail-valeur { opacity: 1; }
.rail-volet:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.rail-remplissage {
  position: absolute; left: 0; right: 0; top: 0;
  background: var(--cat-volets-fond); border-bottom: 2px solid var(--cat-volets);
  transition: height var(--moyen) linear;
}
/* Les barres défilent dans le TABLIER lui-même -- la partie haute du
   rail, celle qui est fermée -- et non dans la portion qu'il reste à
   parcourir. C'est ce qui bouge réellement à la fenêtre : les lames
   descendent ou remontent, l'ouverture, elle, ne bouge pas. Enfant du
   remplissage, la zone rayée suit sa hauteur sans un calcul de plus. */
.rail-course {
  position: absolute; inset: 0; pointer-events: none;
  background-image: repeating-linear-gradient(
    to bottom,
    var(--cat-volets) 0 2px,
    transparent 2px 10px);
  opacity: .38;
  animation: defile-course 1s linear infinite;
  display: none;
}
.rail-volet.en-course .rail-course { display: block; }
.rail-volet.en-course.remonte .rail-course { animation-direction: reverse; }
@keyframes defile-course {
  from { background-position-y: 0; }
  to   { background-position-y: 10px; }
}

.rail-poignee {
  position: absolute; left: 50%; transform: translate(-50%, -50%);
  width: 18px; height: 3px; pointer-events: none;
  transition: top var(--vite) linear;
  will-change: top;
}
.rail-poignee-barre {
  display: block; width: 100%; height: 100%;
  border-radius: 2px; background: var(--cat-volets);
  /* Le repère de consigne, lui, s'épaissit encore : une mise à l'échelle
     plutôt qu'une largeur, pour rester composité par le navigateur. */
  transform: scale(1); transform-origin: center;
  transition: transform var(--moyen) var(--courbe);
}
/* Sous le doigt, la poignée ne change ni de taille ni de forme : c'est
   le rail entier qui grandit et s'écarte de la main. Elle cesse en
   revanche de lisser sa POSITION verticale, sinon elle traînerait
   derrière le doigt de deux dixièmes de seconde. */
.rail-volet.saisi .rail-poignee { transition: none; }
/* Pendant la course, la poignée est un repère de consigne et non plus un
   curseur : un liseré clair la détache du bord du remplissage, sans
   qu'elle change d'épaisseur pour autant. */
.rail-poignee.cible .rail-poignee-barre { box-shadow: 0 0 0 2px var(--surface); }
/* Consigne pendant la course. Elle prend la place du badge de pied --
   une information secondaire, et surtout une ligne qui existe déjà :
   rien ne bouge dans la mise en page, et rien ne recouvre les touches. */
.consigne-volet { display: none; color: var(--cat-volets); font-weight: 700; }
/* Le pied n'existe plus que pour accueillir la consigne : tant qu'il n'y
   en a pas, il ne prend pas de place. */
.tuile-pied.pied-vide:not(.avec-consigne) { display: none; }
.tuile-pied.avec-consigne .consigne-volet { display: inline; }
.tuile-pied.avec-consigne .pied-texte { display: none; }
.consigne-volet.echec { color: var(--danger); }
.tuile-etat.en-course { color: var(--cat-volets); }

.touches-volet {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 8px;
  width: 100%; margin-top: 10px; flex-shrink: 0;
}
.touche-volet {
  height: 42px; border: 1px solid var(--trait); background: var(--surface-douce);
  color: var(--cat-volets); border-radius: 10px; cursor: pointer;
  display: grid; place-items: center; padding: 0;
  transition: background var(--vite), border-color var(--vite), transform var(--vite);
}
.touche-volet:hover { background: var(--surface-survol); border-color: var(--trait-fort); }
.touche-volet:active { transform: scale(.94); }
/* La commande est partie, la box n'a pas encore répondu : la touche
   respire, le temps de l'aller-retour. */
.touche-volet.attente, .bouton-action.attente { animation: respiration .9s ease-in-out infinite; }
/* Un bouton d'action rendu inerte -- en automatique, « Allumer » n'a
   personne à qui parler. */
.bouton-action:disabled { opacity: .4; cursor: default; pointer-events: none; }
@keyframes respiration { 50% { opacity: .45; } }
.touche-volet:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.touche-volet svg { width: 17px; height: 17px; }
.touche-volet.arret svg { width: 13px; height: 13px; }
/* Le mode silencieux est un réglage global du proxy, pas une commande de
   volet : il se range sous l'icône, du côté de ce qui décrit l'appareil,
   et non parmi les gestes. Il s'allume quand il est actif, comme dans la
   fiche. */
.touche-volet.silence {
  width: 30px; height: 30px; border-radius: 9px; color: var(--texte-doux);
  flex-shrink: 0;
}
.touche-volet.silence svg { width: 15px; height: 15px; }
.touche-volet.silence.actif {
  background: var(--accent); border-color: var(--accent); color: var(--accent-contraste);
}
/* Sur une tuile étroite, la plume ne disparaît pas : elle redescend sous
   l'icône, où elle ne coûte aucune largeur. C'est ajusterControlesVolets
   qui la déplace, une fois la taille réelle connue. */
.tuile-volets .colonne-icone .touche-volet.silence { grid-column: auto; grid-row: auto; }
.tuile.sans-place .touche-volet.silence { display: none; }
/* Trop étroit ou trop bas pour être manipulable : la tuile reprend son
   comportement d'avant, tout passe par la fenêtre. */
.tuile.sans-place .touches-volet,
.tuile.sans-place .rail-place,
.tuile.sans-place .rail-volet { display: none; }
/* En mode disposition, la tuile n'est plus qu'une poignée. */
.tuile.mode-edition .touches-volet,
.tuile.mode-edition .rail-volet { pointer-events: none; opacity: .45; }

/* ------------------------------------------------------------
   LUMIÈRES ET PROJECTEURS : commande directe sur la tuile
   Une lampe obéit en quelques centaines de millisecondes : on peut donc
   basculer l'affichage tout de suite et corriger si la relecture dit
   autre chose -- l'inverse d'un volet, qui met vingt secondes.
   ------------------------------------------------------------ */
.commande-tuile { margin-top: 10px; flex-shrink: 0; display: flex; justify-content: center; }

/* Une lampe se commande par un interrupteur à deux moitiés, comme au
   mur : la moitié enfoncée est celle qui commande, et on voit donc où
   appuyer avant même d'avoir touché. Il reste blanc dans les deux états
   -- c'est le mot sous le nom qui change de couleur, pas le bouton. */
.tuile.tuile-lampe {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  column-gap: 10px; align-items: center;
}
.tuile-lampe .colonne-icone {
  grid-column: 1; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 8px;
}
/* Le bouton du mode automatique tient sous l'icône, à la mesure d'une
   tuile de lampe. Il ne porte pas la classe « silence » des volets :
   celle-ci est déplacée d'une colonne à l'autre par le code qui adapte
   les tuiles de volet, qui l'aurait arraché à la sienne. */
.touche-auto {
  width: 30px; height: 30px; border-radius: 9px; flex-shrink: 0;
  color: var(--texte-doux);
}
.touche-auto svg { width: 15px; height: 15px; }
.touche-auto.actif {
  background: var(--accent); border-color: var(--accent); color: var(--accent-contraste);
}
.tuile.sans-place .touche-auto { display: none; }
.tuile-lampe .colonne-gauche {
  grid-column: 2; min-width: 0; display: flex; flex-direction: column; justify-content: center;
}
/* Chacun sa rangée : les trois colonnes en haut, la ligne de message en
   dessous, collée au bas de la tuile. */
.tuile-lampe .colonne-icone, .tuile-lampe .colonne-gauche, .tuile-lampe .plaque-tuile { grid-row: 1; }
.tuile-lampe .tuile-pied {
  grid-column: 1 / -1; grid-row: 2; align-self: end;
  margin-top: 4px; padding-top: 0;
}
.tuile-lampe .cale-entete { display: none; }
.tuile-lampe .tuile-haut { grid-template-columns: minmax(0, 1fr); }

/* Une seule surface qui bascule, comme une plaque d'interrupteur : le
   creux passe d'un bord à l'autre, la plaque paraît s'enfoncer en haut
   quand la lampe est allumée, en bas quand elle est éteinte. Elle reste
   blanche dans les deux cas -- c'est le mot sous le nom qui change de
   couleur, pas le bouton. Les deux flèches disent où appuyer. */
.plaque-tuile {
  grid-column: 3; width: 42px; height: 64px; border-radius: 13px;
  position: relative; cursor: pointer; flex-shrink: 0; overflow: hidden;
  background: var(--surface); border: 1px solid var(--trait);
  box-shadow: var(--ombre-1);
  display: grid; grid-template-rows: 1fr 1fr;
}
/* Le relief : ombre du côté enfoncé, lumière du côté qui ressort. Une
   rotation d'un demi-tour suffit à le faire basculer -- c'est le même
   dégradé, retourné. */
.plaque-tuile::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg,
      rgba(25, 23, 21, .15) 0%, rgba(25, 23, 21, .02) 38%,
      transparent 60%, rgba(255, 255, 255, .55) 100%);
  transition: transform var(--moyen) var(--courbe);
}
html[data-theme="sombre"] .plaque-tuile::before {
  background: linear-gradient(180deg,
      rgba(0, 0, 0, .45) 0%, rgba(0, 0, 0, .12) 38%,
      transparent 60%, rgba(255, 255, 255, .07) 100%);
}
.plaque-tuile[aria-checked="false"]::before { transform: rotate(180deg); }
.plaque-tuile > span {
  position: relative; display: grid; place-items: center;
  color: var(--texte-faible); transition: color var(--moyen);
}
.plaque-tuile svg { width: 14px; height: 14px; }
/* La flèche du côté qui ressort est celle qu'on peut encore enfoncer :
   c'est elle qu'on met en avant. */
.plaque-tuile[aria-checked="true"] .plaque-bas,
.plaque-tuile[aria-checked="false"] .plaque-haut { color: var(--texte); }
.plaque-tuile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Tant que la commande n'est pas confirmée, la plaque s'estompe : elle
   dit « c'est parti » sans prétendre que c'est fait. */
.plaque-tuile.attente { opacity: .55; }
/* En mode automatique, l'interrupteur montre l'état sans l'ouvrir au
   doigt. La plaque garde sa place et son relief -- la tuile ne doit pas
   changer de forme à chaque bascule --, mais ses deux flèches passent au
   gris le plus clair : plus rien n'invite à appuyer, y compris du côté
   qui était mis en avant. */
.plaque-tuile.verrouille { pointer-events: none; }
.plaque-tuile.verrouille > span,
.plaque-tuile.verrouille[aria-checked="true"] .plaque-bas,
.plaque-tuile.verrouille[aria-checked="false"] .plaque-haut { color: var(--trait-fort); }

/* Trop petite pour porter la commande : la tuile retrouve sa fiche. */
.tuile.sans-place .commande-tuile,
.tuile.sans-place .plaque-tuile { display: none; }

/* États lisibles à la couleur */
.carte-valeur.vert,  .tuile-etat.vert  { color: var(--cat-vehicule); }
.carte-valeur.charge,.tuile-etat.charge{ color: var(--cat-vehicule); }
.carte-valeur.alarme,.tuile-etat.alarme{ color: var(--danger); }
.carte-valeur.actif, .tuile-etat.actif { color: var(--cat-eclairage); }
.carte-valeur.inactif,.tuile-etat.inactif { color: var(--texte-doux); font-weight: 600; }
.carte-valeur.repos,  .tuile-etat.repos   { color: var(--cat-vehicule); }
/* Détecteur sans contact : l'orange de la maison, celui qui dit « il y a
   quelque chose à vérifier » -- pas le rouge, qui est réservé à ce qui
   brûle vraiment. */
.carte-valeur.veille, .tuile-etat.veille  { color: var(--alerte); }

/* ============================================================
   PAGE SÉCURITÉ
   Trois bandes : ce que voient les caméras, ce que disent les
   détecteurs, ce que peuvent faire les sirènes. Une alerte ne se
   cherche pas : quand quelque chose se déclenche, un bandeau le dit en
   haut de la page et la tuile concernée s'allume.
   ============================================================ */
.page-securite {
  position: fixed; inset: 0; z-index: 4;
  padding: calc(16px + var(--haut-sur)) 26px calc(104px + env(safe-area-inset-bottom));
  overflow-y: auto; display: none;
}
.page-securite.visible { display: block; }
.page-securite-contenu { max-width: var(--largeur-max); margin: 0 auto; }
.securite-titre {
  font-size: var(--t-13); font-weight: 600; color: var(--texte-doux);
  letter-spacing: .04em; text-transform: uppercase; margin: 26px 0 12px;
}
.securite-titre:first-of-type { margin-top: 4px; }

/* Le bandeau d'alerte : absent tant que tout va bien. */
.securite-alerte {
  display: none; align-items: center; gap: 12px; margin-bottom: 18px;
  padding: 14px 18px; border-radius: var(--r-md);
  background: var(--danger); color: #FFFFFF; box-shadow: var(--ombre-2);
  font-weight: 600; line-height: 1.4;
}
.securite-alerte.visible { display: flex; }
.securite-alerte svg { flex: none; }
@media (prefers-reduced-motion: no-preference) {
  .securite-alerte.visible { animation: pulse-alerte 1.8s ease-in-out infinite; }
}
@keyframes pulse-alerte { 50% { box-shadow: var(--ombre-2), 0 0 0 6px rgba(192,80,58,.22); } }

/* Les caméras : une vignette rafraîchie régulièrement, et le direct au
   toucher. Les caméras Netatmo ne diffusent qu'un flux à la fois, donc
   afficher quatre directs côte à côte ne marcherait pas. */
.securite-cameras {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--gouttiere);
}
.camera-vignette {
  position: relative; display: block; width: 100%; padding: 0; overflow: hidden;
  aspect-ratio: 16 / 9; border-radius: var(--r-md); border: 1px solid var(--trait);
  background: var(--surface-creuse); color: var(--texte);
  box-shadow: var(--ombre-1); cursor: pointer; text-align: left;
  transition: box-shadow var(--moyen), border-color var(--moyen), transform var(--vite);
}
.camera-vignette:hover { box-shadow: var(--ombre-2); border-color: var(--trait-fort); }
.camera-vignette:active { transform: scale(.99); }
.camera-vignette img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity var(--lent);
}
.camera-vignette img.chargee { opacity: 1; }
.camera-vignette .camera-pied {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 20px 14px 10px; color: #FFFFFF;
  background: linear-gradient(180deg, transparent, rgba(0,0,0,.62));
}
.camera-nom { font-weight: 600; font-size: var(--t-15); }
.camera-etat { font-size: var(--t-12); opacity: .85; }
.camera-vignette.hors-ligne { opacity: .62; }
/* Tant qu'aucune image n'est arrivée, le cadre dit pourquoi. */
.camera-attente {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  padding: 12px; text-align: center; font-size: var(--t-13); color: var(--texte-doux);
}

.securite-grille {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: var(--gouttiere);
}
.securite-grille .tuile { min-height: 118px; }
/* Un détecteur au repos se fait oublier ; déclenché, il se voit de loin. */
.tuile.tuile-declenchee {
  border-color: var(--danger); background: var(--danger-fond, rgba(192,80,58,.10));
}
.tuile.tuile-declenchee .tuile-nom, .tuile.tuile-declenchee .tuile-etat { color: var(--danger); }
.securite-sirene .touches-sirene { display: flex; gap: 8px; margin-top: 10px; }
.securite-sirene .touche-sirene {
  flex: 1; height: 38px; border-radius: var(--r-sm); cursor: pointer;
  border: 1px solid var(--trait); background: var(--surface-creuse); color: var(--texte);
  font-size: var(--t-13); font-weight: 600; transition: background var(--vite), color var(--vite), border-color var(--vite);
}
.securite-sirene .touche-sirene:hover { border-color: var(--trait-fort); }
.securite-sirene .touche-sirene.danger { color: var(--danger); }
.securite-sirene .touche-sirene.danger:hover { background: var(--danger); color: #FFFFFF; border-color: var(--danger); }
.securite-sirene .touche-sirene:disabled { opacity: .45; cursor: not-allowed; }
.securite-vide { color: var(--texte-doux); font-size: var(--t-13); padding: 6px 0 2px; }

@media (max-width: 820px) {
  .page-securite { padding: calc(14px + var(--haut-sur)) 16px calc(96px + env(safe-area-inset-bottom)); }
  /* Trois vignettes pleine largeur, c'est tout l'écran occupé avant
     d'atteindre les détecteurs : sur téléphone elles se mettent par
     deux, et le direct reste à un toucher. */
  .securite-cameras { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
  .camera-vignette .camera-pied { padding: 16px 10px 8px; }
  .camera-nom { font-size: var(--t-13); }
  .camera-etat { font-size: var(--t-11); }
  .securite-grille { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
}

/* ============================================================
   PAGE ENSOLEILLEMENT DE LA FAÇADE SUD
   Le calcul des ombres portées du balcon, de la casquette et de la
   pergola sur les deux baies. La feuille de style d'origine visait une
   page entière -- elle est ici cantonnée à « .page-soleil », sans quoi
   ses règles sur « button », « svg » ou « header » repeindraient tout le
   tableau de bord. Les couleurs de structure sont raccordées au thème
   maison ; seules les couleurs du dessin lui restent propres.
   ============================================================ */
.page-soleil {
  position: fixed; inset: 0; z-index: 4;
  padding: calc(16px + var(--haut-sur)) 26px calc(104px + env(safe-area-inset-bottom));
  overflow-y: auto; display: none;

  /* Structure : ces noms sont ceux de la page d'origine, leurs valeurs
     celles du tableau de bord -- le thème sombre suit ainsi tout seul. */
  --paper: var(--surface-douce);
  --panel: var(--surface);
  --rule: var(--trait);
  --ink: var(--texte);
  --ink-2: var(--texte-doux);
  --ink-3: var(--texte-faible);
  --radius: var(--r-sm);
  /* Dessin : le soleil, l'ombre, et chaque ouvrage de la façade. */
  --sun:#E39A18; --shade:#4E4E48; --slab:#6FA33B; --casq:#C8603C;
  --perg:#C0803A; --bois:#9A6B3C; --glass:#7FA8C4; --glass-2:#9C8AC0; --wall:#E2D9C8;
}
/* De nuit, l'ombre et le mur s'éclaircissent : sur fond sombre, un gris
   foncé sur fond noir ne se distingue plus de rien. */
html[data-theme="sombre"] .page-soleil {
  --shade:#8E8E86; --wall:#3E3830; --glass:#6F9BBA; --glass-2:#8D7CB4;
}
.page-soleil.visible { display: block; }

.page-soleil .wrap {max-width:var(--largeur-max);margin:0 auto;padding:0}
.page-soleil header {display:flex;flex-wrap:wrap;gap:12px;align-items:baseline;justify-content:space-between;padding-bottom:14px;border-bottom:1px solid var(--rule);margin-bottom:20px}
.page-soleil h1 {font-size:var(--t-21);font-weight:600;letter-spacing:-0.01em;margin:0}
.page-soleil header p {margin:2px 0 0;color:var(--ink-2);font-size:var(--t-13)}
.page-soleil .now {display:flex;gap:8px;align-items:center}
/* Les boutons Thème et Réglages flottent en haut à droite de toutes les
   pages : « Maintenant » et « Dérouler la journée » passaient dessous.
   On leur réserve la même largeur qu'aux titres de page. Sur un
   téléphone, l'en-tête se replie et les boutons descendent d'eux-mêmes
   sous le titre : rien à réserver. */
@media (min-width: 500px) { .page-soleil header { padding-right: 104px; } }
.page-soleil button {font:inherit;font-size:var(--t-13);padding:7px 12px;border:1px solid var(--rule);background:var(--panel);color:var(--ink);border-radius:var(--radius);cursor:pointer}
.page-soleil button:hover {border-color:var(--ink-3)}
.page-soleil button:focus-visible {outline:2px solid var(--accent);outline-offset:2px}
.page-soleil button.on {background:var(--sun);border-color:var(--sun);color:#231A05}
.page-soleil .grid {display:grid;grid-template-columns:minmax(0,1.55fr) minmax(290px,1fr);gap:20px;align-items:start}
@media (max-width:940px) {
  .page-soleil .grid{grid-template-columns:minmax(0,1fr)}
}
.page-soleil .card {background:var(--panel);border:1px solid var(--rule);border-radius:var(--radius);padding:14px 16px}
.page-soleil .card+.card {margin-top:16px}
.page-soleil .card h2 {font-size:var(--t-13);font-weight:600;color:var(--ink-2);margin:0 0 10px}
.page-soleil svg {display:block;width:100%;height:auto}
.page-soleil .field {display:grid;grid-template-columns:1fr auto;gap:2px 10px;align-items:center;margin:0 0 14px}
.page-soleil .field label {font-size:var(--t-13);color:var(--ink-2)}
.page-soleil .field output {font-size:var(--t-13);font-weight:600;font-variant-numeric:tabular-nums}
.page-soleil .field input[type=range] {grid-column:1/-1;width:100%;accent-color:var(--sun);margin:2px 0 0}
.page-soleil .field input[type=date] {grid-column:1/-1;font:inherit;font-size:var(--t-13);padding:6px 8px;border:1px solid var(--rule);border-radius:8px;background:var(--paper);color:var(--ink)}
.page-soleil details {border-top:1px solid var(--rule);padding-top:12px;margin-top:4px}
.page-soleil details summary {cursor:pointer;font-size:var(--t-13);color:var(--ink-2);margin-bottom:12px}
.page-soleil .nums {display:grid;grid-template-columns:1fr 84px;gap:7px 10px;align-items:center;font-size:var(--t-13);margin-bottom:12px}
.page-soleil .nums span {color:var(--ink-2)}
.page-soleil .nums input {font:inherit;font-size:var(--t-13);width:100%;padding:5px 7px;border:1px solid var(--rule);border-radius:7px;background:var(--paper);color:var(--ink);font-variant-numeric:tabular-nums}
.page-soleil .nums h3 {grid-column:1/-1;font-size:var(--t-12);font-weight:600;color:var(--ink);margin:6px 0 0}
.page-soleil .read {display:grid;grid-template-columns:repeat(auto-fit,minmax(128px,1fr));gap:1px;background:var(--rule);border:1px solid var(--rule);border-radius:var(--radius);overflow:hidden}
.page-soleil .read div {background:var(--panel);padding:11px 13px}
.page-soleil .read dt {font-size:var(--t-12);color:var(--ink-2);margin:0}
.page-soleil .read dd {margin:2px 0 0;font-size:var(--t-19);font-weight:600;font-variant-numeric:tabular-nums;letter-spacing:-0.01em}
.page-soleil .read div.key dd {color:var(--sun);font-size:var(--t-17)}
.page-soleil table.baies {width:100%;border-collapse:collapse;font-size:var(--t-13);margin-top:12px;font-variant-numeric:tabular-nums}
.page-soleil table.baies th {text-align:right;font-weight:500;color:var(--ink-2);padding:6px 4px;border-bottom:1px solid var(--rule)}
.page-soleil table.baies th:first-child {text-align:left}
.page-soleil table.baies td {text-align:right;padding:7px 4px;border-bottom:1px solid var(--rule)}
.page-soleil table.baies td:first-child {text-align:left}
.page-soleil table.baies tr:last-child td {border-bottom:none}
.page-soleil .chip {display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:6px}
.page-soleil .legend {display:flex;flex-wrap:wrap;gap:14px;font-size:var(--t-12);color:var(--ink-2);margin-top:10px}
.page-soleil .legend i {display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:5px;vertical-align:-1px}
.page-soleil .calib {display:flex;flex-wrap:wrap;gap:8px;align-items:center;font-size:var(--t-13)}
.page-soleil .calib input[type=number] {font:inherit;width:88px;padding:6px 8px;border:1px solid var(--rule);border-radius:8px;background:var(--paper);color:var(--ink)}
.page-soleil footer {margin-top:26px;padding-top:14px;border-top:1px solid var(--rule);color:var(--ink-3);font-size:var(--t-13);max-width:72ch}
.page-soleil footer ul {margin:6px 0 0;padding-left:18px}
@media (max-width: 820px) {
  .page-soleil { padding: calc(14px + var(--haut-sur)) 16px calc(96px + env(safe-area-inset-bottom)); }
}

/* Les deux vues côte à côte en haut de page, l'heure sur toute la
   largeur, puis les réglages sur trois colonnes. */
.page-soleil .vues {display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:20px;align-items:start;margin-bottom:20px}
.page-soleil .vues .card+.card {margin-top:0}
.page-soleil .carte-heure {margin-bottom:20px}
.page-soleil .carte-heure .field {margin-bottom:10px}
.page-soleil .carte-heure .field label {font-size:var(--t-13);font-weight:600;color:var(--ink)}
.page-soleil .carte-heure .field output {font-size:var(--t-17)}
.page-soleil .grid-reglages {grid-template-columns:repeat(3,minmax(0,1fr));margin-bottom:20px}
.page-soleil .grid-reglages .card+.card {margin-top:0}
@media (max-width:940px) {
  .page-soleil .vues {grid-template-columns:minmax(0,1fr)}
  .page-soleil .vues .card+.card {margin-top:16px}
  .page-soleil .grid-reglages {grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:560px) {
  .page-soleil .grid-reglages {grid-template-columns:minmax(0,1fr)}
  .page-soleil .grid-reglages .card+.card {margin-top:16px}
}

/* Sur un téléphone (iPhone en tête), la page d'ensoleillement n'est
   pas proposée : trop dense pour l'écran. */
@media (max-width: 600px) { .barre-bas-item[data-page="soleil"] { display: none; } }
html.iphone .barre-bas-item[data-page="soleil"] { display: none; }

/* Le plan du terrain en relief : un canevas dessiné à la main en
   projection orthographique, et par-dessus, dans le plan de l'écran,
   les poignées des arbres et la boussole. */
.page-soleil .terrain-aide {margin:0 0 10px;font-size:var(--t-13);color:var(--ink-2)}
.page-soleil .terrain-scene {position:relative;width:100%;aspect-ratio:4/3;min-height:240px;overflow:hidden;border-radius:var(--radius);
  background:#ECE8DF;border:1px solid var(--rule);touch-action:pan-y;user-select:none;-webkit-user-select:none}
html[data-theme="sombre"] .page-soleil .terrain-scene {background:#2B2B27}
.page-soleil .terrain-toile {position:absolute;left:0;top:0;display:block;width:100%;height:100%}
.page-soleil .terrain-poignees {position:absolute;inset:0;pointer-events:none}
.page-soleil .terrain-poignee {position:absolute;width:24px;height:24px;margin:-12px 0 0 -12px;padding:0;border-radius:50%;
  pointer-events:auto;touch-action:none;cursor:grab;background:#2F7D3A;color:#fff;border:2px solid #fff;
  box-shadow:0 2px 6px rgba(0,0,0,.35);font-weight:700;font-size:var(--t-11);line-height:1}
.page-soleil .terrain-poignee:hover {border-color:#fff;background:#3E8E4A}
.page-soleil .terrain-poignee.saisie {cursor:grabbing;transform:scale(1.15);background:#3E8E4A}
.page-soleil .terrain-boussole {position:absolute;right:10px;top:10px;width:44px;height:44px;pointer-events:none}
.page-soleil .terrain-boussole svg {width:100%;height:100%;overflow:visible}
.page-soleil .terrain-boussole-fond {fill:#fff;fill-opacity:.88;stroke:#6A6A62;stroke-width:1}
html[data-theme="sombre"] .page-soleil .terrain-boussole-fond {fill:#2B2B27;stroke:#8E8E86}
html[data-theme="sombre"] .page-soleil .terrain-boussole-n {fill:#F0EEE8}
.page-soleil .terrain-boutons {display:flex;flex-wrap:wrap;gap:8px;margin:10px 0 12px}
.page-soleil .terrain-lecture {font-size:var(--t-13);color:var(--ink-2);display:grid;gap:4px}
.page-soleil .terrain-lecture + .terrain-aide {margin:10px 0 0}

/* ============================================================
   BARRE DE NAVIGATION DU BAS
   ============================================================ */
.barre-bas {
  position: fixed; left: 0; right: 0; z-index: 20;
  bottom: var(--bas-flottant);
  display: flex; justify-content: center; pointer-events: none;
  /* La pilule peut devenir plus large que l'écran : elle doit pouvoir
     glisser sans que la barre elle-même déborde. */
  max-width: 100%; padding: 0 10px;
}
.barre-bas-pilule {
  background: var(--surface); border: 1px solid var(--trait);
  box-shadow: var(--ombre-2); border-radius: var(--r-pilule);
  display: flex; gap: 4px; padding: 6px; pointer-events: auto;
  /* Huit pages ne tiennent pas dans la largeur d'un téléphone. Plutôt
     que de rapetisser les cibles sous le seuil du doigt, la pilule
     défile ; l'icône active est ramenée à l'écran à chaque changement
     de page. La barre de défilement, elle, n'a rien à montrer. */
  max-width: 100%; overflow-x: auto; scrollbar-width: none;
  overscroll-behavior-x: contain; scroll-behavior: smooth;
}
.barre-bas-pilule::-webkit-scrollbar { display: none; }
.barre-bas-item {
  flex: none; width: 50px; height: 50px; border-radius: var(--r-pilule);
  display: flex; align-items: center; justify-content: center;
  color: var(--texte-doux); cursor: pointer; border: none; background: none;
  transition: background var(--vite), color var(--vite), transform var(--vite);
}
.barre-bas-item:hover { background: var(--surface-creuse); color: var(--texte); }
.barre-bas-info {
  position: absolute; bottom: calc(100% + 8px); left: 0;
  transform: translateX(-50%);
  padding: 5px 10px; border-radius: 9px;
  background: var(--texte); color: var(--surface);
  font-size: var(--t-11); font-weight: 650; white-space: nowrap;
  pointer-events: none; box-shadow: var(--ombre-2);
}
.barre-bas-info[hidden] { display: none; }
.barre-bas-item:active { transform: scale(.92); }
.barre-bas-item.actif { background: var(--accent); color: var(--accent-contraste); }
.barre-bas-item.en-cours { color: var(--accent); pointer-events: none; }
.barre-bas-item.en-cours svg { animation: tourner-actualiser .9s linear infinite; }
@keyframes tourner-actualiser { to { transform: rotate(360deg); } }

/* ============================================================
   FENÊTRES MODALES
   ============================================================ */
.voile, .voile-graphique, .voile-flux {
  position: fixed; inset: 0; z-index: 40; display: none;
  background: color-mix(in srgb, var(--texte) 34%, transparent);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
}
.voile-graphique { z-index: 42; }
.voile-flux { z-index: 44; }
.voile-capteur {
  position: fixed; inset: 0; z-index: 44; display: none;
  background: color-mix(in srgb, var(--texte) 34%, transparent);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
}
.voile-capteur.ouvert { display: block; }
/* La tuile en grand : la même courbe, mais avec de quoi la lire --
   une échelle de temps sous l'axe et les valeurs sur le côté. */
.fenetre-capteur {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r-xl); color: var(--texte); box-shadow: var(--ombre-3);
  z-index: 45; display: none; overflow-y: auto;
  width: min(960px, calc(100vw - 28px)); max-height: calc(100vh - 32px);
  padding: 22px 24px calc(22px + env(safe-area-inset-bottom));
}
.fenetre-capteur.ouvert { display: block; }
.fenetre-capteur .lieu { margin-bottom: 0; }
/* Un module : ses mesures du moment côte à côte, puis une courbe par
   mesure, l'une sous l'autre. */
.capteur-valeur .module-mesure { display: inline-flex; flex-direction: column; margin-right: 22px; }
.capteur-valeur .module-mesure-nom {
  font-size: var(--t-11); font-weight: 600; color: var(--texte-doux);
  letter-spacing: .04em; text-transform: uppercase;
}
.capteur-courbe.module .module-courbe + .module-courbe { margin-top: 18px; }
.capteur-courbe.module .module-courbe-titre {
  font-size: var(--t-13); font-weight: 650; color: var(--texte-doux); margin-bottom: 4px;
}
/* Sous le titre, une ligne à trois places : la valeur du capteur à
   gauche, le mini et le maxi de chaque courbe au milieu, la clé des
   couleurs à droite. Sur un téléphone, la ligne se replie. */
.capteur-bandeau {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px 18px; flex-wrap: wrap; margin: 14px 0 6px;
}
.capteur-valeur {
  font-size: var(--t-30); font-weight: 750; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums; flex: 0 1 auto;
}
.capteur-extremes { display: flex; gap: 18px; flex: 1 1 auto; justify-content: center; }
.capteur-extreme { text-align: center; font-variant-numeric: tabular-nums; }
.capteur-extreme .titre {
  font-size: var(--t-11); font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: var(--couleur-courbe);
}
.capteur-extreme .valeurs { font-size: var(--t-15); font-weight: 750; color: var(--couleur-courbe); white-space: nowrap; }
.capteur-extreme .valeurs small { font-size: var(--t-11); font-weight: 600; color: var(--texte-faible); margin: 0 3px; }
.capteur-cles { display: flex; flex-direction: column; gap: 5px; flex: 0 0 auto; }
.capteur-cle { display: flex; align-items: center; gap: 8px; font-size: var(--t-12); font-weight: 650; color: var(--texte-doux); }
.capteur-cle .trait { width: 22px; height: 0; border-top: 2.5px solid var(--couleur-courbe); border-radius: 2px; }
@media (max-width: 600px) {
  /* Replié sous la valeur : la clé tient sur une ligne, sans prendre
     deux hauteurs. */
  .capteur-cles { flex-direction: row; flex-wrap: wrap; gap: 4px 16px; }
}
.capteur-valeur.inconnue { color: var(--texte-faible); }
.capteur-valeur-note {
  font-size: var(--t-13); font-weight: 600; color: var(--texte-faible);
  letter-spacing: 0; margin-left: 6px;
}
.capteur-courbe svg { width: 100%; height: auto; display: block; }
.capteur-courbe .trace {
  fill: none; stroke: var(--cat, var(--cat-autres)); stroke-width: 2.2px;
  stroke-linejoin: round; stroke-linecap: round;
}
.capteur-courbe .aire { fill: var(--cat, var(--cat-autres)); opacity: .12; stroke: none; }
/* Dans la grande fenêtre, le modèle se distingue franchement du relevé :
   un trait rouge continu, sans aire dessous. */
.capteur-courbe .trace-prevue {
  fill: none; stroke: var(--danger); stroke-width: 2px;
  opacity: .9; stroke-linejoin: round; stroke-linecap: round;
}
.capteur-courbe .tete { fill: var(--cat, var(--cat-autres)); stroke: none; }
.capteur-courbe .grille { stroke: var(--trait); stroke-width: 1px; }
.capteur-courbe .axe { stroke: var(--trait-fort); stroke-width: 1px; }
.capteur-courbe .repere-maintenant { stroke: var(--texte-faible); stroke-width: 1px; stroke-dasharray: 3 3; opacity: .6; }
.capteur-courbe .etiquette {
  fill: var(--texte-faible); font-size: 11px; font-weight: 650;
  font-family: inherit; font-variant-numeric: tabular-nums;
}
.capteur-courbe .etiquette.maintenant { fill: var(--texte-doux); }
/* Le curseur sous le doigt : trait, points et valeurs de la couleur de
   chaque courbe, heure sur fond de surface pour rester lisible
   par-dessus les graduations. */
.capteur-courbe svg { touch-action: none; cursor: crosshair; }
.capteur-courbe .curseur[hidden], .capteur-courbe .curseur [hidden] { display: none; }
.capteur-courbe .curseur-ligne { stroke: var(--texte-doux); stroke-width: 1px; stroke-dasharray: 2 2; }
.capteur-courbe .curseur-fond { fill: var(--surface); stroke: var(--trait-fort); stroke-width: 1px; }
.capteur-courbe .curseur-heure { fill: var(--texte); font-size: 11px; font-weight: 700; font-family: inherit; }
.capteur-courbe .curseur-point { stroke: var(--surface); stroke-width: 2px; }
.capteur-courbe .curseur-point.mesure { fill: var(--cat, var(--cat-autres)); }
.capteur-courbe .curseur-point.modele { fill: var(--danger); }
.capteur-courbe .curseur-valeur {
  font-size: 13px; font-weight: 750; font-family: inherit; font-variant-numeric: tabular-nums;
  paint-order: stroke; stroke: var(--surface); stroke-width: 4px; stroke-linejoin: round;
}
.capteur-courbe .curseur-valeur.mesure { fill: var(--cat, var(--cat-autres)); }
.capteur-courbe .curseur-valeur.modele { fill: var(--danger); }
.capteur-sans-courbe {
  display: flex; align-items: center; justify-content: center; text-align: center;
  min-height: 150px; padding: 20px; font-size: var(--t-13); color: var(--texte-doux);
  background: var(--surface-douce); border-radius: var(--r-md);
}
.voile-radar {
  position: fixed; inset: 0; z-index: 46; display: none;
  background: color-mix(in srgb, var(--texte) 34%, transparent);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
}
.voile.ouvert, .voile-graphique.ouvert, .voile-flux.ouvert, .voile-radar.ouvert { display: block; }
/* Une tuile de capteur s'ouvre : le doigt doit sentir que c'est cliquable. */
.meteo-capteurs:not(.reorganisable) .meteo-capteur { cursor: pointer; }
.meteo-capteurs:not(.reorganisable) .meteo-capteur:active { transform: scale(.985); }

/* La fenêtre du radar occupe la moitié de la page, en hauteur comme en
   largeur : assez pour lire l'arrivée d'une averse, pas assez pour
   perdre de vue ce qu'il y avait derrière. */
.fenetre-radar {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r-xl); color: var(--texte); box-shadow: var(--ombre-3);
  z-index: 47; display: none; overflow-y: auto;
  width: min(75vw, 960px); max-width: calc(100vw - 32px);
  height: 75vh; min-height: 460px; max-height: calc(100vh - 32px);
  padding: 22px 24px calc(22px + env(safe-area-inset-bottom));
}
.fenetre-radar.ouvert { display: flex; flex-direction: column; }
@media (max-width: 820px) {
  /* Sur un téléphone, une fraction de la largeur ne montrerait rien :
     la fenêtre prend les trois quarts de l'écran, toute largeur utile
     comprise -- une averse se lit mal dans un timbre-poste. */
  .fenetre-radar { width: calc(100vw - 20px); height: 75vh; }
}
.cadre-radar {
  position: relative; flex: 1; min-height: 0; margin-bottom: 12px;
  border-radius: var(--r-md); overflow: hidden; background: var(--surface-creuse);
  touch-action: none;   /* molette et pincement vont au zoom de la carte */
}
.cadre-radar canvas { width: 100%; height: 100%; display: block; object-fit: cover; }
.radar-etat {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  text-align: center; padding: 20px; font-size: var(--t-13); color: var(--texte-doux);
  background: var(--surface-douce);
}
.radar-etat[hidden] { display: none; }
.radar-horodatage {
  position: absolute; left: 10px; bottom: 10px; padding: 4px 10px;
  border-radius: 999px; background: color-mix(in srgb, var(--surface) 82%, transparent);
  font-size: var(--t-12); font-weight: 650; font-variant-numeric: tabular-nums;
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
}
/* Les dernières images ne sont plus des relevés mais une extrapolation :
   elles le disent, pour qu'on ne prenne pas une anticipation pour une
   averse constatée. */
.radar-horodatage.prevision { color: var(--accent); }
/* Où va l'averse, écrit sous l'heure : la flèche sur la carte donne la
   direction, cette ligne donne le chiffre. */
.radar-trajectoire {
  position: absolute; left: 10px; bottom: 40px; padding: 3px 10px;
  border-radius: 999px; background: color-mix(in srgb, var(--surface) 82%, transparent);
  font-size: var(--t-11); font-weight: 650; color: var(--texte-doux);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
}
.radar-trajectoire[hidden] { display: none; }
.radar-zoom {
  position: absolute; right: 10px; top: 10px; display: flex; flex-direction: column; gap: 6px;
}
.radar-zoom button {
  width: 34px; height: 34px; border-radius: 10px; padding: 0;
  border: 1px solid var(--trait); background: color-mix(in srgb, var(--surface) 88%, transparent);
  color: var(--texte); font: inherit; font-size: var(--t-17); font-weight: 700; cursor: pointer;
  display: flex; align-items: center; justify-content: center; line-height: 1;
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
}
.radar-zoom button:hover:not(:disabled) { background: var(--surface); }
.radar-zoom button:disabled { opacity: .4; cursor: default; }
/* Observé / Prévu : deux sources qui ne se confondent pas. L'une est
   une mesure du ciel, l'autre un modèle ; un onglet par nature de
   donnée vaut mieux qu'une timeline qui les couturerait ensemble. */
.radar-onglets {
  display: inline-flex; gap: 3px; flex: none; margin: -12px 0 12px;
  padding: 3px; border-radius: 12px; background: var(--surface-creuse);
}
.radar-onglets button {
  border: 0; background: transparent; color: var(--texte-doux);
  font: inherit; font-size: var(--t-12); font-weight: 650; cursor: pointer;
  padding: 6px 15px; border-radius: 9px;
  transition: background var(--vite), color var(--vite);
}
.radar-onglets button.actif { background: var(--surface); color: var(--texte); box-shadow: var(--ombre-1); }
/* L'échelle des couleurs : sans elle, un aplat vert ne veut rien dire. */
.radar-echelle {
  display: flex; align-items: center; gap: 8px; flex: none; margin-top: 10px;
  font-size: var(--t-11); font-weight: 650; color: var(--texte-faible);
}
.radar-echelle[hidden] { display: none; }
.radar-echelle i {
  flex: 1; height: 8px; border-radius: 999px;
  background: linear-gradient(to right,
    rgb(150,205,240), rgb(80,160,225), rgb(40,105,205), rgb(55,170,95),
    rgb(235,200,55), rgb(240,140,45), rgb(220,60,60));
}
.radar-commandes { display: flex; align-items: center; gap: 12px; flex: none; }
.bouton-radar-lecture {
  width: 38px; height: 38px; flex: none; border-radius: 50%;
  border: 1px solid var(--trait); background: var(--surface-douce);
  color: var(--texte); cursor: pointer; display: flex;
  align-items: center; justify-content: center; padding: 0;
}
.bouton-radar-lecture svg { width: 17px; height: 17px; }
.bouton-radar-lecture:hover:not(:disabled) { background: var(--surface-creuse); }
.bouton-radar-lecture:disabled, #radar-curseur:disabled { opacity: .4; cursor: default; }
#radar-curseur { flex: 1; min-width: 0; accent-color: var(--accent); }
.radar-source {
  flex: none; margin-top: 10px; font-size: var(--t-11); color: var(--texte-faible);
}

.fenetre, .fenetre-graphique, .fenetre-flux {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r-xl); color: var(--texte);
  box-shadow: var(--ombre-3);
  overflow-y: auto; display: none;
  padding: 24px 26px calc(26px + env(safe-area-inset-bottom));
}
.fenetre { width: 412px; max-width: calc(100vw - 40px); max-height: 86vh; z-index: 41; }
/* La fiche d'une caméra : deux fois plus large, parce que l'image EST
   le contenu. La hauteur suit toute seule, le cadre gardant son 16/9. */
.fenetre.fenetre-camera { width: 824px; }
/* La fiche du coût de l'électricité : ses tableaux comparatifs veulent
   de la largeur. En feuille (téléphone), la règle générale reprend. */
.fenetre.fenetre-large { width: 660px; }
/* Le graphique du coût, dans la fiche : presque deux fois plus haut
   qu'avant (26/09, demande de Fred) -- les écarts entre jours se lisent. */
.fenetre.fenetre-large .cout-barres { max-height: 260px; }
/* Un détecteur n'a qu'un mot à dire : sa fiche est une vignette, pas une
   fenêtre. Tout y est resserré -- titre, croix, marges, bouton -- parce
   qu'une petite boîte pleine de vide reste une grande boîte. */
.fenetre.fenetre-menue { width: 232px; padding: 13px 15px 15px; }
.fenetre.fenetre-menue .fenetre-entete { margin-bottom: 0; gap: 8px; }
.fenetre.fenetre-menue .fenetre-entete h2,
.fenetre.fenetre-menue h2 { font-size: var(--t-15); line-height: 1.2; }
.fenetre.fenetre-menue .fermer-fenetre { width: 28px; height: 28px; flex: none; }
.fenetre.fenetre-menue .lieu { margin-bottom: 7px; font-size: var(--t-11); }
.fenetre.fenetre-menue .valeur-geante { font-size: var(--t-21); margin: 2px 0 0; }
.fenetre.fenetre-menue .valeur-legende { font-size: var(--t-11); margin-top: 2px; }
.fenetre.fenetre-menue #relire-capteur {
  margin-top: 10px; padding: 8px 10px; font-size: var(--t-12);
}
/* Le bandeau de retour ne réserve pas sa place tant qu'il n'a rien à
   dire : sur une vignette, ses trente pixels se voient. */
.fenetre.fenetre-menue .message-retour:empty { display: none; margin: 0; }
.fenetre-graphique { width: 760px; max-width: calc(100vw - 40px); max-height: 88vh; z-index: 43; }
.fenetre-flux { width: 660px; max-width: calc(100vw - 32px); max-height: 88vh; z-index: 45; }
.fenetre.ouvert, .fenetre-graphique.ouvert, .fenetre-flux.ouvert { display: block; }

.fenetre-entete {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px; margin-bottom: 3px;
}
.fenetre-entete h2, .fenetre h2 { font-size: var(--t-21); margin: 0; font-weight: 700; letter-spacing: -0.015em; }
.lieu { font-size: var(--t-13); font-weight: 500; color: var(--texte-doux); margin-bottom: 20px; }
.fermer-fenetre, .bouton-retour-flux {
  width: 34px; height: 34px; border-radius: 10px; border: 1px solid var(--trait);
  cursor: pointer; background: var(--surface-douce); color: var(--texte-doux);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--t-17); flex-shrink: 0; transition: background var(--vite), color var(--vite);
}
.fermer-fenetre:hover, .bouton-retour-flux:hover { background: var(--surface-creuse); color: var(--texte); }

.valeur-geante {
  font-size: var(--t-46); font-weight: 700; text-align: center; margin: 4px 0 2px;
  font-variant-numeric: tabular-nums; letter-spacing: -0.03em; line-height: 1.05;
}
.valeur-geante.vert, .valeur-geante.charge { color: var(--cat-vehicule); }
.valeur-geante.attention { color: var(--alerte); }
/* --- Liste des piles ---------------------------------------------- */
.liste-piles {
  display: flex; flex-direction: column; gap: 2px; margin-top: 4px;
  border: 1px solid var(--trait); border-radius: var(--r-sm); overflow: hidden; background: var(--trait);
}
.liste-piles.discrete { opacity: .72; }
/* La fiche Santé, le journal et les versions (Diagnostic). */
.liste-sante { display: flex; flex-direction: column; gap: 1px; margin-top: 12px; border-radius: var(--r-sm); overflow: hidden; }
.ligne-sante { display: flex; align-items: flex-start; gap: 10px; padding: 9px 12px; background: var(--surface-douce); }
.point-sante { flex: none; width: 10px; height: 10px; border-radius: 50%; margin-top: 5px; background: var(--succes); }
.ligne-sante.g1 .point-sante { background: #D9A400; }
.ligne-sante.g2 .point-sante { background: var(--danger); }
.sante-nom { font-size: var(--t-13); font-weight: 650; }
.sante-detail { font-weight: 500; color: var(--texte-doux); font-size: var(--t-11); }
.sante-etat { font-size: var(--t-12); color: var(--texte-doux); }
.ligne-sante.g2 .sante-etat { color: var(--danger); font-weight: 600; }
.valeur-geante.alarme { color: var(--danger); }
.valeur-geante.attention { color: #B68A00; }
.zone-journal { margin-top: 8px; max-height: 360px; overflow-y: auto; font-size: var(--t-12); }
.journal-jour { font-size: var(--t-11); font-weight: 650; text-transform: uppercase; letter-spacing: .04em; color: var(--texte-doux); margin: 10px 0 4px; }
.ligne-journal { display: flex; gap: 8px; padding: 4px 0; border-top: 1px solid var(--trait); }
.journal-heure { flex: none; font-variant-numeric: tabular-nums; color: var(--texte-doux); }
.journal-texte { overflow-wrap: anywhere; }
.ligne-journal.erreur .journal-texte { color: var(--danger); }
.ligne-journal.attention .journal-texte { color: #B68A00; }
.ligne-version { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 7px 0; border-top: 1px solid var(--trait); }
.version-texte { display: flex; flex-direction: column; font-size: var(--t-12); }
.version-texte span { color: var(--texte-doux); }
.ligne-version .bouton.compact { margin: 0; }

.ligne-pile {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--surface-douce); padding: 10px 13px;
}
.pile-nom { font-size: var(--t-14); font-weight: 650; min-width: 0; }
.pile-source {
  display: block; font-size: var(--t-11); font-weight: 600; color: var(--texte-faible);
  text-transform: uppercase; letter-spacing: .05em; margin-top: 2px;
}
.pile-mesure { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.pile-jauge {
  width: 64px; height: 8px; border-radius: 999px; background: var(--trait); overflow: hidden;
}
.pile-jauge > span { display: block; height: 100%; border-radius: 999px; background: var(--succes); }
.pile-valeur {
  font-size: var(--t-14); font-weight: 700; font-variant-numeric: tabular-nums;
  min-width: 52px; text-align: right;
}
.ligne-pile.attention .pile-valeur { color: var(--alerte); }
.ligne-pile.attention .pile-jauge > span { background: var(--alerte); }
.ligne-pile.alarme .pile-valeur { color: var(--danger); }
.ligne-pile.alarme .pile-jauge > span { background: var(--danger); }
.valeur-legende {
  text-align: center; font-size: var(--t-13); color: var(--texte-doux); margin-bottom: 20px;
}

.rangee-boutons { display: flex; gap: 8px; margin-bottom: 14px; }
.bouton-action {
  flex: 1; padding: 14px 8px; border-radius: var(--r-sm); cursor: pointer;
  background: var(--surface-douce); border: 1px solid var(--trait);
  color: var(--texte); font-size: var(--t-13); font-weight: 650;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  transition: background var(--vite), border-color var(--vite), transform var(--vite);
}
.bouton-action:hover { background: var(--surface-creuse); border-color: var(--trait-fort); }
.bouton-action:active { transform: scale(.96); }
.bouton-action.principal {
  background: var(--accent); border-color: var(--accent); color: var(--accent-contraste);
}
.bouton-action.principal:hover { background: var(--accent-fort); border-color: var(--accent-fort); }
.bouton-action.eteint { color: var(--texte-faible); }
/* Commande indisponible : la borne n'attend rien de nous (pas de
   véhicule branché, ou charge pilotée depuis Loxone). */
.bouton-action[disabled] {
  background: var(--surface-creuse); border-color: var(--trait);
  color: var(--texte-faible); cursor: not-allowed; box-shadow: none;
}
.bouton-action[disabled]:hover { background: var(--surface-creuse); border-color: var(--trait); }
.bouton-action[disabled]:active { transform: none; }
.bouton-action[disabled] svg { opacity: .55; }
.bouton-action.bouton-charge-actif {
  background: var(--danger-doux); border-color: var(--danger); color: var(--danger);
}
.bouton-action.bouton-charge-inactif {
  background: var(--accent); border-color: var(--accent); color: var(--accent-contraste);
}

input[type=range] {
  width: 100%; margin: 8px 0 4px; accent-color: var(--accent); height: 28px;
}
.etiquettes-curseur {
  display: flex; justify-content: space-between; font-size: var(--t-11);
  color: var(--texte-doux); font-variant-numeric: tabular-nums;
}
.message-retour {
  font-size: var(--t-12); color: var(--accent); text-align: center;
  min-height: 17px; margin-top: 12px; font-weight: 600;
  line-height: 1.45; overflow-wrap: anywhere;
}
.message-retour.erreur { color: var(--danger); }
.separateur { border: none; border-top: 1px solid var(--trait); margin: 20px 0 16px; }
.sous-liste-titre {
  font-size: var(--t-11); font-weight: 700; color: var(--texte-doux);
  text-transform: uppercase; letter-spacing: .07em; margin-bottom: 10px;
}

.bouton {
  padding: 12px 16px; border-radius: var(--r-sm); border: 1px solid var(--accent);
  background: var(--accent); color: var(--accent-contraste);
  font-size: var(--t-13); font-weight: 650; cursor: pointer; width: 100%;
  margin-top: 4px; transition: background var(--vite), transform var(--vite);
}
.bouton:hover { background: var(--accent-fort); }
.bouton:active { transform: scale(.98); }
.bouton.secondaire {
  background: var(--surface-douce); border-color: var(--trait); color: var(--texte);
}
.bouton.secondaire:hover { background: var(--surface-creuse); border-color: var(--trait-fort); }

/* Toute la maison en vitesse lente : ça se voit, et ça se coupe d'ici. */
.bandeau-silencieux {
  position: fixed; left: 50%; top: calc(var(--haut-sur) + 8px); z-index: 24;
  transform: translateX(-50%); display: flex; align-items: center; gap: 12px;
  max-width: calc(100vw - 32px); padding: 8px 10px 8px 16px;
  background: var(--surface); border: 1px solid var(--trait); border-left: 4px solid var(--alerte);
  box-shadow: var(--ombre-2); border-radius: var(--r-pilule);
  font-size: var(--t-13); color: var(--texte);
}
.bandeau-silencieux[hidden] { display: none; }
.bandeau-silencieux button {
  border: 1px solid var(--trait); background: var(--surface-douce); color: var(--texte);
  font: inherit; font-size: var(--t-12); padding: 6px 12px; border-radius: var(--r-pilule); cursor: pointer;
}
.bandeau-silencieux button:hover { background: var(--surface-creuse); }

/* Vérification des détecteurs : bouton dans le titre, et le relevé en
   direct de ceux qui se sont manifestés. */
.securite-titre .bouton-verifier {
  width: auto; margin: 0 0 0 12px; padding: 6px 12px; font-size: var(--t-12); vertical-align: middle;
}
.securite-titre .bouton-verifier.actif { background: var(--alerte-doux); border-color: var(--alerte); }
.verification-detecteurs {
  margin: 10px 0 14px; padding: 12px 14px; font-size: var(--t-13);
  background: var(--surface); border: 1px solid var(--trait); border-left: 4px solid var(--alerte);
  border-radius: var(--r-md);
}
.verification-detecteurs[hidden] { display: none; }
.verification-titre { margin-bottom: 8px; }
.verification-pied { margin-top: 8px; color: var(--texte-doux); font-size: var(--t-12); }
.ligne-verification {
  display: flex; align-items: center; gap: 10px; padding: 5px 0;
  border-top: 1px solid var(--trait);
}
.ligne-verification.vue { color: var(--accent-fort); font-weight: 650; }
.verification-heure { margin-left: auto; color: var(--texte-doux); font-weight: 400; }
.tuile-test { margin-top: 4px; font-size: var(--t-12); color: var(--texte-doux); }
.tuile-test.test-vu { color: var(--accent-fort); font-weight: 650; }

/* Grille de mesures (borne de recharge, compteur) */
.grille-borne {
  display: grid; grid-template-columns: 1fr 1fr; gap: 2px; margin-top: 18px;
  border: 1px solid var(--trait); border-radius: var(--r-sm); overflow: hidden;
  background: var(--trait);
}
.grille-borne > div {
  font-size: var(--t-15); font-weight: 650; background: var(--surface-douce);
  padding: 11px 13px; font-variant-numeric: tabular-nums;
}
.etiquette-borne {
  display: block; font-size: var(--t-11); font-weight: 600; color: var(--texte-doux);
  text-transform: uppercase; letter-spacing: .05em; margin-bottom: 3px;
}

/* Historique d'une borne, dans sa fiche */
.historique-borne { margin-top: 6px; font-size: var(--t-12); color: var(--texte-doux); }
.graphe-borne { display: block; width: 100%; height: auto; margin: 2px 0 8px; }
.graphe-borne-titre { font-size: var(--t-11); font-weight: 600; color: var(--texte-doux); margin-top: 8px; }
.graphe-borne-grille { stroke: var(--trait); stroke-width: 1; }
.graphe-borne-axe { font-size: var(--t-9); fill: var(--texte-faible); }
.graphe-borne-valeur { font-size: var(--t-9); font-weight: 600; fill: var(--texte-doux); }
.graphe-borne-barre { fill: var(--accent); opacity: .85; }

/* Mode silencieux */
.ligne-valeur-geante { display: flex; align-items: center; margin: 4px 0 2px; }
.ligne-valeur-geante .valeur-geante { margin: 0; flex: 1; text-align: center; }
.ligne-valeur-geante-espace, .colonne-silencieux { flex: 0 0 auto; width: 48px; }
.colonne-silencieux { display: flex; flex-direction: column; align-items: center; gap: 5px; }
.etiquette-silencieux { font-size: var(--t-10); font-weight: 600; color: var(--texte-doux); }
.bouton-silencieux {
  width: 46px; height: 46px; border-radius: 14px; cursor: pointer;
  background: var(--surface-douce); border: 1px solid var(--trait); color: var(--texte-doux);
  display: flex; align-items: center; justify-content: center;
  transition: background var(--vite), color var(--vite), border-color var(--vite), transform var(--vite);
}
.bouton-silencieux:hover { background: var(--surface-creuse); color: var(--texte); }
.bouton-silencieux:active { transform: scale(.94); }
.bouton-silencieux.actif {
  background: var(--accent); border-color: var(--accent); color: var(--accent-contraste);
}

/* ============================================================
   PAGE MÉTÉO
   ============================================================ */
.page-meteo {
  position: fixed; inset: 0; z-index: 4;
  padding: calc(16px + var(--haut-sur)) 26px calc(104px + env(safe-area-inset-bottom));
  overflow-y: auto; display: none;
}
.page-meteo.visible { display: block; }
.page-meteo-contenu { max-width: var(--largeur-max); margin: 0 auto; }

.meteo-vide {
  padding: 40px 0; text-align: center; color: var(--texte-doux);
  font-size: var(--t-13); line-height: 1.6;
}

/* Seul le haut de la page se lit en deux colonnes : la prévision du
   moment à gauche, les mesures de la maison à droite. La timeline et les
   jours à venir reprennent ensuite toute la largeur. */
.meteo-colonnes {
  display: grid; align-items: start;
  grid-template-columns: minmax(260px, 380px) 1px minmax(0, 1fr);
  gap: 0 22px; margin-bottom: 4px;
}
.meteo-colonnes > * { min-width: 0; }
.meteo-filet { background: var(--trait); align-self: stretch; width: 1px; opacity: .7; }
.meteo-etiquette-zone {
  font-size: var(--t-11); font-weight: 650; letter-spacing: .04em;
  color: var(--texte-faible); margin-bottom: 8px; line-height: 1.3;
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
}
/* Ce que racontent les courbes des blocs, dit une fois au-dessus d'eux
   plutôt que répété sur chacun -- il n'y a pas la place sur une tuile de
   80 px, et la mention serait huit fois la même. */
.etiquette-historique {
  font-weight: 500; letter-spacing: .02em; text-transform: none;
  color: var(--texte-faible); opacity: .8;
}
.etiquette-historique::before { content: "· "; }

.meteo-maintenant { margin-bottom: 18px; }
.meteo-maintenant > * { min-width: 0; }
.meteo-carte {
  background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r-lg); box-shadow: var(--ombre-1); padding: 18px 20px;
}
.meteo-actuel { display: flex; align-items: center; gap: 18px; }
.meteo-actuel .symbole { width: 62px; height: 62px; flex-shrink: 0; }
.meteo-actuel .symbole svg { width: 100%; height: 100%; }
.meteo-degres {
  font-size: var(--t-40); font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
}
.meteo-libelle { font-size: var(--t-13); color: var(--texte-doux); margin-top: 4px; line-height: 1.35; }
.meteo-detail-ligne {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
  gap: 12px 10px; margin-top: 18px; padding-top: 16px;
  border-top: 1px solid var(--trait);
}
.meteo-detail {
  min-width: 0; display: flex; flex-direction: column; gap: 3px;
}
.meteo-detail .etiquette {
  font-size: var(--t-10); font-weight: 650; letter-spacing: .05em;
  text-transform: uppercase; color: var(--texte-faible);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.meteo-detail .mesure {
  font-size: var(--t-15); font-weight: 700; line-height: 1.1;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.meteo-detail .mesure small {
  font-size: var(--t-11); font-weight: 600; color: var(--texte-doux);
  display: block; margin-top: 2px;
}

/* Grille à cases : chaque bloc occupe une case précise, et les cases
   vides restent vides -- on peut donc laisser des trous en déplaçant
   les blocs, au lieu de les voir se retasser. */
.meteo-capteurs {
  display: grid; gap: 12px; align-content: start;
  grid-template-columns: repeat(var(--colonnes-meteo, 2), minmax(0, 1fr));
  grid-template-rows: repeat(var(--lignes-meteo, 1), var(--hauteur-bloc-meteo, 124px));
  grid-auto-rows: var(--hauteur-bloc-meteo, 124px);
}
.meteo-capteur {
  background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r-md); box-shadow: var(--ombre-1);
  padding: 13px 14px; min-width: 0; overflow: hidden;
  /* Six pixels et non huit : la courbe des 24 h a pris la place du nom
     de la pièce, et un nom sur deux lignes débordait de quatre pixels. */
  display: flex; flex-direction: column; gap: 6px;
  position: relative;   /* la croix de retrait du mode disposition s'y accroche */
}
.meteo-capteur-haut {
  display: flex; align-items: center; gap: 9px; min-width: 0;
}
.meteo-capteur .chip-icone { width: 28px; height: 28px; border-radius: 8px; flex-shrink: 0; }
.meteo-capteur-nom {
  font-size: var(--t-13); font-weight: 650; line-height: 1.25;
  min-width: 0; overflow-wrap: anywhere;
}
.meteo-capteur-valeur {
  font-size: var(--t-21); font-weight: 700; font-variant-numeric: tabular-nums;
  line-height: 1.1; letter-spacing: -0.02em; margin-top: auto;
}
/* Sans courbe (un bloc qui n'en a pas), la valeur reste collée en bas
   comme avant : c'est la marge automatique de l'un ou de l'autre. */
.meteo-capteur-courbe:empty { margin-top: 0; height: 0; min-height: 0; }
/* Les 24 dernières heures, sous la valeur. Le tracé s'étire sur toute
   la largeur du bloc et prend la couleur de sa catégorie ; l'aire en
   dessous, très pâle, donne le volume sans attirer l'œil. */
.meteo-capteur-courbe {
  margin-top: auto; height: 22px; min-height: 22px; line-height: 0;
}
.meteo-capteur-courbe svg { width: 100%; height: 22px; display: block; overflow: visible; }
.meteo-capteur-courbe .trace {
  fill: none; stroke: var(--cat, var(--cat-autres)); stroke-width: 1.5px;
  stroke-linejoin: round; stroke-linecap: round;
}
.meteo-capteur-courbe .aire { fill: var(--cat, var(--cat-autres)); opacity: .12; stroke: none; }
.meteo-capteur-courbe .tete { fill: var(--cat, var(--cat-autres)); stroke: none; }
/* La moitié droite : ce qui est annoncé, pas mesuré. Pointillés, aplat
   plus pâle -- on doit voir au premier coup d'œil où finit le certain. */
.meteo-capteur-courbe .trace-prevue {
  fill: none; stroke: var(--cat, var(--cat-autres)); stroke-width: 1.5px;
  stroke-dasharray: 2.6 2.4; opacity: .8;
  stroke-linejoin: round; stroke-linecap: round;
}
.meteo-capteur-courbe .aire-prevue { fill: var(--cat, var(--cat-autres)); opacity: .05; stroke: none; }
.meteo-capteur-courbe .repere-maintenant {
  stroke: var(--texte-faible); stroke-width: 1px; stroke-dasharray: 1.5 2; opacity: .45;
}
/* En mode disposition seulement : les blocs se glissent pour changer
   d'ordre, et chacun porte sa croix de retrait. */
.meteo-capteurs.reorganisable .meteo-capteur {
  cursor: grab; touch-action: none;
  border-style: dashed; border-color: var(--edition, var(--accent));
}
.meteo-capteurs.reorganisable .meteo-capteur.en-deplacement {
  cursor: grabbing; opacity: .8; z-index: 5; box-shadow: var(--ombre-2, var(--ombre-1));
}
/* Case visée pendant le glissement : un liseré pour montrer où le bloc
   va se poser, y compris sur une case vide. */
.meteo-case-visee {
  border: 1.5px dashed var(--edition, var(--accent)); border-radius: var(--r-md);
  opacity: .55; pointer-events: none;
}
/* Lecteur vidéo : le flux arrive en 16/9, on lui réserve sa place pour
   que la fenêtre ne saute pas quand l'image apparaît. */
.cadre-video {
  position: relative; width: 100%; aspect-ratio: 16 / 9;
  background: #000; border-radius: var(--r-md); overflow: hidden;
}
.cadre-video video { width: 100%; height: 100%; object-fit: contain; display: block; }
.video-etat {
  position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; text-align: center; padding: 16px;
  color: var(--texte-doux); font-size: var(--t-13); line-height: 1.5;
  background: rgba(0, 0, 0, .55); pointer-events: none;
}
.video-etat:empty { display: none; }
/* L'image d'une détection vient se poser par-dessus le direct, dans le
   même cadre : on regarde ce qui s'est passé sans quitter la caméra. */
.image-detection {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; background: #000; display: none;
}
.image-detection.visible { display: block; }
.retour-direct {
  position: absolute; left: 10px; top: 10px; z-index: 2;
  border: 1px solid rgba(255, 255, 255, .28); border-radius: 999px;
  background: rgba(0, 0, 0, .55); color: #fff; cursor: pointer;
  font: inherit; font-size: var(--t-12); font-weight: 650; padding: 6px 13px;
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
}
.retour-direct[hidden] { display: none; }
.retour-direct:hover { background: rgba(0, 0, 0, .72); }

/* ===== Ce que la caméra a vu =====
   Une bande d'images sous le direct, la plus récente à gauche. Chacune
   dit ce que la caméra a reconnu -- personne, animal, véhicule -- parce
   que c'est elle qui fait l'analyse, à bord. */
.frise-detections { margin-top: 14px; }
.frise-detections:empty { display: none; }
.frise-titre {
  font-size: var(--t-11); font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--texte-faible); margin-bottom: 8px;
}
.frise-bande {
  display: flex; gap: 10px; overflow-x: auto; padding-bottom: 6px;
  scroll-snap-type: x proximity;
}
.frise-vue {
  flex: 0 0 auto; width: 132px; scroll-snap-align: start; cursor: pointer;
  border: 1px solid var(--trait); border-radius: var(--r-md); overflow: hidden;
  background: var(--surface-douce); padding: 0; text-align: left;
  font: inherit; color: var(--texte);
  transition: border-color var(--vite), transform var(--vite);
}
.frise-vue:hover { border-color: var(--trait-fort); }
.frise-vue:active { transform: scale(.97); }
.frise-vue.active { border-color: var(--accent); }
/* Pastille « séquence filmée », posée sur le coin de la vignette. */
.frise-vue { position: relative; }
.frise-video {
  position: absolute; top: 6px; right: 6px; z-index: 1;
  display: flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%;
  background: rgba(20, 18, 16, .66); color: #fff; font-size: 11px; line-height: 1;
  backdrop-filter: blur(2px);
}
.frise-video.enregistre { color: var(--danger); }
/* Médaillon du visage reconnu, posé en bas à gauche de la vignette. */
.frise-visage {
  position: absolute; left: 6px; bottom: 44px; z-index: 1;
  width: 30px; height: 30px; border-radius: 50%; object-fit: cover;
  border: 2px solid var(--succes); background: var(--surface);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .35);
}
.frise-visage.inconnu { border-color: var(--alerte); }
.frise-quoi.reconnu { color: var(--succes); }
/* Les visages mémorisés par la caméra, en bas de la fiche. */
.frise-bande.visages { gap: 14px; }
.visage-fiche { flex: 0 0 auto; width: 74px; text-align: center; }
.visage-photo {
  width: 58px; height: 58px; border-radius: 50%; object-fit: cover; margin: 0 auto 6px;
  display: block; border: 2px solid var(--succes); background: var(--surface-douce);
}
.visage-photo.sans {
  display: flex; align-items: center; justify-content: center; color: var(--texte-faible); padding: 12px;
}
.visage-photo.sans svg { width: 100%; height: 100%; }
.visage-photo.inconnu { border-color: var(--alerte); }
.visage-nom { font-size: var(--t-11); font-weight: 650; line-height: 1.25; }
.visage-nom.inconnu { color: var(--alerte); }
.frise-quoi.inconnu { color: var(--alerte); }
.frise-vue .vignette {
  width: 100%; aspect-ratio: 16 / 9; object-fit: cover; display: block;
  background: var(--surface-creuse);
}
.frise-vue .vignette-absente {
  width: 100%; aspect-ratio: 16 / 9; display: flex; align-items: center;
  justify-content: center; background: var(--surface-creuse); color: var(--texte-faible);
}
.frise-vue .vignette-absente svg { width: 22px; height: 22px; }
.frise-legende { padding: 7px 9px 8px; }
.frise-quoi {
  display: flex; align-items: center; gap: 5px;
  font-size: var(--t-12); font-weight: 700;
}
.frise-quoi svg { width: 14px; height: 14px; flex-shrink: 0; }
.frise-quoi.personne { color: var(--danger); }
.frise-quoi.animal   { color: var(--cat-eclairage); }
.frise-quoi.vehicule { color: var(--accent); }
.frise-quoi.mouvement { color: var(--texte-doux); }
.frise-quand {
  font-size: var(--t-11); font-weight: 600; color: var(--texte-faible);
  font-variant-numeric: tabular-nums; margin-top: 2px;
}
.frise-vide, .frise-echec {
  font-size: var(--t-12); color: var(--texte-faible); padding: 4px 0;
}

.meteo-case-vide {
  border: 1px dashed var(--trait); border-radius: var(--r-md);
  pointer-events: none; opacity: .55;
}
/* La croix se place À L'INTÉRIEUR du bloc : celui-ci masque ce qui
   dépasse (il tient dans une case de hauteur fixe), et une croix posée
   sur le bord se retrouvait coupée en deux. */
.meteo-capteur-retirer {
  position: absolute; top: 5px; right: 5px; width: 21px; height: 21px;
  display: none; align-items: center; justify-content: center;
  border-radius: 50%; border: 1px solid var(--trait);
  background: var(--surface-creuse); color: var(--danger);
  font-size: var(--t-15); line-height: 1; cursor: pointer; padding: 0;
}
.meteo-capteurs.reorganisable .meteo-capteur-retirer { display: flex; }
/* Le nom se retire pour ne pas passer sous la croix. */
.meteo-capteurs.reorganisable .meteo-capteur-haut { padding-right: 22px; }
/* Blocs étroits (iPhone : huit blocs sur deux lignes, ça fait quatre
   colonnes de 80 px). À cette largeur, l'icône et le nom côte à côte ne
   laissent au nom que quelques pixels, et « overflow-wrap: anywhere »
   le débitait alors une lettre par ligne, en poussant la valeur hors du
   bloc. On empile donc : l'icône sur sa ligne, le nom en dessous sur
   toute la largeur, la valeur en bas. Le nom est abrégé et coupé à deux
   lignes ; son intitulé complet reste dans l'infobulle. */
.meteo-capteurs.compact .meteo-capteur { padding: 8px 9px; gap: 4px; }
.meteo-capteurs.compact .meteo-capteur-haut {
  flex-direction: column; align-items: stretch; gap: 4px; padding-right: 0;
}
.meteo-capteurs.compact .meteo-capteur .chip-icone { width: 24px; height: 24px; border-radius: 7px; }
.meteo-capteurs.compact .meteo-capteur .chip-icone svg { width: 14px; height: 14px; }
.meteo-capteurs.compact .meteo-capteur-nom {
  font-size: var(--t-11); line-height: 1.2; overflow-wrap: break-word; hyphens: auto;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* Une seule ligne pour la valeur : « 1013 hPa » passé à la ligne
   poussait la pièce hors du bloc. La taille est ensuite rabotée juste
   ce qu'il faut pour que le relevé tienne, jamais en dessous de 10 px. */
.meteo-capteurs.compact .meteo-capteur-valeur {
  font-size: var(--t-17); letter-spacing: -0.01em; white-space: nowrap;
}
.meteo-capteurs.compact .meteo-capteur-courbe { height: 18px; min-height: 18px; }
.meteo-capteurs.compact .meteo-capteur-courbe svg { height: 18px; }
/* La croix se pose au-dessus de l'icône, jamais sur le nom : le nom
   commence plus bas que là où elle s'arrête. */
.meteo-capteurs.compact .meteo-capteur-retirer { top: 4px; right: 4px; width: 20px; height: 20px; }
/* Encore plus étroit : la valeur descend d'un cran pour qu'un relevé à
   quatre chiffres avec son unité tienne toujours sur une ligne. La pièce
   reste affichée -- c'est elle qui dit de quelle température on parle. */
.meteo-capteurs.tres-compact .meteo-capteur-valeur { font-size: var(--t-15); }

.meteo-aide-blocs {
  font-size: var(--t-11); line-height: 1.45; color: var(--edition, var(--accent));
  margin: -2px 0 10px;
}

.meteo-titre-section {
  font-size: var(--t-11); font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--texte-faible);
  margin: 22px 0 10px;
}

/* Le bouton du radar vit juste sous la tuile principale, calé à droite :
   il prolonge la lecture du temps qu'il fait sans couper la page. */
.ligne-radar { display: flex; justify-content: flex-end; margin: -8px 0 4px; }
/* Deux fois plus haut qu'un simple bouton : la place d'y montrer un
   morceau de radar en couleur. Le mot « Radar » suffit à côté. */
.bouton-radar {
  display: inline-flex; align-items: center; gap: 11px; margin-left: auto;
  height: 56px; border: 1px solid var(--trait); background: var(--surface);
  color: var(--texte); border-radius: 16px; padding: 5px 16px 5px 5px;
  font: inherit; font-size: var(--t-13); font-weight: 700; cursor: pointer;
  transition: background var(--vite), color var(--vite), border-color var(--vite);
}
.apercu-radar {
  position: relative; width: 66px; height: 46px; flex: none;
  border-radius: 12px; overflow: hidden; background: var(--surface-creuse);
  display: flex; align-items: center; justify-content: center;
}
.apercu-radar canvas { width: 100%; height: 100%; display: none; }
.apercu-radar.prete canvas { display: block; }
.apercu-radar.prete .icone-radar { display: none; }
.apercu-radar .icone-radar { width: 20px; height: 20px; color: var(--texte-faible); }
.bouton-radar:hover { background: var(--surface-creuse); border-color: var(--trait-fort); }
.bouton-radar:active { transform: scale(.97); }

/* --- Les heures qui viennent, en bande défilante --- */
.meteo-heures {
  display: flex; gap: 8px; overflow-x: auto; padding-bottom: 6px;
  scroll-snap-type: x proximity;
}
.meteo-heure {
  flex: 0 0 auto; width: 68px; scroll-snap-align: start;
  background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r-md); padding: 10px 6px; text-align: center;
  cursor: pointer; transition: border-color var(--vite), background var(--vite);
}
.meteo-heure:hover { border-color: var(--trait-fort); }
.meteo-heure.maintenant { border-color: var(--accent); }
/* La case dont on regarde le détail en haut : nettement marquée, pour
   qu'on sache à quoi se rapporte la grande carte. */
.meteo-heure.examinee {
  border-color: var(--accent); background: var(--accent-doux);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.meteo-heure-examinee {
  display: inline-flex; align-items: center; gap: 4px; max-width: 100%;
  padding: 2px 4px 2px 9px; border-radius: 999px; white-space: nowrap;
  background: var(--accent-doux); color: var(--accent);
  font-size: var(--t-11); font-weight: 700; text-transform: capitalize;
}
.meteo-retour-maintenant {
  background: transparent; border: none; color: inherit; cursor: pointer;
  font-size: var(--t-15); line-height: 1; padding: 0 3px; opacity: .8;
}
.meteo-retour-maintenant:hover { opacity: 1; }
.meteo-heure .quand { font-size: var(--t-11); font-weight: 650; color: var(--texte-doux); }
.meteo-heure .symbole { height: 26px; margin: 5px 0 3px; }
.meteo-heure .symbole svg { width: 24px; height: 24px; }
.meteo-heure .degres {
  font-size: var(--t-15); font-weight: 700; font-variant-numeric: tabular-nums;
  line-height: 1.15;
}
/* Le ressenti sous la température, en plus petit : c'est une précision,
   pas la mesure principale. La main reste grise quelle que soit la
   couleur du chiffre, qui suit la température. */
.meteo-heure .ressenti {
  display: flex; align-items: center; justify-content: center; gap: 3px;
  font-size: var(--t-13); font-weight: 700; font-variant-numeric: tabular-nums;
  line-height: 1.2; margin-top: 2px; min-height: 18px;
}
.main-ressenti { width: 14px; height: 14px; flex: none; color: var(--texte-faible); }
.meteo-heure .pluie {
  font-size: var(--t-11); font-weight: 600; margin-top: 3px;
  color: var(--cat-meteo); min-height: 14px;
}
.meteo-heure .pluie:empty::after { content: "\00a0"; }
.meteo-heure .uv {
  margin-top: 5px; font-size: var(--t-10); font-weight: 700; letter-spacing: .02em;
  border-radius: 999px; padding: 2px 0; min-height: 16px;
  background: var(--surface-creuse); color: var(--texte-faible);
}
.meteo-heure .uv:empty { background: none; }
.meteo-heure .uv:empty::after { content: "\00a0"; }
.uv-faible  { background: rgba(61, 148, 84, .16)  !important; color: #3D9454 !important; }
.uv-modere  { background: rgba(197, 160, 18, .18) !important; color: #A88A10 !important; }
.uv-fort    { background: rgba(198, 118, 32, .18) !important; color: #C67620 !important; }
.uv-tresfort{ background: rgba(199, 62, 62, .16)  !important; color: #C73E3E !important; }
.uv-extreme { background: rgba(140, 86, 184, .18) !important; color: #8C56B8 !important; }

/* --- Les jours : une barre de température par jour --- */
.meteo-jour {
  display: grid; grid-template-columns: 92px 34px minmax(0, 1fr) 54px;
  align-items: center; gap: 12px; padding: 11px 4px;
  border-bottom: 1px solid var(--trait);
  width: 100%; background: none; border-left: 0; border-right: 0; border-top: 0;
  color: inherit; font: inherit; text-align: left; cursor: pointer;
  border-radius: var(--r-sm); transition: background var(--vite);
}
.meteo-jour:hover { background: var(--surface-creuse); }
.meteo-jour.choisi { background: var(--cat-meteo-fond); }
.meteo-jour.choisi .date { color: var(--cat-meteo); }
.meteo-jour:last-child { border-bottom: none; }
.meteo-jour .date { font-size: var(--t-13); font-weight: 650; }
.meteo-jour .date span { display: block; font-size: var(--t-11); font-weight: 500; color: var(--texte-doux); }
/* Confiance : lisible d'un coup d'œil, discrète tant qu'elle est bonne. */
.confiance-jour {
  display: inline-block !important; margin-left: 5px; padding: 0 5px;
  border-radius: 999px; font-size: var(--t-10); font-weight: 700;
  background: var(--surface-creuse); color: var(--texte-faible);
  vertical-align: 1px;
}
.confiance-jour.bonne   { background: rgba(61, 148, 84, .16);  color: #3D9454; }
.confiance-jour.moyenne { background: rgba(197, 160, 18, .18); color: #A88A10; }
.confiance-jour.faible  { background: rgba(199, 62, 62, .16);  color: #C73E3E; }
.valeur-geante.alarme { color: var(--danger); }
.bouton-action.danger { color: var(--danger); border-color: var(--danger); }
.meteo-jour .symbole { line-height: 0; }
.meteo-jour .symbole svg { width: 26px; height: 26px; }
.meteo-jour .pluie-jour {
  font-size: var(--t-11); font-weight: 600; color: var(--cat-meteo); text-align: right;
}
.uv-jour {
  display: block; margin-top: 4px; border-radius: 999px; padding: 1px 6px;
  font-size: var(--t-10); font-weight: 700; background: var(--surface-creuse);
  color: var(--texte-faible);
}
.barre-temperature {
  position: relative; height: 6px; border-radius: 999px;
  background: var(--surface-creuse); overflow: hidden;
}
.barre-temperature i {
  position: absolute; top: 0; bottom: 0; border-radius: 999px;
  background: linear-gradient(90deg, var(--cat-meteo), var(--cat-eclairage));
}
.meteo-bornes {
  display: flex; justify-content: space-between; font-size: var(--t-11);
  color: var(--texte-doux); margin-top: 3px; font-variant-numeric: tabular-nums;
}
.meteo-source {
  margin-top: 18px; font-size: var(--t-11); color: var(--texte-faible); line-height: 1.6;
}

@media (max-width: 820px) {
  .page-meteo { padding: calc(14px + var(--haut-sur)) 16px calc(96px + env(safe-area-inset-bottom)); }
  /* Trop étroit pour deux colonnes : elles s'empilent et le filet
     devient la ligne horizontale qui les sépare. */
  .meteo-colonnes { grid-template-columns: 1fr; gap: 0; }
  .meteo-filet { width: auto; height: 1px; margin: 22px 0 18px; }
  .meteo-jour { grid-template-columns: 76px 28px minmax(0, 1fr) 48px; gap: 8px; }
}

/* ============================================================
   PAGE GRAPHIQUES
   ============================================================ */
.page-graphiques {
  position: fixed; inset: 0; z-index: 4;
  padding: calc(58px + var(--haut-sur)) 26px 96px; overflow: hidden; display: none;
}
.page-graphiques.visible { display: block; }
.page-graphiques-contenu {
  max-width: var(--largeur-max); margin: 0 auto; height: 100%;
  display: flex; flex-direction: column;
}

.selecteur-courbes {
  pointer-events: auto;
  position: absolute; left: 50%; transform: translateX(-50%);
  display: none; width: min(430px, calc(100% - 220px)); margin: 0;
}
.selecteur-courbes.actif-page { display: flex; align-items: center; gap: 8px; }
/* À droite du sélecteur : tout remettre à zéro -- plus aucune courbe,
   et la période revient à aujourd'hui. Grisé quand il n'y a rien à
   remettre. */
.bouton-reset-courbes {
  flex: none; width: 42px; height: 42px; border-radius: 50%;
  background: var(--surface); border: 1px solid var(--trait); box-shadow: var(--ombre-1);
  display: flex; align-items: center; justify-content: center;
  color: var(--texte-doux); cursor: pointer;
  transition: background var(--vite), color var(--vite), border-color var(--vite), transform var(--vite);
}
.bouton-reset-courbes:hover:not(:disabled) { background: var(--surface-survol); border-color: var(--trait-fort); color: var(--texte); }
.bouton-reset-courbes:active:not(:disabled) { transform: scale(.94); }
.bouton-reset-courbes:disabled { opacity: .45; cursor: default; }
.bouton-selecteur-courbes {
  flex: 1; min-width: 0; display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 11px 16px; background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r-pilule); box-shadow: var(--ombre-1);
  color: var(--texte); font-size: var(--t-13); font-weight: 600; cursor: pointer;
}
.bouton-selecteur-courbes:hover { border-color: var(--trait-fort); }
.bouton-selecteur-courbes .puces-resume { display: flex; gap: 4px; }
.bouton-selecteur-courbes .puces-resume span { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.chevron-selecteur { transition: transform var(--vite); flex-shrink: 0; }
.selecteur-courbes.ouvert .chevron-selecteur { transform: rotate(180deg); }

.titre-groupe-courbes {
  padding: 10px 12px 4px; font-size: var(--t-11); font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--texte-faible);
}
.titre-groupe-courbes:first-child { padding-top: 4px; }

.menu-choix-courbes {
  position: absolute; top: calc(100% + 8px); left: 50%; transform: translateX(-50%);
  width: 330px; max-width: calc(100vw - 32px); z-index: 30;
  max-height: min(430px, 70vh); overflow-y: auto;
  background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r-md); padding: 7px; box-shadow: var(--ombre-3); display: none;
}
.selecteur-courbes.ouvert .menu-choix-courbes { display: block; }
.case-courbe {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border-radius: var(--r-xs); cursor: pointer; color: var(--texte);
  font-size: var(--t-13); font-weight: 500; user-select: none; text-align: left;
}
.case-courbe:hover { background: var(--surface-creuse); }
.case-courbe.desactivee { opacity: .38; cursor: not-allowed; }
.case-a-cocher {
  width: 18px; height: 18px; border-radius: 6px; flex-shrink: 0;
  border: 1.5px solid var(--trait-fort);
  display: flex; align-items: center; justify-content: center;
}
.case-courbe.selectionnee .case-a-cocher {
  background: var(--couleur-courbe, var(--accent)); border-color: var(--couleur-courbe, var(--accent));
}
.case-a-cocher svg { display: none; width: 12px; height: 12px; color: #FFF; }
.case-courbe.selectionnee .case-a-cocher svg { display: block; }
.puce-courbe {
  width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0;
  background: var(--couleur-courbe, var(--trait-fort));
}
.case-courbe input { display: none; }

.barre-navigation-periode { display: flex; align-items: center; gap: 10px; margin: 0 0 8px; flex-shrink: 0; }
.barre-navigation-periode .selecteur-periode { flex: 1; margin: 0; }
.bouton-flèche-periode {
  width: 42px; height: 42px; border-radius: var(--r-sm); flex-shrink: 0;
  background: var(--surface); border: 1px solid var(--trait); color: var(--texte);
  font-size: var(--t-17); cursor: pointer; display: flex; align-items: center; justify-content: center;
  box-shadow: var(--ombre-1); transition: background var(--vite);
}
.bouton-flèche-periode:hover { background: var(--surface-survol); }
.bouton-flèche-periode:disabled { opacity: .35; cursor: not-allowed; }
.etiquette-periode-actuelle {
  display: block; margin: 0 auto 14px; flex-shrink: 0;
  background: none; border: 1px solid transparent; cursor: pointer;
  padding: 5px 14px; border-radius: var(--r-pilule);
  color: var(--texte); font-family: inherit;
  text-align: center; font-size: var(--t-15); font-weight: 650; letter-spacing: -0.01em;
}
.etiquette-periode-actuelle:hover { border-color: var(--trait); background: var(--surface); }
.etiquette-periode-actuelle::after {
  content: ""; display: inline-block; vertical-align: middle;
  margin-left: 8px; width: 7px; height: 7px; border-right: 2px solid var(--texte-doux);
  border-bottom: 2px solid var(--texte-doux); transform: translateY(-2px) rotate(45deg);
}

/* ---- Calendrier de sélection de période ---- */
.voile-calendrier {
  position: fixed; inset: 0; z-index: 60; display: none;
  background: rgba(0, 0, 0, .45); backdrop-filter: blur(2px);
}
.voile-calendrier.visible { display: block; }
.calendrier-periode {
  position: fixed; z-index: 61; display: none;
  left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(340px, calc(100vw - 32px));
  background: var(--surface-haute, var(--surface)); border: 1px solid var(--trait);
  border-radius: var(--r-lg); box-shadow: var(--ombre-3); padding: 14px;
}
.calendrier-periode.visible { display: block; }

/* Période libre : deux champs de date, quelques raccourcis */
.boite-plage {
  position: fixed; z-index: 61; display: none;
  left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(380px, calc(100vw - 32px));
  padding: 20px; border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--trait); box-shadow: var(--ombre-3);
}
.boite-plage.visible { display: block; }
.boite-plage h3 { margin: 0 0 14px; font-size: var(--t-15); font-weight: 700; }
.boite-plage input[type="date"] {
  width: 100%; padding: 10px 11px; border-radius: var(--r-xs);
  border: 1px solid var(--trait-fort); background: var(--surface-douce);
  color: var(--texte); font-size: var(--t-13); font-family: inherit;
}
.raccourcis-plage { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.raccourcis-plage button {
  padding: 6px 10px; border-radius: 999px; cursor: pointer; font-size: var(--t-12); font-weight: 600;
  background: var(--surface-douce); border: 1px solid var(--trait); color: var(--texte-doux);
}
.raccourcis-plage button:hover { border-color: var(--trait-fort); color: var(--texte); }
.erreur-plage { color: var(--cat-securite); font-size: var(--t-13); min-height: 17px; margin-top: 10px; }
.boutons-plage { display: flex; gap: 8px; }
.boutons-plage .bouton { margin-top: 0; }
.calendrier-tete {
  display: flex; align-items: center; gap: 8px; margin-bottom: 12px;
}
.calendrier-tete .titre-calendrier {
  flex: 1; text-align: center; font-size: var(--t-15); font-weight: 700;
  background: none; border: none; color: var(--texte); font-family: inherit;
  padding: 6px 8px; border-radius: var(--r-sm); cursor: default;
}
.calendrier-tete .titre-calendrier.cliquable { cursor: pointer; }
.calendrier-tete .titre-calendrier.cliquable:hover { background: var(--surface-creuse); }
.calendrier-fleche {
  width: 32px; height: 32px; flex-shrink: 0; display: flex;
  align-items: center; justify-content: center;
  background: var(--surface-creuse); border: 1px solid var(--trait);
  border-radius: 50%; color: var(--texte); font-size: var(--t-15); cursor: pointer;
}
.calendrier-fleche:hover { border-color: var(--trait-fort); }
.calendrier-fleche:disabled { opacity: .3; cursor: default; }
.calendrier-jours-entete {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; margin-bottom: 4px;
}
.calendrier-jours-entete span {
  text-align: center; font-size: var(--t-11); font-weight: 700; color: var(--texte-faible);
}
.calendrier-grille { display: grid; gap: 3px; }
.calendrier-grille.jours { grid-template-columns: repeat(7, 1fr); }
.calendrier-grille.mois  { grid-template-columns: repeat(3, 1fr); }
.calendrier-grille.annees { grid-template-columns: repeat(4, 1fr); }
.case-calendrier {
  background: none; border: 1px solid transparent; border-radius: var(--r-sm);
  color: var(--texte); font-family: inherit; font-size: var(--t-13); font-weight: 600;
  padding: 8px 0; cursor: pointer; text-align: center;
}
.calendrier-grille.mois .case-calendrier,
.calendrier-grille.annees .case-calendrier { padding: 12px 0; }
.case-calendrier:hover:not(:disabled) { background: var(--surface-creuse); }
.case-calendrier:disabled { opacity: .25; cursor: default; }
.case-calendrier.hors-mois { color: var(--texte-faible); }
.case-calendrier.aujourdhui { border-color: var(--trait-fort); }
.case-calendrier.choisie {
  background: var(--accent); border-color: var(--accent); color: var(--accent-contraste);
}
.calendrier-semaines { display: flex; flex-direction: column; gap: 4px; }
.ligne-semaine {
  display: flex; align-items: center; gap: 8px; width: 100%;
  background: none; border: 1px solid var(--trait); border-radius: var(--r-sm);
  color: var(--texte); font-family: inherit; font-size: var(--t-13); font-weight: 600;
  padding: 9px 12px; cursor: pointer; text-align: left;
}
.ligne-semaine:hover:not(:disabled) { background: var(--surface-creuse); }
.ligne-semaine:disabled { opacity: .3; cursor: default; }
.ligne-semaine.choisie {
  background: var(--accent); border-color: var(--accent); color: var(--accent-contraste);
}
.ligne-semaine .num-semaine {
  font-size: var(--t-11); font-weight: 700; opacity: .7; min-width: 34px;
}
.calendrier-pied {
  display: flex; justify-content: space-between; gap: 8px; margin-top: 12px;
}
.bouton-calendrier {
  flex: 1; padding: 9px 12px; border-radius: var(--r-sm);
  background: var(--surface-creuse); border: 1px solid var(--trait);
  color: var(--texte); font-family: inherit; font-size: var(--t-13); font-weight: 600; cursor: pointer;
}
.bouton-calendrier:hover { border-color: var(--trait-fort); }

.selecteur-periode {
  display: flex; gap: 4px; background: var(--surface-creuse);
  border-radius: var(--r-sm); padding: 4px; margin: 16px 0 20px;
}
.bouton-periode {
  flex: 1; padding: 9px 4px; border-radius: 9px; border: none;
  background: none; color: var(--texte-doux); font-size: var(--t-13); font-weight: 650;
  cursor: pointer; transition: background var(--vite), color var(--vite);
}
.bouton-periode:hover { color: var(--texte); }
.bouton-periode.actif { background: var(--surface); color: var(--texte); box-shadow: var(--ombre-1); }

.zone-graphique-page { position: relative; flex: 1; min-height: 0; touch-action: pan-y; }
/* Relecture déclenchée par un zoom : le graphique reste à l'écran, juste
   terni. Le vider puis le redessiner ferait clignoter toute la page. */
.zone-graphique-page.en-attente { opacity: .55; transition: opacity var(--moyen); }
/* Retour à la période entière, présent seulement quand on a zoomé. */
.bouton-tout-voir {
  display: none; align-items: center; gap: 6px;
  font: inherit; font-size: var(--t-12); font-weight: 600;
  color: var(--accent); background: var(--accent-doux);
  border: 0; border-radius: var(--r-pilule); padding: 5px 12px; cursor: pointer;
  transition: background var(--vite);
}
.bouton-tout-voir.visible { display: inline-flex; }
.bouton-tout-voir:hover { background: var(--surface-creuse); }
.zone-graphique-page canvas, .zone-graphique canvas { max-height: 100%; width: 100% !important; }
.zone-graphique { position: relative; height: 290px; }
.graphique-etat-vide {
  position: absolute; inset: 0; display: flex; align-items: center;
  justify-content: center; color: var(--texte-doux); font-size: var(--t-13); text-align: center;
}
.legende-courbes { display: flex; flex-wrap: wrap; gap: 14px; padding-top: 12px; flex-shrink: 0; }
.legende-item { display: flex; align-items: center; gap: 7px; font-size: var(--t-12); font-weight: 500; color: var(--texte-doux); }
.resume-graphique {
  display: flex; gap: 22px; margin-top: 18px; padding-top: 16px;
  border-top: 1px solid var(--trait); flex-wrap: wrap;
}
.resume-graphique > div { font-size: var(--t-12); color: var(--texte-doux); font-weight: 600; }
.resume-graphique .valeur-resume {
  font-size: var(--t-19); font-weight: 700; margin-top: 2px; color: var(--texte);
  font-variant-numeric: tabular-nums;
}

/* ============================================================
   MONITEUR DE FLUX D'ÉNERGIE
   ============================================================ */
.schema-flux { width: 100%; height: 320px; margin: 10px 0; }
/* Le moniteur de flux n'est pas une valeur dans un cadre : c'est un
   schéma. On lui retire donc l'habillage de tuile pour qu'il se
   présente comme un dessin posé sur la page. */
.tuile.tuile-nue {
  background: none; border-color: transparent; box-shadow: none; padding: 0;
  cursor: default;
}
.tuile.tuile-nue:hover { box-shadow: none; border-color: transparent; }
.tuile.tuile-nue:active { transform: none; }
.tuile.tuile-nue .tuile-haut { display: none; }
/* Le corps occupe toute la hauteur du cadre et le schéma s'y déploie :
   c'est la taille du cadre, réglée à la main, qui décide de la taille
   du dessin. */
.tuile.tuile-nue .tuile-corps { padding-top: 0; flex: 1; }
.schema-flux-mini .noeud-flux[data-detail] { cursor: pointer; }
.schema-flux-mini .noeud-flux[data-detail]:hover .noeud-cercle { stroke: var(--accent); }
.schema-flux-mini .noeud-flux[data-detail]:hover .noeud-pastille { fill: var(--accent-doux); }

.schema-flux-mini {
  /* La largeur est plafonnée plutôt que la hauteur : plafonner la
     hauteur laisserait le dessin flotter au milieu d'une boîte trop
     large au lieu de l'occuper. */
  width: 100%; height: 100%; display: block;
}
.tuile-corps .schema-flux-mini { flex-shrink: 0; }
/* Le schéma est dessiné dans un repère de ~430 unités réduit à moins de
   300 px : à taille égale, les libellés y seraient deux fois plus petits
   que dans la fenêtre agrandie. On les grossit donc dans le repère. */
.schema-flux-mini .noeud-titre { font-size: var(--t-21); font-weight: 600; }
.schema-flux-mini .noeud-valeur { font-size: var(--t-24); }
.schema-flux-mini .ligne-flux { stroke-width: 1.3; }

.schema-flux-mini .noeud-cercle { stroke-width: 1.1; }
.schema-flux-mini .icone-noeud { stroke-width: 1.6; }
.noeud-cercle { fill: none; stroke: var(--trait-fort); stroke-width: 0.9; transition: stroke var(--lent); }
.noeud-flux.actif .noeud-cercle { stroke: var(--flux-conso); }
.noeud-flux.actif.recu .noeud-cercle { stroke: var(--flux-recu); }
.noeud-pastille { fill: var(--surface-creuse); transition: fill var(--lent); }
.noeud-flux.actif .noeud-pastille { fill: var(--flux-conso-fond); }
.noeud-flux.actif.recu .noeud-pastille { fill: var(--flux-recu-fond); }
.noeud-flux text { fill: var(--texte); font-family: inherit; }
.noeud-flux .noeud-valeur { font-size: var(--t-13); font-weight: 700; fill: var(--texte); }
.noeud-flux.actif .noeud-valeur { fill: var(--flux-conso); }
.noeud-flux.actif.recu .noeud-valeur { fill: var(--flux-recu); }
.noeud-flux .noeud-titre { font-size: var(--t-11); font-weight: 600; fill: var(--texte-doux); }
.noeud-flux .icone-noeud { stroke: var(--texte); stroke-width: 1.6; fill: none; }
.noeud-flux[data-cle] { cursor: pointer; }
.ligne-flux { fill: none; stroke: var(--trait); stroke-width: 0.9; }
.ligne-flux.active { stroke: var(--flux-conso); }
.ligne-flux.export { stroke: var(--flux-recu); }

.pastille-flux { fill: var(--flux-conso); stroke: none; transition: opacity var(--lent); }
.pastille-flux.export { fill: var(--flux-recu); }
/* Vue détaillée d'une branche : une liste façon application Loxone
   (total en tête, puis un appareil par ligne) plutôt qu'un second
   diagramme en étoile, qui n'apportait rien pour deux bornes. */
.liste-flux { display: none; flex-direction: column; margin: 8px 0 2px; }
.liste-flux.visible { display: flex; }
.ligne-flux-detail {
  display: flex; align-items: center; gap: 18px; padding: 15px 4px;
}
.ligne-flux-detail + .ligne-flux-detail { border-top: 1px solid var(--trait); }
.ligne-flux-detail.total { padding-bottom: 20px; }
.rond-flux {
  width: 62px; height: 62px; border-radius: 50%; flex-shrink: 0;
  border: 1.5px solid var(--trait-fort); color: var(--texte-doux);
  display: flex; align-items: center; justify-content: center;
  transition: border-color var(--lent), color var(--lent), background var(--lent);
}
.rond-flux svg { width: 26px; height: 26px; }
.ligne-flux-detail.total .rond-flux { width: 76px; height: 76px; }
.ligne-flux-detail.total .rond-flux svg { width: 32px; height: 32px; }
.ligne-flux-detail.actif .rond-flux {
  border-color: var(--accent); color: var(--accent); background: var(--accent-doux);
}
.flux-detail-textes { display: flex; flex-direction: column; min-width: 0; }
.flux-detail-valeur {
  font-size: var(--t-21); font-weight: 700; letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums; color: var(--texte);
}
.ligne-flux-detail.total .flux-detail-valeur { font-size: var(--t-27); }
.ligne-flux-detail.actif .flux-detail-valeur { color: var(--accent); }
.flux-detail-nom { font-size: var(--t-13); color: var(--texte-doux); margin-top: 3px; }

.resume-flux {
  display: flex; justify-content: center; gap: 26px; margin-top: 6px;
  padding-top: 16px; border-top: 1px solid var(--trait); flex-wrap: wrap;
}
.resume-flux > div { text-align: center; font-size: var(--t-11); font-weight: 600; color: var(--texte-doux); }
.resume-flux .valeur-resume-flux {
  font-size: var(--t-19); font-weight: 700; color: var(--texte); margin-top: 3px;
  font-variant-numeric: tabular-nums;
}

/* ============================================================
   PANNEAU DE RÉGLAGES
   ============================================================ */
/* Une carte flottante et non plus un volet collé au bord (26/09/2026,
   demande de Fred) : les quatre coins arrondis, elle commence sous les
   boutons du haut et s'arrête un peu avant le bas de l'écran pour que
   les coins du bas se voient. Elle glisse depuis la droite comme avant. */
.panneau {
  /* Le « top » est recalculé à l'ouverture d'après la hauteur réelle de
     la barre du haut (calerPanneauSousBarre) ; ceci n'est que la valeur
     de départ. */
  position: fixed; top: calc(60px + env(safe-area-inset-top)); right: -460px; width: 420px;
  bottom: calc(16px + env(safe-area-inset-bottom)); height: auto;
  background: var(--surface); border: 1px solid var(--trait); border-radius: var(--r-lg);
  /* Pas de marge basse : le bandeau de validation descend jusqu'au bord
     du panneau, sa propre marge intérieure suffit à l'aérer. */
  --bas-panneau: 0px;
  color: var(--texte); z-index: 50; padding: 26px 24px var(--bas-panneau); overflow-y: auto;
  transition: right var(--moyen) var(--courbe); box-shadow: var(--ombre-3);
}
.panneau.ouvert { right: 16px; }
.panneau h2 { font-size: var(--t-19); margin: 0 0 4px; font-weight: 700; }
.sous-titre-panneau { font-size: var(--t-12); color: var(--texte-doux); margin-bottom: 20px; line-height: 1.5; }
.panneau-section {
  margin-bottom: 22px; padding-bottom: 20px; border-bottom: 1px solid var(--trait);
}
.panneau-section:last-child { border-bottom: none; }
/* Le bouton de validation reste visible au bas du panneau, même quand la
   liste des réglages est longue : c'est la sortie, elle ne doit pas se
   mériter au bout d'un défilement. */
.pied-panneau {
  position: sticky; bottom: 0; z-index: 2;
  margin: 20px -24px calc(-1 * var(--bas-panneau));
  padding: 14px 24px calc(14px + env(safe-area-inset-bottom));
  background: var(--surface); border-top: 1px solid var(--trait);
  /* Un voile au-dessus du bandeau : le contenu qui défile dessous se
     fond au lieu d'être tranché net. */
  box-shadow: 0 -12px 16px -8px var(--surface);
  display: block;
  /* Le bandeau épouse les coins du bas de la carte. */
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}
/* Plus de bouton « Fermer » : le pied n'existe que le temps d'une
   modification, avec Annuler et Enregistrer côte à côte. */
.pied-panneau[hidden] { display: none; }
/* Un seul bouton tant que rien n'a bougé ; deux dès qu'il y a quelque
   chose à garder ou à jeter, côte à côte et de largeur égale.
   Ni flex ni grille ici : les deux ont donné sur Safari un bouton
   accaparant toute la largeur et l'autre réduit à un trait. On ne lui
   demande donc plus de répartir quoi que ce soit -- chaque bouton porte
   sa largeur, en dur, et la classe « a-deux » dit laquelle. */
.pied-panneau .bouton {
  display: inline-block; vertical-align: top; box-sizing: border-box;
  width: 100%; margin-top: 0;
}
.pied-panneau .valider-panneau {
  background: var(--succes); border-color: var(--succes); color: var(--succes-contraste);
}
.pied-panneau .valider-panneau:hover { filter: brightness(1.06); background: var(--succes); }
.pied-panneau .annuler-panneau {
  background: var(--danger); border-color: var(--danger); color: var(--danger-contraste);
}
.pied-panneau .annuler-panneau:hover { filter: brightness(1.06); background: var(--danger); }
.panneau-section h3 {
  font-size: var(--t-11); color: var(--texte-doux); margin: 0 0 12px;
  font-weight: 700; text-transform: uppercase; letter-spacing: .07em;
}
.champ { margin-bottom: 10px; }
.champ label { display: block; font-size: var(--t-12); font-weight: 600; color: var(--texte-doux); margin-bottom: 5px; }
.champ input, .champ select {
  width: 100%; padding: 10px 11px; border-radius: var(--r-xs);
  border: 1px solid var(--trait-fort); background: var(--surface-douce);
  color: var(--texte); font-size: var(--t-13);
}
.champ input:focus, .champ select:focus { outline: 2px solid var(--accent); outline-offset: 0; border-color: transparent; }
.champ-ligne { display: flex; gap: 8px; }
.champ-ligne .champ { flex: 1; margin-bottom: 0; }
/* Le nom du favori tient sa ligne, la condition s'écrit en dessous :
   côte à côte, la phrase « Seulement quand un véhicule est branché »
   mangeait toute la largeur et il ne restait du nom que « Garag… ». */
.liste-favoris-item {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center;
  column-gap: 8px; row-gap: 6px; padding: 10px 11px;
  border-radius: var(--r-xs); background: var(--surface-douce);
  border: 1px solid transparent; margin-bottom: 6px; font-size: var(--t-13); font-weight: 500; cursor: pointer;
}
.liste-favoris-item:hover { background: var(--surface-creuse); }

.liste-favoris-item > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.ligne-icone-piece {
  display: flex; align-items: center; gap: 12px; padding: 10px 4px;
  cursor: pointer; border-bottom: 1px solid rgba(255,255,255,.06);
}
.ligne-icone-piece:last-child { border-bottom: none; }
/* L'arbre des pièces : un niveau par ligne, ses pièces dedans. */
.ligne-niveau {
  display: flex; align-items: center; gap: 10px; padding: 11px 4px;
  cursor: pointer; border-bottom: 1px solid rgba(255,255,255,.06);
}
.ligne-niveau .nom-niveau { flex: 1; font-size: var(--t-13); font-weight: 650; }
.ligne-niveau .compte-niveau {
  flex: none; font-size: var(--t-11); color: var(--texte-doux);
  background: var(--surface-creuse); border-radius: 999px; padding: 2px 8px;
}
.ligne-niveau .chevron-niveau { color: var(--texte-doux); display: flex; transition: transform var(--moyen); }
.ligne-niveau.ouverte .chevron-niveau { transform: rotate(90deg); }
.ligne-niveau.sans-niveau .nom-niveau { color: var(--texte-doux); font-weight: 600; }
.ligne-niveau .niveau-regler {
  flex: none; border: 0; background: transparent; color: var(--texte-doux);
  padding: 4px; border-radius: 8px; cursor: pointer; display: flex;
}
.ligne-niveau .niveau-regler:hover { background: var(--surface-creuse); color: var(--texte); }
/* Les pièces d'un niveau : décalées, pour qu'on voie d'un coup d'œil
   ce qui appartient à quoi. */
.pieces-du-niveau { padding-left: 16px; border-left: 2px solid var(--trait); margin: 2px 0 6px 6px; }
.pieces-du-niveau .sous-titre-panneau { padding: 8px 2px; }
.titre-rattaches {
  font-size: var(--t-11); color: var(--texte-doux); text-transform: uppercase;
  letter-spacing: .05em; margin: 10px 2px 4px;
}
.ligne-rattache {
  display: flex; align-items: center; gap: 10px; padding: 8px 2px;
  border-bottom: 1px solid rgba(255,255,255,.06);
}
.ligne-rattache:last-child { border-bottom: none; }
.ligne-rattache .nom { flex: 1; min-width: 0; font-size: var(--t-13); }
.ligne-rattache .piece-dorigine { font-size: var(--t-11); color: var(--texte-doux); }
.ligne-rattache .retirer-rattache { flex: none; width: auto; padding: 5px 10px; font-size: var(--t-11); }
.edition-niveau { display: flex; gap: 6px; align-items: center; padding: 8px 4px 10px 22px; }
.edition-niveau input {
  flex: 1; min-width: 0; padding: 8px 10px; border-radius: 10px;
  border: 1px solid var(--trait); background: var(--surface-creuse); color: var(--texte);
  font: inherit; font-size: var(--t-13);
}
.actions-pieces { display: flex; flex-direction: column; gap: 10px; margin-top: 16px; }
/* La liste des appareils, par catégorie : même forme que l'arbre des
   pièces, avec la couleur de la famille en plus. */
.ligne-groupe {
  display: flex; align-items: center; gap: 10px; padding: 10px 4px;
  cursor: pointer; border-bottom: 1px solid rgba(255,255,255,.06);
}
.ligne-groupe .nom-groupe { flex: 1; font-size: var(--t-13); font-weight: 650; }
.ligne-groupe .compte-niveau {
  flex: none; font-size: var(--t-11); color: var(--cat);
  background: var(--cat-fond); border-radius: 999px; padding: 2px 8px;
}
.ligne-groupe .chevron-niveau { color: var(--texte-doux); display: flex; transition: transform var(--moyen); }
.ligne-groupe.ouverte .chevron-niveau { transform: rotate(90deg); }
.ligne-groupe .chip-icone { width: 26px; height: 26px; border-radius: 8px; }
.ligne-groupe .chip-icone svg { width: 15px; height: 15px; }
.appareils-du-groupe {
  padding-left: 14px; margin: 2px 0 6px 6px;
  border-left: 2px solid var(--cat, var(--trait));
}
.appareils-du-groupe .sous-titre-panneau { padding: 8px 2px; }
.texte-ligne-reglage { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ligne-icone-piece .nom-piece-reglage {
  font-size: var(--t-13); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ligne-icone-piece .sous-nom-reglage {
  font-size: var(--t-11); color: var(--texte-doux);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ligne-icone-piece .etat-piece-reglage {
  flex: none; font-size: var(--t-11); color: var(--texte-doux); white-space: nowrap;
}
.ligne-icone-piece .chevron-icone-piece { color: var(--texte-doux); transition: transform var(--moyen); }
.ligne-icone-piece.ouverte .chevron-icone-piece { transform: rotate(90deg); }
.grille-choix-icone {
  display: none; grid-template-columns: repeat(6, 1fr); gap: 7px;
  padding: 4px 4px 16px;
}
.grille-choix-icone.ouvert { display: grid; }
/* Le sélecteur peut afficher jusqu'à 120 résultats : sa grille défile
   au lieu de pousser tout le panneau. */
.selecteur-icone .grille-choix-icone {
  max-height: 232px; overflow-y: auto; padding-bottom: 6px;
}
.recherche-icone {
  width: 100%; padding: 8px 11px; font: inherit; font-size: var(--t-13);
  background: var(--surface-douce); color: var(--texte);
  border: 1px solid var(--trait); border-radius: var(--r-xs);
}
.recherche-icone:focus { outline: none; border-color: var(--accent); }
.pied-selecteur-icone {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 2px;
}
.pied-selecteur-icone .tout-voir-icones {
  flex: none; width: auto; padding: 7px 13px; font-size: var(--t-11);
}
.legende-icone { flex: 1; min-width: 0; }
.case-choix-icone {
  aspect-ratio: 1; border-radius: 10px; background: var(--surface-creuse);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  border: 1.5px solid transparent; color: var(--texte);
}
.case-choix-icone:hover { background: var(--accent-doux); }
.case-choix-icone.selectionnee { border-color: var(--edition); color: var(--edition); }
.case-choix-icone svg { width: 19px; height: 19px; }
/* Renommage, appareils et suppression d'une pièce : replié avec la
   grille d'icônes, déplié en même temps qu'elle. */
.gestion-piece { display: none; padding: 0 4px 18px; }
.gestion-piece.ouvert { display: block; }
.ligne-appareil-piece {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 7px 0; border-bottom: 1px solid rgba(255,255,255,.05);
}
.ligne-appareil-piece:last-of-type { border-bottom: none; }
.ligne-appareil-piece .nom-appareil-piece {
  flex: 1 1 130px; min-width: 0; font-size: var(--t-13);
}
.ligne-appareil-piece select { flex: 0 1 auto; max-width: 100%; }
textarea#zone-export {
  width: 100%; height: 130px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--t-11); background: var(--surface-douce); color: var(--texte);
  border: 1px solid var(--trait-fort); border-radius: var(--r-xs); padding: 9px;
}

/* ============================================================
   CONNEXION ET COMPTES
   ============================================================ */
.ecran-connexion {
  position: fixed; inset: 0; z-index: 100; display: none;
  align-items: center; justify-content: center;
  background: var(--fond-voute); color: var(--texte);
  padding: calc(24px + var(--haut-sur)) 20px calc(24px + env(safe-area-inset-bottom));
}
.ecran-connexion.visible { display: flex; }
.carte-connexion {
  width: min(380px, 100%); background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r-md); box-shadow: var(--ombre-3); padding: 28px 24px;
}
.logo-connexion { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.carte-connexion h1 { font-size: var(--t-17); margin: 0; letter-spacing: .08em; text-transform: uppercase; }
.carte-connexion p { font-size: var(--t-13); color: var(--texte-doux); line-height: 1.5; margin: 0 0 18px; }
.erreur-connexion { color: var(--cat-securite); font-size: var(--t-13); min-height: 18px; margin: 4px 0 10px; }
.ligne-utilisateur {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 10px; border-radius: var(--r-xs); background: var(--surface-douce);
  margin-bottom: 6px; font-size: var(--t-13);
}
.ligne-utilisateur .nom-utilisateur { font-weight: 650; flex: 1; }
.changement-mdp {
  border: 1px solid var(--trait); border-radius: 12px;
  padding: 12px; margin: 6px 0 10px;
}
.badge-admin {
  font-size: var(--t-10); font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  padding: 2px 7px; border-radius: 999px; background: var(--accent-doux); color: var(--accent);
}
.actions-utilisateur { display: flex; gap: 6px; flex-wrap: wrap; width: 100%; }
.actions-utilisateur .bouton { flex: 1; padding: 7px 8px; font-size: var(--t-12); margin-top: 0; width: auto; white-space: nowrap; }
.bouton.danger { background: transparent; border-color: var(--cat-securite); color: var(--cat-securite); }
.bouton.danger:hover { background: var(--cat-securite-fond); }
/* Ce qui touche au NAS, aux volets et au diagnostic ne regarde que
   l'administrateur : un invité n'a pas à relancer le proxy. */
body.non-admin .admin-seulement { display: none; }

.meteo-perime { display: block; margin-top: 6px; color: var(--cat-securite); }
/* Le temps d'aller chercher les valeurs d'un autre lieu, la carte reste
   affichée mais s'efface un peu : on voit qu'elle n'est plus d'actualité
   sans qu'elle disparaisse. */
#meteo-contenu .meteo-maintenant,
#meteo-contenu .meteo-heures,
#meteo-contenu .meteo-carte { transition: opacity var(--moyen) var(--courbe); }
/* Mise à jour en cours -- des données ou du lieu. Les tuiles ne bougent
   pas d'un pixel : ce sont les VALEURS qui pâlissent et perdent leur
   couleur, le temps que les nouvelles arrivent. Faire disparaître la
   carte pour la reconstruire donnait un trou à l'écran, et sur la page
   météo ce trou fait toute la hauteur. */
#meteo-contenu.en-attente .meteo-degres,
#meteo-contenu.en-attente .meteo-libelle,
#meteo-contenu.en-attente .meteo-actuel .symbole,
#meteo-contenu.en-attente .meteo-detail .mesure,
#meteo-contenu.en-attente .meteo-heure .symbole,
#meteo-contenu.en-attente .meteo-heure .degres,
#meteo-contenu.en-attente .meteo-heure .ressenti,
#meteo-contenu.en-attente .meteo-heure .pluie,
#meteo-contenu.en-attente .meteo-heure .uv,
#meteo-contenu.en-attente .meteo-jour .symbole,
#meteo-contenu.en-attente .meteo-jour .pluie-jour,
#meteo-contenu.en-attente .meteo-jour .uv-jour,
#meteo-contenu.en-attente .confiance-jour,
#meteo-contenu.en-attente .barre-temperature,
#meteo-contenu.en-attente .meteo-bornes {
  opacity: .35; filter: grayscale(1);
  transition: opacity var(--moyen), filter var(--moyen);
}
/* Le retour se fait en douceur aussi, sinon la carte clignote. */
.meteo-degres, .meteo-libelle, .meteo-actuel .symbole, .meteo-detail .mesure,
.meteo-heure .symbole, .meteo-heure .degres, .meteo-heure .ressenti,
.meteo-heure .pluie, .meteo-heure .uv, .meteo-jour .symbole,
.meteo-jour .pluie-jour, .meteo-jour .uv-jour, .confiance-jour,
.barre-temperature, .meteo-bornes {
  transition: opacity var(--moyen), filter var(--moyen);
}

/* Recherche de lieu, en tête de la colonne des prévisions */
.meteo-recherche { display: flex; gap: 8px; align-items: stretch; margin-bottom: 12px; }
.meteo-recherche .champ-recherche { position: relative; flex: 1; min-width: 0; }
.meteo-recherche .bouton-domicile {
  display: flex; align-items: center; gap: 7px; flex-shrink: 0;
  padding: 9px 13px; border-radius: var(--r-sm); cursor: pointer;
  background: var(--surface-douce); border: 1px solid var(--trait);
  color: var(--texte); font-size: var(--t-13); font-weight: 650;
  transition: background var(--vite), border-color var(--vite);
}
.meteo-recherche .bouton-domicile:hover { background: var(--surface-creuse); border-color: var(--trait-fort); }
/* Déjà chez soi : le bouton reste là mais ne s'annonce plus. */
.meteo-recherche .bouton-domicile.actif {
  background: var(--accent-doux); border-color: var(--accent); color: var(--accent);
}
.meteo-recherche input {
  width: 100%; padding: 9px 12px 9px 34px; border-radius: var(--r-sm);
  border: 1px solid var(--trait); background: var(--surface-douce);
  color: var(--texte); font-size: var(--t-13);
}
.meteo-recherche input:focus { outline: 2px solid var(--accent); outline-offset: 0; border-color: transparent; }
.meteo-recherche .champ-recherche .loupe {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  color: var(--texte-faible); pointer-events: none; display: flex;
}
.meteo-resultats {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px); z-index: 12;
  background: var(--surface); border: 1px solid var(--trait); border-radius: var(--r-sm);
  box-shadow: var(--ombre-3); overflow: hidden; display: none;
}
.meteo-resultats.visible { display: block; }
.meteo-resultat {
  padding: 9px 12px; cursor: pointer; font-size: var(--t-13);
  border-bottom: 1px solid var(--trait);
}
.meteo-resultat:last-child { border-bottom: none; }
.meteo-resultat:hover { background: var(--accent-doux); }
.meteo-resultat .r-nom { font-weight: 650; }
.meteo-resultat .r-detail { font-size: var(--t-11); color: var(--texte-doux); }
.meteo-resultats .vide { padding: 9px 12px; font-size: var(--t-12); color: var(--texte-doux); }

/* Menu des lieux favoris, à droite de la barre */
.menu-favoris-lieux { position: relative; flex-shrink: 0; }
.bouton-favoris-lieux {
  height: 100%; display: flex; align-items: center; gap: 5px;
  padding: 9px 12px; border-radius: var(--r-sm); cursor: pointer;
  background: var(--surface-douce); border: 1px solid var(--trait); color: var(--texte);
  font-size: var(--t-13); font-weight: 650; white-space: nowrap;
  transition: background var(--vite), border-color var(--vite), color var(--vite);
}
.bouton-favoris-lieux:hover { background: var(--surface-creuse); border-color: var(--trait-fort); color: var(--texte); }
.menu-favoris-lieux.ouvert .bouton-favoris-lieux { background: var(--accent-doux); border-color: var(--accent); color: var(--accent); }
.chevron-favoris { transition: transform var(--moyen); }
.menu-favoris-lieux.ouvert .chevron-favoris { transform: rotate(180deg); }
.liste-favoris-lieux {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 12; display: none;
  min-width: 210px; max-width: 78vw; padding: 5px;
  background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r-sm); box-shadow: var(--ombre-3);
}
.menu-favoris-lieux.ouvert .liste-favoris-lieux { display: block; }
.favori-lieu {
  display: grid; grid-template-columns: 1fr auto; align-items: center;
  width: 100%; gap: 2px 8px; text-align: left; cursor: pointer;
  padding: 7px 8px 7px 10px; border: none; border-radius: var(--r-xs);
  background: transparent; color: var(--texte); font-size: var(--t-13);
}
.favori-lieu:hover { background: var(--surface-creuse); }
.favori-lieu.actif { background: var(--accent-doux); color: var(--accent); }
.favori-lieu .f-nom {
  grid-column: 1; grid-row: 1; font-weight: 650;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.favori-lieu .f-detail {
  grid-column: 1; grid-row: 2; font-size: var(--t-11); color: var(--texte-doux);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.favori-lieu .f-retirer {
  grid-column: 2; grid-row: 1 / span 2; align-self: center;
  display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; flex-shrink: 0; cursor: pointer;
  border: 1px solid var(--trait); border-radius: var(--r-xs);
  background: var(--surface-douce); color: var(--texte-doux);
  transition: background var(--vite), color var(--vite), border-color var(--vite);
}
.favori-lieu .f-retirer:hover {
  color: var(--cat-securite); background: var(--cat-securite-fond); border-color: var(--cat-securite);
}
.entete-favoris {
  padding: 6px 10px 8px; font-size: var(--t-11); font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em; color: var(--texte-faible);
}

/* Nom du lieu, dans la carte des prévisions */
.meteo-carte.avec-lieu { position: relative; }
/* Le coin haut droit de la carte : le nom du lieu, et dessous l'heure
   qu'on examine dans la bande. Sa largeur est posée par ajusterNomLieu,
   d'après la place qui reste à droite de la température. */
.meteo-coin-lieu {
  position: absolute; top: 12px; right: 14px; z-index: 2;
  display: flex; flex-direction: column; align-items: flex-end; gap: 6px;
  max-width: 58%; min-width: 0;
}
.meteo-lieu-affiche {
  display: flex; align-items: baseline; gap: 4px;
  font-weight: 700; color: var(--texte-doux);
  font-size: var(--t-15); line-height: 1.1;
  max-width: 100%; min-width: 0;
}
.meteo-lieu-affiche .nom-lieu-carte {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
/* Ailleurs que chez soi : le nom s'affirme, et deux boutons apparaissent. */
.meteo-lieu-affiche.ailleurs {
  align-items: center; gap: 6px;
  padding: 5px 8px 5px 12px; border-radius: 999px;
  background: var(--accent); color: var(--accent-contraste);
}
.meteo-lieu-retour, .meteo-lieu-garder {
  background: transparent; border: none; color: inherit; cursor: pointer;
  font-size: var(--t-17); line-height: 1; padding: 0 2px; opacity: .75;
}
.meteo-lieu-garder { font-size: var(--t-13); }
.meteo-lieu-retour:hover, .meteo-lieu-garder:hover { opacity: 1; }

/* Lieux de prévision : liste dans les réglages, puces sur la page météo */
.ligne-lieu {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px; margin-bottom: 6px;
  border-radius: var(--r-xs); background: var(--surface-douce); font-size: var(--t-13);
  border: 1px solid transparent;
}
.ligne-lieu.actif { border-color: var(--accent); background: var(--accent-doux); }
.ligne-lieu .lieu-texte { flex: 1; min-width: 0; }
.ligne-lieu .lieu-nom { font-weight: 650; }
.ligne-lieu .lieu-detail {
  font-size: var(--t-11); color: var(--texte-doux);
  /* Une région peut être longue : elle se coupe plutôt que de pousser
     les boutons à la ligne suivante. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ligne-lieu .bouton { width: auto; margin: 0; padding: 6px 10px; font-size: var(--t-12); }

.segmente-fav {
  display: flex; gap: 4px; padding: 3px; margin-top: 6px;
  background: var(--surface-creuse); border-radius: var(--r-sm);
}
.segmente-fav button {
  flex: 1; min-width: 0; padding: 9px 4px; border: none; border-radius: calc(var(--r-sm) - 3px);
  background: transparent; color: var(--texte-doux); cursor: pointer;
  font-size: var(--t-13); font-weight: 650; font-family: inherit;
  transition: background var(--vite), color var(--vite);
}
.segmente-fav button:hover { color: var(--texte); }
.segmente-fav button.actif { background: var(--surface); color: var(--texte); box-shadow: var(--ombre-1); }

/* ----- Image de fond : quatre sources, un bloc par source ----- */
.segmente-fond { margin: 0 0 12px; }
.ligne-voile { margin: 0 0 12px; }
.ligne-voile label { display: flex; justify-content: space-between; font-size: var(--t-12); font-weight: 600; color: var(--texte-doux); margin-bottom: 4px; }
.ligne-voile label b { color: var(--texte); font-variant-numeric: tabular-nums; }
.ligne-voile input[type="range"] { width: 100%; accent-color: var(--accent); }
.segmente-fond button { padding: 8px 2px; font-size: var(--t-12); }
.bloc-fond { border: 1px solid var(--trait); border-radius: var(--r-sm); padding: 12px; }
.ligne-fond { display: flex; gap: 8px; align-items: center; }
.ligne-fond input[type="search"] { flex: 1; min-width: 0; }
.bouton.compact { width: auto; margin: 0; padding: 8px 12px; font-size: var(--t-12); white-space: nowrap; }
.note-fond { font-size: var(--t-11); color: var(--texte-doux); line-height: 1.5; margin-top: 10px; }
.note-fond a { color: var(--accent); }
.retour-fond { font-size: var(--t-11); color: var(--texte-doux); min-height: 1em; }
.retour-fond.erreur { color: var(--danger); }
.puces-fond { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 10px; }
.puce-fond {
  font-size: var(--t-12); font-weight: 600; padding: 5px 10px; border-radius: 999px;
  border: 1px solid var(--trait-fort); background: var(--surface-douce); color: var(--texte); cursor: pointer;
}
.puce-fond.actif { background: var(--accent); border-color: var(--accent); color: var(--accent-contraste); }
.case-fond { display: flex; gap: 8px; align-items: center; font-size: var(--t-13); margin: 6px 0; cursor: pointer; }
.segmente-orientation { margin: 0 0 8px; }
.segmente-orientation button { font-size: var(--t-12); padding: 7px 2px; }
.galerie-fond { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.galerie-fond figure {
  margin: 0; position: relative; aspect-ratio: 4 / 3; border-radius: var(--r-xs); overflow: hidden;
  background: var(--surface-creuse); cursor: pointer; outline: 0 solid var(--accent);
}
.galerie-fond figure.choisie { outline-width: 3px; outline-offset: -3px; }
.galerie-fond img { width: 100%; height: 100%; object-fit: cover; display: block; }
.galerie-fond figcaption {
  position: absolute; left: 0; right: 0; bottom: 0; font-size: 10px; padding: 3px 6px; color: #fff;
  background: linear-gradient(transparent, rgba(0,0,0,.6));
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Les deux emplacements (paysage, portrait) avec leur aperçu recadré :
   on glisse la photo dedans pour choisir ce que l'autre orientation
   garde. */
.fond-orientations { display: grid; gap: 10px; margin-top: 10px; }
.emplacement-fond {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 10px; align-items: start;
  padding: 8px; border-radius: var(--r-xs); background: var(--surface-douce);
}
.emplacement-fond .titre-emplacement { font-size: var(--t-12); font-weight: 700; }
.emplacement-fond .detail-emplacement { font-size: var(--t-11); color: var(--texte-doux); line-height: 1.45; margin-top: 2px; }
.emplacement-fond .detail-emplacement a { color: var(--accent); }
.emplacement-fond .actions-emplacement { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.apercu-ancre {
  position: relative; border-radius: 6px; overflow: hidden; background: var(--surface-creuse);
  background-size: cover; background-repeat: no-repeat; touch-action: none; cursor: grab;
  border: 1px solid var(--trait);
}
/* La photo entière, dans son sens ; par-dessus, la bande claire est ce
   que l'écran tenu dans l'autre sens gardera. C'est elle qu'on glisse. */
.apercu-ancre.paysage { width: 126px; height: 84px; }
.apercu-ancre.portrait { width: 84px; height: 126px; }
.apercu-ancre .bande {
  position: absolute; box-sizing: border-box;
  border: 2px solid #fff; border-radius: 4px;
  box-shadow: 0 0 0 200px rgba(20, 19, 15, .45);   /* assombrit tout sauf la bande */
  pointer-events: none;
}
.apercu-ancre.paysage .bande { top: 0; height: 100%; width: 31%; }
.apercu-ancre.portrait .bande { left: 0; width: 100%; height: 45%; }
.apercu-ancre.vide { display: flex; align-items: center; justify-content: center; font-size: 18px; color: var(--texte-faible); cursor: default; }
.apercu-ancre:active { cursor: grabbing; }
.nuancier-fond { display: flex; flex-wrap: wrap; gap: 8px; }
.teinte-fond {
  width: 34px; height: 34px; border-radius: 50%; background: var(--c);
  border: 1px solid rgba(0,0,0,.12); cursor: pointer; outline: 0 solid var(--accent); outline-offset: 2px; padding: 0;
}
.teinte-fond.actif { outline-width: 2.5px; }
.roue-fond { position: relative; width: 44px; height: 44px; flex: none; cursor: pointer; }
.roue-fond input { position: absolute; inset: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; }
.roue-fond span {
  display: block; width: 44px; height: 44px; border-radius: 50%; border: 2px solid var(--surface);
  box-shadow: 0 0 0 1px rgba(0,0,0,.12);
  background: conic-gradient(#f66, #fb5, #fe6, #7d7, #6de, #77e, #d7d, #f66);
}
.segmente-fav button:active { transform: scale(.94); }
/* Les trois façons d'afficher une pastille : l'une exclut les autres,
   d'où des boutons radio plutôt qu'une pile de cases à cocher. */
.choix-affichage { display: flex; flex-direction: column; gap: 2px; margin-top: 6px; }
.choix-affichage label {
  display: flex; align-items: center; gap: 9px; cursor: pointer;
  padding: 8px 10px; border-radius: var(--r-xs); font-size: var(--t-13);
  color: var(--texte-doux);
}
.choix-affichage label:hover { background: var(--surface-creuse); }
.choix-affichage input { width: 16px; height: 16px; margin: 0; flex: none; accent-color: var(--accent); }
.choix-affichage label:has(input:checked) { color: var(--texte); font-weight: 600; }
.bloc-seuil {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 8px 0 0; padding: 10px; border-radius: var(--r-sm);
  background: var(--surface-douce); border: 1px solid var(--trait);
}
.bloc-seuil[hidden] { display: none; }
.bloc-seuil .seuil-grandeur { font-size: var(--t-13); font-weight: 650; flex: none; }
.bloc-seuil select {
  flex: 1; min-width: 118px; margin: 0; padding: 8px 10px;
  border-radius: var(--r-sm); border: 1px solid var(--trait);
  background: var(--surface); color: var(--texte);
  font-size: var(--t-13); font-family: inherit;
}
.bloc-seuil select:focus, .bloc-seuil input:focus {
  outline: 2px solid var(--accent); outline-offset: 0; border-color: transparent;
}
.bloc-seuil input {
  width: 84px; flex: none; padding: 8px 10px; border-radius: var(--r-sm);
  border: 1px solid var(--trait); background: var(--surface);
  color: var(--texte); font-size: var(--t-13); font-family: inherit;
  font-variant-numeric: tabular-nums;
}
.bloc-seuil .seuil-unite { font-size: var(--t-13); color: var(--texte-doux); flex: none; }
/* La liste des conditions d'une pastille. Une ligne par condition,
   et le mot qui les relie seulement à partir de deux. */
.bloc-conditions { margin-top: 8px; }
.bloc-conditions[hidden] { display: none; }
.ligne-condition {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin-bottom: 6px; padding: 8px; border-radius: var(--r-sm);
  background: var(--surface-douce); border: 1px solid var(--trait);
}
.ligne-condition select {
  flex: 1 1 110px; min-width: 96px; margin: 0; padding: 7px 8px;
  border-radius: var(--r-sm); border: 1px solid var(--trait);
  background: var(--surface); color: var(--texte);
  font-size: var(--t-12); font-family: inherit;
}
.ligne-condition input {
  width: 68px; flex: none; padding: 7px 8px; border-radius: var(--r-sm);
  border: 1px solid var(--trait); background: var(--surface);
  color: var(--texte); font-size: var(--t-12); font-family: inherit;
  font-variant-numeric: tabular-nums;
}
.ligne-condition select:focus, .ligne-condition input:focus {
  outline: 2px solid var(--accent); outline-offset: 0; border-color: transparent;
}
.ligne-condition .seuil-unite { font-size: var(--t-12); color: var(--texte-doux); flex: none; }
.retirer-condition {
  margin-left: auto; flex: none; width: 26px; height: 26px; border-radius: var(--r-sm);
  border: none; background: var(--danger-doux); color: var(--danger);
  font-size: var(--t-15); line-height: 1; cursor: pointer;
}
.condition-toute {
  display: flex; align-items: center; gap: 9px; cursor: pointer;
  padding: 8px 10px; margin-bottom: 4px; border-radius: var(--r-xs);
  font-size: var(--t-13); color: var(--texte-doux);
}
.condition-toute:hover { background: var(--surface-creuse); }
.condition-toute input { width: 16px; height: 16px; margin: 0; flex: none; accent-color: var(--accent); }
.condition-toute:has(input:checked) { color: var(--texte); font-weight: 600; }
.ajouter-condition {
  border: 1px dashed var(--trait); background: none; color: var(--texte-doux);
  border-radius: var(--r-sm); padding: 8px 10px; width: 100%;
  font: inherit; font-size: var(--t-12); font-weight: 600; cursor: pointer;
}
.ajouter-condition:hover { color: var(--texte); border-color: var(--trait-fort); }
.segmente-fav.combinaison { margin-top: 8px; }
.segmente-fav.portee-calibrage { margin: 0 0 4px; }
.segmente-fav.combinaison[hidden] { display: none; }

/* Page Favoris sans rien à montrer : un mot et une porte de sortie. */
/* La liste des alertes dans sa fiche : une ligne par chose à faire,
   chacune cliquable, la gravité dans la pastille de gauche. */
.liste-alertes { display: flex; flex-direction: column; gap: 6px; margin-top: 14px; }
.ligne-alerte {
  display: flex; align-items: center; gap: 11px; width: 100%;
  padding: 11px 12px; border-radius: var(--r-sm); cursor: pointer;
  border: 1px solid var(--trait); background: var(--surface-douce);
  font: inherit; text-align: left; color: var(--texte);
}
.ligne-alerte:hover { border-color: var(--trait-fort); background: var(--surface-creuse); }
.alerte-pastille {
  width: 9px; height: 9px; border-radius: 50%; flex: none;
  background: var(--alerte);
}
.ligne-alerte.grave .alerte-pastille { background: var(--danger); }
.ligne-alerte.grave { border-color: var(--danger); }
.alerte-texte { display: flex; flex-direction: column; min-width: 0; }
.alerte-titre { font-size: var(--t-13); font-weight: 650; }
.alerte-detail { font-size: var(--t-11); color: var(--texte-doux); }
.valeur-geante.repos { color: var(--cat-vehicule); }

.favoris-vides {
  max-width: 420px; margin: 40px auto; padding: 20px 22px; text-align: center;
  border: 1px dashed var(--trait); border-radius: var(--r-md);
  background: var(--surface-douce); color: var(--texte-doux);
  font-size: var(--t-13); line-height: 1.6;
}
.favoris-vides b { color: var(--texte); font-weight: 650; }
.favoris-vides .bouton { margin-left: auto; margin-right: auto; }

/* Ce qu'on a mis dans la voiture, et depuis quand : sous les kW, en
   petit. Les kW disent l'instant, cette ligne dit la session. */
.carte-session {
  font-size: var(--t-11); font-weight: 600; color: var(--texte-doux);
  font-variant-numeric: tabular-nums; margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Une pastille conditionnelle, vue depuis le mode réglage : elle est là
   mais elle ne sera pas toujours affichée. Le liseré pointillé le dit
   sans avoir à ouvrir les réglages. */
.carte[data-conditionnel] { position: relative; }
body.en-edition .carte[data-conditionnel] {
  border-style: dashed;
}
/* La règle d'affichage, portée par la pastille en mode réglage : on la
   lit, et on la touche pour la changer. Elle prend toute la rangée du
   bas -- le nom de la pièce s'efface le temps du réglage plutôt que de
   se chevaucher avec elle, sans être retiré pour que la pastille ne
   change pas de taille en entrant en mode réglage. */
.condition-pastille { display: none; }
body.en-edition .condition-pastille {
  display: block; position: absolute; left: 8px; right: 8px; bottom: 4px;
  padding: 2px 2px; border: 0; border-radius: 6px; background: none;
  font: inherit; font-size: var(--t-10); font-weight: 700; letter-spacing: .02em;
  color: var(--texte-faible); text-align: left; cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
body.en-edition .condition-pastille:hover { background: var(--surface-creuse); }
body.en-edition .condition-pastille.sans-regle { font-weight: 600; color: var(--texte-doux); }
/* Condition remplie : la pastille serait là même hors mode réglage.
   C'est ce que le mode réglage, qui montre tout, ne peut pas dire
   autrement. */
body.en-edition .carte[data-conditionnel][data-condition-active="1"] {
  border-color: var(--accent);
}
/* Le mode réglage montre tout, et le montre en entier -- mais une
   pastille dont la condition n'est pas remplie ne serait pas là hors
   réglage : elle passe en gris. En gris et non en transparent : elle
   reste parfaitement lisible, c'est justement celle qu'on vient régler.
   Seules les couleurs partent : l'état, le nom, la teinte de l'icône. */
body.en-edition .carte[data-condition-active="0"] {
  background: var(--surface-douce);
}
body.en-edition .carte[data-condition-active="0"] .carte-valeur,
body.en-edition .carte[data-condition-active="0"] .carte-nom,
body.en-edition .carte[data-condition-active="0"] .carte-session,
body.en-edition .carte[data-condition-active="0"] .carte-soustitre {
  color: var(--texte-doux);
}
body.en-edition .carte[data-condition-active="0"] .carte-pied {
  color: var(--texte-faible);
}
body.en-edition .carte[data-condition-active="0"] .chip-icone {
  background: var(--surface-creuse); color: var(--texte-faible);
}
/* (Le texte n'est plus recoloré quand la condition est remplie : sur le
   surlignage bleu, le vert de l'accent devenait illisible.) */
body.en-edition .carte[data-reglable] .carte-pied { visibility: hidden; }
/* Plus haut que le menu du plan : une liste de conditions tient mal
   dans 380 px, et la phrase du bas doit rester atteignable. */
/* « .plan-menu.condition-menu » et non « .condition-menu » seul : la
   règle de base vit dans plan.css, chargé après app.css ; à spécificité
   égale elle gagnait, et le menu restait limité à 380 px -- le champ du
   message des notifications tombait sous le bord (26/09/2026). */
.plan-menu.condition-menu { padding: 8px 10px 10px; min-width: 300px;
                  max-width: min(360px, 92vw); max-height: min(88vh, 760px); }

/* Une ligne de type dans les réglages : le nom modifiable, le nombre de
   pièces qu'il range, puis les deux gestes. */
.ligne-type-piece {
  display: flex; align-items: center; gap: 6px; margin-bottom: 6px;
}
.ligne-type-piece input {
  flex: 1; min-width: 0; padding: 8px 10px; border-radius: var(--r-sm);
  border: 1px solid var(--trait); background: var(--surface);
  color: var(--texte); font-size: var(--t-13); font-family: inherit;
}
.ligne-type-piece .type-compte {
  flex: none; min-width: 22px; text-align: center;
  font-size: var(--t-11); font-weight: 700; color: var(--texte-faible);
}
.ligne-type-piece .bouton {
  width: auto; margin: 0; flex: none; padding: 8px 10px; font-size: var(--t-12);
  white-space: nowrap;
}

/* Filtres par type sur la page Pièces. Une rangée de pilules qui défile
   si elle déborde : sur un téléphone, six types tiennent rarement sur une
   ligne, et les faire passer à la ligne mangerait la hauteur de la
   grille. La barre disparaît tant qu'aucun type n'existe. */
.filtres-types {
  display: flex; gap: 7px; margin: 0 0 14px; padding-bottom: 2px;
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.filtres-types::-webkit-scrollbar { display: none; }
.filtres-types:empty { display: none; }
.filtre-type {
  flex: none; padding: 7px 14px; border-radius: var(--r-pilule, 999px);
  border: 1px solid var(--trait); background: var(--surface);
  color: var(--texte-doux); font-size: var(--t-13); font-weight: 650;
  font-family: inherit; cursor: pointer; white-space: nowrap;
  transition: background var(--vite), color var(--vite), border-color var(--vite);
}
.filtre-type:hover { background: var(--surface-creuse); color: var(--texte); }
.filtre-type.actif {
  background: var(--accent); border-color: var(--accent); color: var(--accent-contraste);
}
.filtre-type .compte-type { opacity: .65; font-weight: 500; margin-left: 5px; }
body.en-edition .filtres-types { display: none; }

/* Les mêmes pilules, mais dans les réglages : un sous-onglet par niveau
   de la maison, et les pièces de ce niveau dessous. C'est le rangement
   lui-même qui sert de navigation -- on ne cherche pas une pièce dans
   une liste de trente, on ouvre l'étage où elle est. */
.onglets-niveaux {
  display: flex; flex-wrap: wrap; gap: 7px; margin: 0 0 14px;
}
.onglets-niveaux:empty { display: none; }
.onglet-niveau {
  flex: none; padding: 7px 13px; border-radius: var(--r-pilule, 999px);
  border: 1px solid var(--trait); background: var(--surface);
  color: var(--texte-doux); font-size: var(--t-13); font-weight: 650;
  font-family: inherit; cursor: pointer; white-space: nowrap;
  transition: background var(--vite), color var(--vite), border-color var(--vite);
}
.onglet-niveau:hover { background: var(--surface-creuse); color: var(--texte); }
.onglet-niveau.actif {
  background: var(--accent); border-color: var(--accent); color: var(--accent-contraste);
}
.onglet-niveau .compte-type { opacity: .65; font-weight: 500; margin-left: 5px; }
/* Le fourre-tout de départ : tant qu'il reste des pièces non rangées,
   sa pilule se distingue pour qu'on sache qu'il y a du travail. */
.onglet-niveau.sans-niveau:not(.actif) {
  border-style: dashed; border-color: var(--trait-fort, var(--trait));
}

/* Choix de couleur : la palette en pastilles, celle en service
   entourée. La première case est barrée -- « pas de choix », donc la
   couleur que l'appli donnerait d'elle-même. */
.selecteur-couleur { margin-top: 12px; }
.cases-couleur {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(38px, 1fr));
  gap: 7px; margin-top: 6px;
}
.case-couleur {
  aspect-ratio: 1; display: flex; align-items: center; justify-content: center;
  border: 1.5px solid var(--trait); border-radius: var(--r-sm);
  background: var(--surface); cursor: pointer; padding: 0;
  transition: border-color var(--vite), transform var(--vite);
}
.case-couleur:active { transform: scale(.92); }
.case-couleur .rond-couleur {
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--pastille, var(--surface-creuse));
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12);
}
.case-couleur.choisie { border-color: var(--pastille, var(--texte)); border-width: 2.5px; }
/* La case « par défaut » : un rond barré, comme un interrupteur éteint. */
.case-couleur.sans-couleur .rond-couleur {
  background: var(--surface-creuse); position: relative; overflow: hidden;
}
.case-couleur.sans-couleur .rond-couleur::after {
  content: ""; position: absolute; left: 50%; top: -3px; bottom: -3px; width: 1.5px;
  background: var(--texte-faible); transform: translateX(-50%) rotate(45deg);
}
.case-couleur.sans-couleur.choisie { border-color: var(--texte-doux); }

/* Ordre du menu du bas : une ligne par page, deux flèches. Pas de
   glisser-déposer ici -- le panneau défile déjà sous le doigt, et un
   appui qui hésite entre « je fais défiler » et « je déplace » finit
   toujours par faire l'autre. */
.ligne-menu-bas {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; margin-bottom: 6px;
  border: 1px solid var(--trait); border-radius: var(--r-sm);
  background: var(--surface-douce);
}
.ligne-menu-bas:last-child { margin-bottom: 0; }
.ligne-menu-bas .mb-icone {
  display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; flex-shrink: 0; border-radius: 50%;
  background: var(--surface-creuse); color: var(--texte-doux);
}
.ligne-menu-bas .mb-icone svg { width: 17px; height: 17px; }
.ligne-menu-bas .mb-nom {
  flex: 1; min-width: 0; font-size: var(--t-13); font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ligne-menu-bas .mb-note { font-size: var(--t-11); color: var(--texte-faible); font-weight: 500; }
.mb-fleche {
  flex-shrink: 0; width: 34px; height: 34px; display: flex;
  align-items: center; justify-content: center; cursor: pointer;
  border: 1px solid var(--trait); border-radius: var(--r-sm);
  background: var(--surface); color: var(--texte-doux);
  transition: background var(--vite), color var(--vite);
}
.mb-fleche:hover:not(:disabled) { background: var(--surface-creuse); color: var(--texte); }
.mb-fleche:active:not(:disabled) { transform: scale(.92); }
.mb-fleche:disabled { opacity: .3; cursor: default; }

/* Choix du lieu de référence, dans les réglages : soit on tape une
   adresse et tout se remplit, soit on pose les trois nombres à la main.
   Les deux mènent au même endroit -- ce sont deux façons de désigner un
   point, pas deux réglages différents. */
.bloc-domicile {
  margin-top: 14px; padding: 14px; border-radius: var(--r-sm);
  background: var(--surface-douce); border: 1px solid var(--trait);
}
.titre-domicile {
  font-size: var(--t-11); font-weight: 700; text-transform: uppercase;
  letter-spacing: .07em; color: var(--texte-doux); margin-bottom: 10px;
}
.onglets-domicile {
  display: flex; gap: 4px; padding: 3px; margin-bottom: 12px;
  background: var(--surface-creuse); border-radius: var(--r-sm);
}
.onglets-domicile button {
  flex: 1; padding: 8px 10px; border: none; border-radius: calc(var(--r-sm) - 3px);
  background: transparent; color: var(--texte-doux); cursor: pointer;
  font-size: var(--t-13); font-weight: 650; font-family: inherit;
  transition: background var(--vite), color var(--vite);
}
.onglets-domicile button[aria-pressed="true"] {
  background: var(--surface); color: var(--texte); box-shadow: var(--ombre-1);
}
.mode-domicile[hidden] { display: none; }
.recherche-adresse { position: relative; }
.recherche-adresse input {
  width: 100%; box-sizing: border-box; padding: 9px 12px 9px 34px;
  border-radius: var(--r-sm); border: 1px solid var(--trait);
  background: var(--surface); color: var(--texte); font-size: var(--t-13);
  font-family: inherit;
}
.recherche-adresse input:focus { outline: 2px solid var(--accent); outline-offset: 0; border-color: transparent; }
.recherche-adresse .loupe {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  color: var(--texte-faible); pointer-events: none; display: flex;
}
/* Les résultats poussent le contenu au lieu de le recouvrir : dans un
   panneau qui défile, une liste flottante se retrouve vite coupée par le
   bord de la section. */
.resultats-adresse:empty { display: none; }
.resultats-adresse {
  margin-top: 8px; border: 1px solid var(--trait); border-radius: var(--r-sm);
  background: var(--surface); overflow: hidden;
}
.resultat-adresse {
  padding: 9px 12px; cursor: pointer; border-bottom: 1px solid var(--trait);
  display: flex; align-items: center; gap: 10px;
}
.resultat-adresse:last-child { border-bottom: none; }
.resultat-adresse:hover { background: var(--accent-doux); }
.resultat-adresse .a-texte { flex: 1; min-width: 0; }
.resultat-adresse .a-nom {
  font-size: var(--t-13); font-weight: 650;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.resultat-adresse .a-detail { font-size: var(--t-11); color: var(--texte-doux); }
.resultats-adresse .vide { padding: 9px 12px; font-size: var(--t-12); color: var(--texte-doux); }
.recap-domicile {
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--trait);
  font-size: var(--t-12); color: var(--texte-doux); line-height: 1.5;
}
.recap-domicile strong { color: var(--texte); font-weight: 650; }

/* ------------------------------------------------------------
   LE MENU DES RÉGLAGES
   Treize titres de même poids, en petites capitales grises, ne se lisent
   pas : ils se parcourent. Chaque réglage porte donc une icône dans une
   pastille teintée et son nom en poids normal, et les treize sont rangés
   en quatre familles. Les teintes ne sont pas décoratives : ce sont
   celles des catégories du tableau de bord, si bien qu'un réglage de
   volet porte déjà le bleu des volets.
   ------------------------------------------------------------ */
.panneau-section.repliable { margin-bottom: 0; padding-bottom: 0; }
.panneau-section.repliable > h3 {
  display: flex; align-items: center; gap: 13px;
  margin: 0; padding: 11px 0; cursor: pointer; user-select: none; -webkit-user-select: none;
  font-size: var(--t-15); font-weight: 600; letter-spacing: -0.005em;
  color: var(--texte); text-transform: none;
  border-radius: var(--r-xs); transition: background var(--vite);
}
.panneau-section.repliable > h3:hover { background: var(--surface-creuse); }
.panneau-section.repliable > h3::after {
  content: ""; width: 7px; height: 7px; flex-shrink: 0; margin-right: 6px;
  border-right: 1.7px solid var(--texte-faible); border-bottom: 1.7px solid var(--texte-faible);
  transform: rotate(-45deg); transition: transform var(--moyen) var(--courbe);
}
.panneau-section.repliable.ouverte > h3::after { transform: rotate(45deg); }
.pastille-reglage {
  flex: none; width: 36px; height: 36px; border-radius: 10px;
  display: grid; place-items: center;
  background: var(--fond-reglage); color: var(--teinte-reglage);
}
.pastille-reglage svg { width: 21px; height: 21px; }
.reglage-texte { flex: 1; min-width: 0; }
/* Un réglage qui réclame une intervention (calibrage jamais fait, mesure
   à refaire) : sa pastille bat lentement en orange. Le titre reste
   lisible replié -- c'est justement quand la section est fermée qu'il
   faut que ça se voie. L'animation s'arrête d'elle-même si le système
   demande moins de mouvement (règle globale plus bas). */
.panneau-section.attention > h3 .pastille-reglage {
  background: var(--alerte-doux); color: var(--alerte);
  animation: battement-attention 1.8s ease-in-out infinite;
}
/* Le nom bat avec la pastille : sur un écran où l'on ne voit que du
   texte, une pastille qui clignote toute seule passe inaperçue. */
.panneau-section.attention > h3 .reglage-texte {
  color: var(--alerte); font-weight: 650;
  animation: texte-attention 1.8s ease-in-out infinite;
}
@keyframes battement-attention {
  50% { box-shadow: 0 0 0 5px var(--alerte-doux); }
}
@keyframes texte-attention {
  50% { opacity: .45; }
}
/* Quand la section qui réclame quelque chose est hors de l'écran, une
   flèche orange la montre, en bas du panneau et dans la colonne des
   chevrons -- là où l'œil cherche déjà les replis de section. Elle est
   collée au bas de la partie visible, au-dessus du bandeau de
   validation, et y mène au clic. */
.fleche-attention {
  position: sticky; z-index: 3; display: flex; margin: -14px 0 0 auto;
  bottom: calc(78px + env(safe-area-inset-bottom));
  width: 34px; height: 34px; align-items: center; justify-content: center;
  border-radius: 50%; border: 1px solid var(--alerte);
  background: var(--surface); color: var(--alerte); cursor: pointer; padding: 0;
  box-shadow: var(--ombre-2);
  animation: battement-attention 1.8s ease-in-out infinite;
}
.fleche-attention[hidden] { display: none; }
.fleche-attention svg { width: 18px; height: 18px; }
.fleche-attention.vers-le-haut svg { transform: rotate(180deg); }
.panneau-section.repliable > .panneau-section-corps { display: none; padding: 2px 0 16px 49px; }
.panneau-section.repliable.ouverte > .panneau-section-corps { display: block; }

/* Les familles. Le liseré épais va d'un bord à l'autre du panneau : il
   sépare des groupes, il ne décore pas une liste. */
.famille { padding-bottom: 2px; }
.famille + .famille {
  margin: 6px -24px 0; padding: 0 24px;
  border-top: 8px solid var(--surface-creuse);
}
.famille-tete { padding: 16px 0 8px; }
.famille-nom {
  font-size: var(--t-11); font-weight: 700; text-transform: uppercase;
  letter-spacing: .09em; color: var(--texte-doux);
}
/* Une famille dont tous les réglages sont masqués (non-administrateur,
   aucune tuile sélectionnée) ne doit pas laisser son titre tout seul. */
.famille.vide { display: none; }
.famille .panneau-section:last-child { border-bottom: none; }
@media (max-width: 600px) {
  .famille + .famille { margin-left: -18px; margin-right: -18px; padding-left: 18px; padding-right: 18px; }
}

/* Segmenté de choix de thème */
.segmente { display: flex; gap: 4px; background: var(--surface-creuse); border-radius: var(--r-sm); padding: 4px; }
.segmente button {
  flex: 1; padding: 9px 6px; border-radius: 9px; border: none; background: none;
  color: var(--texte-doux); font-size: var(--t-13); font-weight: 650; cursor: pointer;
  transition: background var(--vite), color var(--vite);
}
.segmente button:hover { color: var(--texte); }
.segmente button.actif { background: var(--surface); color: var(--texte); box-shadow: var(--ombre-1); }

/* ============================================================
   APPAREILS AJOUTÉS ET DÉCOUVERTE (panneau Réglages -> Appareils)
   ============================================================ */
.rangee-boutons-panneau { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.decouverte-resume { display: flex; align-items: center; gap: 8px; font-size: var(--t-12); font-weight: 600; margin: 10px 0 4px; }
.decouverte-resume > span:first-child { flex: 1; }
.fermer-decouverte {
  flex: none; width: 26px; height: 26px; border-radius: 50%; border: 1px solid var(--trait);
  background: var(--surface); color: var(--texte); font-size: var(--t-15); line-height: 1; cursor: pointer;
}
.fermer-decouverte:hover { background: var(--surface-creuse); }
.entete-fermable { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: var(--t-12); font-weight: 600; margin: 6px 0 2px; }
.lien-discret { background: none; border: none; padding: 6px 0; font: inherit; font-size: var(--t-12); color: var(--texte-doux); text-decoration: underline; cursor: pointer; }
.decouverte-duree { font-weight: 500; color: var(--texte-doux); }
.decouverte-filtres { display: flex; gap: 14px; flex-wrap: wrap; font-size: var(--t-12); color: var(--texte-doux); margin-bottom: 6px; }
.decouverte-filtres label { display: flex; align-items: center; gap: 5px; cursor: pointer; }
.decouverte-groupe { margin-top: 10px; }
.decouverte-item {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  padding: 8px 6px; border-top: 1px solid var(--trait);
}
.decouverte-item .chip-icone { width: 26px; height: 26px; border-radius: 8px; flex: none; }
.decouverte-item .chip-icone svg { width: 15px; height: 15px; }
.decouverte-texte { flex: 1 1 140px; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.decouverte-nom { font-size: var(--t-13); font-weight: 650; }
.decouverte-detail { font-size: var(--t-11); color: var(--texte-doux); overflow-wrap: anywhere; }
.decouverte-ports { opacity: .7; }
.decouverte-note { display: block; margin-top: 2px; color: var(--texte); }
.decouverte-etat { font-size: var(--t-11); color: var(--texte-doux); white-space: nowrap; }
.decouverte-grise .decouverte-nom { font-weight: 550; color: var(--texte-doux); }
.decouverte-item .bouton.compact { margin: 0; }
.decouverte-attente { padding: 10px 0; }
.decouverte-brut { font-family: ui-monospace, Menlo, monospace; font-size: var(--t-11); color: var(--texte-doux); overflow-wrap: anywhere; }
.formulaire-appareil .champ-double { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.formulaire-appareil .champ input:not([type=checkbox]), .formulaire-appareil .champ select {
  width: 100%; box-sizing: border-box;
}
.formulaire-appareil label.case { display: flex; align-items: center; gap: 7px; font-weight: 500; color: var(--texte); margin-top: 8px; }
.formulaire-appareil #tester-appareil { width: 100%; margin-top: 0; }
.pied-appareil-ajoute { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }

/* Bouton Loxone : une seule grande touche. Enceinte : six petites. */
.touche-impulsion {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  margin-top: 8px; padding: 10px 16px; border-radius: var(--r-pilule);
  background: var(--accent); color: var(--accent-contraste); font-size: var(--t-13); font-weight: 650;
  cursor: pointer; user-select: none; transition: transform var(--vite), background var(--vite);
}
.touche-impulsion svg { width: 16px; height: 16px; }
.touche-impulsion:active { transform: scale(.96); }
.touche-impulsion.attente { opacity: .6; }
.touche-impulsion.echec { background: var(--danger); }
.tuile.tuile-bouton .tuile-corps { justify-content: center; }
.touches-media { display: flex; gap: 5px; margin-top: 8px; flex-wrap: wrap; justify-content: center; }
.touche-media {
  width: 34px; height: 30px; border-radius: 9px; display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface-creuse); color: var(--texte); font-size: var(--t-15); cursor: pointer; user-select: none;
}
.touche-media:hover { background: var(--trait); }
.touche-media:active { transform: scale(.94); }
.touche-media.attente { opacity: .5; }
.media-apercu { font-size: var(--t-12); color: var(--texte-doux); text-align: center; }
.media-artiste { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.presets-media { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; margin-top: 6px; }
.preset-media {
  padding: 3px 8px; border-radius: var(--r-pilule); border: 1px solid var(--trait);
  font-size: var(--t-11); font-weight: 600; color: var(--texte); cursor: pointer; user-select: none;
}
.preset-media.actif { background: var(--accent); border-color: var(--accent); color: var(--accent-contraste); }
.preset-media.attente { opacity: .5; }
/* Le formulaire s'ouvre depuis le panneau des réglages, qui passe
   au-dessus des fenêtres (z 50) : le temps qu'il est ouvert, la
   fenêtre et son voile montent au-dessus de lui. */
.fenetre.devant-panneau { z-index: 61; }
.voile.devant-panneau { z-index: 60; }

/* ============================================================
   MODE ÉDITION
   ============================================================ */
@keyframes fremir {
  0%   { transform: rotate(-0.55deg) translate(0, 0); }
  50%  { transform: rotate(0.55deg) translate(0, -1px); }
  100% { transform: rotate(-0.55deg) translate(0, 0); }
}
.carte.mode-edition, .tuile.mode-edition {
  animation: fremir var(--lent) ease-in-out infinite; cursor: grab; z-index: 2;
  touch-action: none;
}
.carte.mode-edition:nth-child(even), .tuile.mode-edition:nth-child(even) { animation-delay: .1s; }
.carte.mode-edition { outline: 2px dashed transparent; outline-offset: 2px; }
.carte.mode-edition:hover { outline-color: var(--accent); }
.carte.mode-edition.selectionnee { outline: 2px solid var(--accent); }
.carte.mode-edition.deplacement {
  animation: none; z-index: 30; opacity: .95; box-shadow: var(--ombre-3);
}

.poignee-redim { position: absolute; right: 0; bottom: 0; width: 24px; height: 24px; cursor: nwse-resize; display: none; }
.carte.mode-edition .poignee-redim,
.tuile.mode-edition .poignee-redim { display: block; }
.poignee-redim::after {
  content: ""; position: absolute; right: 7px; bottom: 7px; width: 10px; height: 10px;
  border-right: 2px solid var(--accent); border-bottom: 2px solid var(--accent);
}
.bouton-suppr-carte {
  position: absolute; top: -8px; right: -8px; width: 25px; height: 25px; border-radius: 50%;
  z-index: 3;
  background: var(--danger); color: #FFF; border: none; display: none;
  align-items: center; justify-content: center; font-size: var(--t-15); line-height: 1;
  cursor: pointer; z-index: 2; box-shadow: var(--ombre-1);
}
.carte.mode-edition .bouton-suppr-carte { display: flex; }
.badge-favori {
  position: absolute; top: -8px; right: -8px; width: 26px; height: 26px; z-index: 3;
  border-radius: 50%; border: 1px solid var(--trait); display: none;
  align-items: center; justify-content: center; cursor: pointer; z-index: 2;
  font-size: var(--t-13); background: var(--surface); color: var(--texte-doux);
  box-shadow: var(--ombre-1);
}
.tuile.mode-edition .badge-favori { display: flex; }

/* Retirer une tuile d'une page de catégorie : la croix fait pendant à
   l'étoile, de l'autre côté. La tuile disparaît ; le clic droit sur la
   page (ou le rappel à côté du titre) la fait revenir. */
.bouton-masquer-tuile {
  position: absolute; top: -8px; left: -8px; width: 26px; height: 26px; z-index: 3;
  border-radius: 50%; border: none; display: none;
  align-items: center; justify-content: center; cursor: pointer;
  font-size: var(--t-15); line-height: 1; background: var(--danger); color: #FFF;
  box-shadow: var(--ombre-1);
}
.tuile.mode-edition .bouton-masquer-tuile { display: flex; }

.rappel-masquees {
  align-self: center; white-space: nowrap; cursor: pointer; background: none;
  font: inherit; font-size: var(--t-12); font-weight: 550; color: var(--texte-doux);
  border: 1px solid var(--trait); border-radius: var(--r-pilule);
  padding: 3px 10px; opacity: .85;
}
.rappel-masquees:hover { opacity: 1; background: var(--surface); }
.menu-masquees .chip-icone { width: 26px; height: 26px; flex: none; }
.menu-masquees .chip-icone svg { width: 15px; height: 15px; }
.badge-favori.est-favori { background: var(--accent); border-color: var(--accent); color: var(--accent-contraste); }

.barre-edition {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: var(--bas-flottant);
  display: none; gap: 8px; z-index: 35;
}
.barre-edition.visible { display: flex; }
body.en-edition .barre-bas { display: none; }
.bouton-edition-flottant {
  white-space: nowrap; background: var(--surface); border: 1px solid var(--trait);
  box-shadow: var(--ombre-2); color: var(--texte); border-radius: var(--r-pilule);
  padding: 13px 22px; font-size: var(--t-13); font-weight: 650; cursor: pointer;
  display: flex; align-items: center; gap: 8px; transition: background var(--vite), transform var(--vite);
}
.bouton-edition-flottant:hover { background: var(--surface-survol); }
.bouton-edition-flottant:active { transform: scale(.96); }
/* Sortir d'un côté, renoncer de l'autre : la couleur dit laquelle des
   deux garde le travail, sans avoir à lire. */
.bouton-edition-flottant.valider {
  background: var(--succes); border-color: var(--succes); color: var(--succes-contraste);
}
.bouton-edition-flottant.valider:hover { filter: brightness(1.06); background: var(--succes); }
.bouton-edition-flottant.annuler {
  background: var(--danger); border-color: var(--danger); color: var(--danger-contraste);
}
.bouton-edition-flottant.annuler:hover { filter: brightness(1.06); background: var(--danger); }
.astuce-appui-long {
  position: absolute; left: 0; right: 0; bottom: calc(var(--bas-flottant) + 70px); text-align: center;
  color: var(--texte-faible); font-size: var(--t-12); font-weight: 500;
  z-index: 6; pointer-events: none; opacity: 0; transition: opacity var(--lent);
}
.astuce-appui-long.visible { opacity: 1; }

/* Réglage de taille : deux compteurs en cases. Deux pastilles réglées
   sur les mêmes chiffres sont rigoureusement de la même taille -- c'est
   tout l'intérêt d'une grille par rapport à un ajustement au pixel. */
.reglage-taille { display: flex; gap: 10px; margin-bottom: 4px; }
.compteur-taille {
  flex: 1; background: var(--surface-douce); border: 1px solid var(--trait);
  border-radius: var(--r-sm); padding: 10px 10px 12px; text-align: center;
}
.compteur-taille-libelle {
  font-size: var(--t-11); font-weight: 700; color: var(--texte-doux);
  text-transform: uppercase; letter-spacing: .06em; margin-bottom: 8px;
}
.compteur-taille-ligne { display: flex; align-items: center; justify-content: center; gap: 10px; }
.compteur-taille-valeur {
  font-size: var(--t-24); font-weight: 700; min-width: 34px;
  font-variant-numeric: tabular-nums; line-height: 1;
}
.compteur-pas {
  width: 38px; height: 38px; border-radius: 50%; flex-shrink: 0;
  border: 1px solid var(--trait-fort); background: var(--surface);
  color: var(--texte); font-size: var(--t-19); line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background var(--vite), transform var(--vite);
}
.compteur-pas:hover { background: var(--surface-creuse); }
.compteur-pas:active { transform: scale(.9); }
.compteur-pas:disabled { opacity: .3; cursor: not-allowed; }
.apercu-forme {
  margin: 14px auto 4px; padding: 6px; min-height: 46px;
  border: 1px dashed var(--trait-fort); border-radius: 8px;
  display: flex; align-items: flex-start;
}
.apercu-bloc { background: var(--accent); border-radius: 4px; }

/* Empêche la sélection accidentelle pendant le glisser-déposer */
.carte, .tuile, .zone-cartes, .page-liste, .grille-pastilles {
  -webkit-touch-callout: none; -webkit-user-select: none; user-select: none;
}
.carte, .tuile { touch-action: manipulation; }

/* ============================================================
   TABLETTE MURALE — lisible à deux mètres
   ============================================================ */
@media (min-width: 821px) and (max-width: 1280px) and (pointer: coarse) {
  .horloge-heure { font-size: var(--t-82); }
  .carte-valeur { font-size: calc(var(--t-24) * var(--echelle, 1)); }
  .carte-nom { --taille-nom: 24px; }
  .tuile-etat { font-size: calc(var(--t-21) * var(--echelle, 1)); }
  .tuile-nom { --taille-nom: 21px; }
  
  .barre-bas-item { width: 58px; height: 58px; }
  .grille-pastilles { --hauteur-case: 28px; }
}

/* ============================================================
   TÉLÉPHONE
   ============================================================ */
@media (max-width: 820px) {
  .barre-haut { padding: 5px 16px; padding-top: calc(5px + var(--haut-sur)); }
  .page-titre, .horloge-interieur { padding-right: 96px; }
  .selecteur-courbes {
    position: static; transform: none; width: auto; flex: 1; min-width: 0; margin: 0 6px;
  }
  .bouton-selecteur-courbes { padding: 10px 12px; font-size: var(--t-12); gap: 6px; }
  .bouton-selecteur-courbes #texte-selecteur-courbes {
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
  }
  .page-graphiques { padding: calc(52px + var(--haut-sur)) 16px 96px; }
  .logo-texte { font-size: var(--t-15); }
  .logo-rond, .icone-ronde { width: 40px; height: 40px; }

  .horloge-zone { top: calc(14px + var(--haut-sur)); padding: 0 16px; }
  .horloge-interieur { flex-direction: column; align-items: stretch; gap: 14px; }
  .horloge-bloc { display: flex; align-items: baseline; gap: 12px; }
  .horloge-date { font-size: var(--t-13); margin-bottom: 0; }
  .horloge-heure { font-size: var(--t-40); letter-spacing: -0.03em; }
  .bandeau-resume { gap: 8px; }
  .puce-resume { flex: 1 1 calc(50% - 4px); min-width: 0; padding: 9px 11px 9px 9px; }
  .puce-resume .chip-icone { width: 30px; height: 30px; border-radius: 9px; }
  .puce-resume-valeur { font-size: var(--t-15); }
  .puce-resume-libelle { font-size: var(--t-11); }

  /* Sur téléphone, l'accueil devient une colonne qui défile d'un bloc :
     l'horloge, le résumé et les pastilles s'enchaînent au lieu d'être
     positionnés les uns par-dessus les autres à hauteur fixe. */
  .accueil {
    overflow-y: auto; -webkit-overflow-scrolling: touch;
    display: flex; flex-direction: column; gap: 16px;
    padding: calc(14px + var(--haut-sur)) 16px calc(76px + env(safe-area-inset-bottom));
  }
  .horloge-zone { position: static; top: auto; padding: 0; }
  .horloge-bloc { display: flex; align-items: baseline; gap: 11px; flex-wrap: wrap; }
  .horloge-heure { order: 1; }
  .horloge-date { order: 2; }
  .zone-cartes { padding: 0; }
  .grille-pastilles { --hauteur-case: 23.2px; --marge-case: 5px; }
  .carte { padding: 13px 14px; border-radius: var(--r-md); }
  .carte-valeur { font-size: calc(var(--t-17) * var(--echelle, 1)); }
  .carte-nom { --taille-nom: 18px; }
  .carte-soustitre { font-size: calc(var(--t-11) * var(--echelle, 1)); }
  
  .poignee-redim { display: none !important; }

  .page-liste { padding: calc(14px + var(--haut-sur)) 16px calc(76px + env(safe-area-inset-bottom)); }
  .page-plan { padding: calc(12px + var(--haut-sur)) 10px calc(88px + env(safe-area-inset-bottom)); }
  .page-titre h1 { font-size: var(--t-24); }
  .tuile { padding: 13px 14px; border-radius: var(--r-md); }
  
  .tuile-etat { font-size: calc(var(--t-17) * var(--echelle, 1)); }
  .tuile-nom { --taille-nom: 17px; }

  .page-graphiques { padding: calc(14px + var(--haut-sur)) 14px 66px; }
  body.sur-graphiques .logo-texte { display: none; }
  .selecteur-courbes { margin: 0 6px; max-width: none; }

  .barre-bas { bottom: var(--bas-flottant); }
  .barre-bas-item { width: 48px; height: 48px; }
  .barre-edition { bottom: var(--bas-flottant); }

  /* Les fenêtres deviennent des feuilles qui montent du bas */
  .fenetre, .fenetre-graphique, .fenetre-flux {
    left: 0; right: 0; top: auto; bottom: 0; transform: none;
    width: 100%; max-width: 100%; max-height: 90vh;
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    padding: 20px 18px calc(30px + env(safe-area-inset-bottom));
    border-left: none; border-right: none; border-bottom: none;
  }
  /* En feuille, la fiche caméra rend au flux les marges latérales : sur
     un téléphone, quarante pixels de marge, c'est un dixième de l'image. */
  .fenetre.fenetre-camera { padding-left: 0; padding-right: 0; }
  .fenetre.fenetre-camera > *:not(.cadre-video) { padding-left: 18px; padding-right: 18px; }
  .fenetre.fenetre-camera .cadre-video { border-radius: 0; }
  /* La petite tuile ne monte pas du bas comme une feuille : elle reste
     une tuile, posée au milieu de l'écran. */
  .fenetre.fenetre-menue {
    left: 50%; right: auto; top: 50%; bottom: auto;
    transform: translate(-50%, -50%);
    width: min(232px, calc(100vw - 56px)); max-width: none;
    border: 1px solid var(--trait); border-radius: var(--r-xl);
    padding: 13px 15px 15px;
  }
  .bouton-action { padding: 16px 6px; font-size: var(--t-12); }
  .valeur-geante { font-size: var(--t-40); }
  input[type=range] { height: 34px; }
  .schema-flux { height: 260px; }
  .ligne-flux-detail { gap: 14px; padding: 13px 2px; }
  .rond-flux { width: 54px; height: 54px; }
  .rond-flux svg { width: 23px; height: 23px; }
  .ligne-flux-detail.total .rond-flux { width: 64px; height: 64px; }
  .ligne-flux-detail.total .rond-flux svg { width: 28px; height: 28px; }
  .flux-detail-valeur { font-size: var(--t-19); }
  .ligne-flux-detail.total .flux-detail-valeur { font-size: var(--t-24); }
  .zone-graphique { height: 220px; }
  .panneau { width: calc(100% - 20px); right: -110%; padding: 22px 18px var(--bas-panneau); }
  .panneau.ouvert { right: 10px; }
  .pied-panneau { margin-left: -18px; margin-right: -18px; padding-left: 18px; padding-right: 18px; }
}

@media (max-width: 359px) {
  .grille-pastilles { --colonnes: 5 !important; }
  .puce-resume { flex-basis: 100%; }
}

/* ------------------------------------------------------------
   GESTES
   Une page balayée arrive du côté d'où l'on vient : le glissement
   dit dans quel sens on a tourné. Le disque « tirer pour actualiser »
   descend sous le doigt, se retourne quand on a tiré assez, tourne
   pendant la relecture, puis remonte.
   ------------------------------------------------------------ */
@keyframes arrivee-droite { from { opacity: 0; transform: translateX(28px); } to { opacity: 1; transform: none; } }
@keyframes arrivee-gauche { from { opacity: 0; transform: translateX(-28px); } to { opacity: 1; transform: none; } }
.arrive-droite { animation: arrivee-droite var(--moyen) var(--courbe) both; }
.arrive-gauche { animation: arrivee-gauche var(--moyen) var(--courbe) both; }

/* Glissement au doigt entre pages, comme les écrans d'accueil d'iOS : le
   temps du geste seulement, la page qui part et celle qui arrive se
   posent en plein écran l'une à côté de l'autre pour suivre le doigt.
   Une fois relâchées (page changée ou retour à l'origine), elles
   redeviennent des blocs normaux dans le flux. */
.glisse-page {
  position: fixed !important;
  top: 0; left: 0; right: 0; bottom: 0;
  z-index: 15;   /* au-dessus des autres pages (3/4), sous les barres fixes (20) */
  will-change: transform;
}
.glisse-page.glisse-anime { transition: transform var(--moyen) var(--courbe); }

/* ------------------------------------------------------------
   HORS CONNEXION
   Le NAS ne répond plus (VPN tombé, wifi perdu, proxy arrêté). Plutôt
   que des tuiles en erreur ou des valeurs qui sautent, un bandeau
   discret dit ce qui se passe et depuis quand ; les valeurs restent à
   l'écran, ternies, parce qu'elles restent la meilleure chose qu'on
   sache. Il se range tout seul dès que ça répond à nouveau.
   ------------------------------------------------------------ */
.bandeau-reseau {
  position: fixed; left: 50%; top: calc(var(--haut-sur) + 8px); z-index: 22;
  transform: translate(-50%, -140%); opacity: 0; pointer-events: none;
  display: flex; align-items: center; gap: 9px; max-width: calc(100vw - 32px);
  background: var(--surface); border: 1px solid var(--trait);
  box-shadow: var(--ombre-2); border-radius: var(--r-pilule);
  padding: 8px 15px; font-size: var(--t-13); color: var(--texte);
  /* Une seule ligne : un bandeau qui se plie en quatre sur un téléphone
     étroit inquiète plus qu'il n'informe. */
  white-space: nowrap; overflow: hidden;
  transition: opacity var(--moyen), transform var(--moyen) var(--courbe);
}
.bandeau-reseau.visible { opacity: 1; transform: translate(-50%, 0); }
.bandeau-reseau .pastille-reseau {
  width: 8px; height: 8px; border-radius: 50%; background: var(--alerte); flex: none;
}
.bandeau-reseau.revenu .pastille-reseau { background: var(--succes); }
.bandeau-reseau .age-reseau { color: var(--texte-doux); white-space: nowrap; }
/* Le disque « tirer pour actualiser » descend sous le bandeau. */
body.hors-ligne .tirer-actualiser { top: calc(var(--haut-sur) + 56px); }
/* Les valeurs restent lisibles, mais on voit qu'elles ne sont plus fraîches. */
body.hors-ligne .carte-valeur, body.hors-ligne .tuile-etat,
body.hors-ligne .puce-resume-valeur { opacity: .55; transition: opacity var(--lent); }

/* Alertes de connexion : seul l'administrateur les voit. Un bandeau
   pour ce qui n'a pas encore été vu, les mêmes lignes dans Réglages. */
.alertes-connexion {
  position: fixed; left: 50%; top: calc(var(--haut-sur) + 8px); z-index: 23;
  transform: translateX(-50%); width: min(560px, calc(100vw - 32px));
  max-height: calc(100vh - var(--haut-sur) - 32px); overflow-y: auto;
  background: var(--surface); border: 1px solid var(--trait); border-left: 4px solid var(--alerte);
  box-shadow: var(--ombre-2); border-radius: var(--r-md);
  padding: 12px 14px; font-size: var(--t-13); color: var(--texte);
}
.alertes-connexion[hidden] { display: none; }
.alertes-connexion-tete { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 4px; }
.alertes-connexion-tete strong { font-size: 14px; }
.alertes-connexion-tete button {
  background: none; border: 0; padding: 4px; color: var(--texte-doux);
  font: inherit; font-size: var(--t-12); text-decoration: underline; cursor: pointer;
}
.alerte-ligne { padding: 8px 0; border-top: 1px solid var(--trait); }
.alerte-ligne:first-child { border-top: 0; }
.alerte-ligne.lue { opacity: .7; }
.alerte-titre { display: flex; justify-content: space-between; gap: 10px; font-weight: 650; }
.alerte-heure { color: var(--texte-doux); font-weight: 400; white-space: nowrap; }
.alerte-texte { margin-top: 2px; overflow-wrap: anywhere; }
.alerte-detail { margin-top: 2px; color: var(--texte-doux); font-size: var(--t-12); overflow-wrap: anywhere; }
.alerte-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.alerte-actions .bouton { width: auto; margin-top: 0; padding: 8px 12px; font-size: var(--t-12); }
.alerte-actions .bouton.danger { color: var(--danger); }

/* Le service worker a trouvé une page plus récente sur le NAS */
.nouvelle-version {
  position: fixed; left: 50%; bottom: calc(var(--bas-flottant) + 74px); z-index: 21;
  transform: translate(-50%, 20px); opacity: 0; pointer-events: none;
  display: flex; align-items: center; gap: 12px;
  background: var(--texte); color: var(--surface); border: 0; border-radius: 999px;
  padding: 10px 10px 10px 16px; font: inherit; font-size: var(--t-13); box-shadow: var(--ombre-2);
  transition: opacity var(--moyen), transform var(--moyen) var(--courbe);
}
.nouvelle-version.visible { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
.nouvelle-version b { font-weight: 650; }
.nouvelle-version .bouton-version {
  border: 0; border-radius: 999px; padding: 7px 15px; font: inherit; font-size: var(--t-13);
  font-weight: 600; cursor: pointer; white-space: nowrap;
}
.nouvelle-version .bouton-version.oui { background: var(--accent); color: var(--accent-contraste); }
.nouvelle-version .bouton-version.non { background: rgba(255,255,255,.15); color: inherit; }

.tirer-actualiser {
  position: fixed; left: 50%; top: calc(var(--haut-sur) + 10px); z-index: 19;
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--surface); border: 1px solid var(--trait); box-shadow: var(--ombre-2);
  display: flex; align-items: center; justify-content: center; color: var(--texte-doux);
  pointer-events: none; opacity: 0;
  --tirer: 0px;
  transform: translate(-50%, calc(var(--tirer) - 60px));
  transition: opacity var(--moyen), transform var(--moyen) var(--courbe);
}
/* Tant que le doigt tire, le disque le suit sans inertie */
.tirer-actualiser.visible { opacity: 1; transition: opacity var(--moyen); }
.tirer-actualiser.en-cours { transition: opacity var(--moyen), transform var(--moyen) var(--courbe); }
.tirer-actualiser svg { width: 18px; height: 18px; transition: transform var(--moyen) var(--courbe); }
.tirer-actualiser .roue { display: none; }
.tirer-actualiser.arme { color: var(--accent); }
.tirer-actualiser.arme .fleche { transform: rotate(180deg); }
.tirer-actualiser.en-cours .fleche { display: none; }
.tirer-actualiser.en-cours .roue { display: block; animation: tourner-actualiser .9s linear infinite; }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}


/* ============================================================
   SCÉNARIOS
   Une rangée de boutons posée au-dessus des favoris : c'est le premier
   geste de la journée, il doit tomber sous le pouce avant tout le reste.
   La rangée défile horizontalement plutôt que de passer à la ligne --
   trois scénarios ne doivent pas repousser les pastilles hors de l'écran.
   ============================================================ */
.barre-scenarios {
  display: flex; gap: 8px; overflow-x: auto; padding: 0 0 10px;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.barre-scenarios::-webkit-scrollbar { display: none; }
.barre-scenarios[hidden] { display: none; }

.barre-scenarios .scenario {
  display: flex; align-items: center; gap: 7px; flex: 0 0 auto;
  padding: 9px 14px 9px 11px; border: 1px solid var(--trait);
  border-radius: 999px; background: var(--surface-douce); color: var(--texte);
  font: inherit; font-size: var(--t-13); font-weight: 650; cursor: pointer;
  transition: transform .12s ease, background .18s ease, border-color .18s ease;
}
.barre-scenarios .scenario:active { transform: scale(0.96); }
.barre-scenarios .scenario[disabled] { cursor: default; opacity: .75; }
.barre-scenarios .scenario.en-cours { border-color: var(--accent); background: var(--accent-doux); }
.barre-scenarios .scenario.echec { border-color: var(--danger); }
.barre-scenarios .scenario-icone { display: flex; width: 18px; height: 18px; opacity: .8; }
.barre-scenarios .scenario-icone svg { width: 100%; height: 100%; }
.barre-scenarios .scenario-nom { white-space: nowrap; }

/* ----- l'éditeur, dans les réglages ----- */
.ligne-scenario {
  border: 1px solid var(--trait); border-radius: var(--r-sm);
  background: var(--surface-douce); margin-bottom: 8px; overflow: hidden;
}
.ligne-scenario.ouvert { border-color: var(--accent); }
.scenario-entete { display: flex; align-items: center; gap: 10px; padding: 10px; }
.scenario-entete .scenario-icone { width: 20px; height: 20px; flex: 0 0 auto; opacity: .75; }
.scenario-entete .scenario-icone svg { width: 100%; height: 100%; }
.scenario-texte { flex: 1; min-width: 0; }
.scenario-titre { font-weight: 650; font-size: var(--t-13); }
.scenario-detail {
  font-size: var(--t-11); color: var(--texte-doux);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.scenario-entete .bouton { width: auto; margin: 0; padding: 6px 10px; font-size: var(--t-12); }

.scenario-edition { padding: 0 10px 10px; border-top: 1px solid var(--trait); }
.scenario-champ { display: block; margin: 10px 0 8px; font-size: var(--t-12); color: var(--texte-doux); }
.scenario-champ .champ { margin-top: 4px; }

.scenario-icones { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.scenario-icones .choix-icone {
  width: 38px; height: 38px; display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--trait); border-radius: var(--r-xs);
  background: var(--surface); cursor: pointer; padding: 8px;
}
.scenario-icones .choix-icone svg { width: 100%; height: 100%; }
.scenario-icones .choix-icone.actif { border-color: var(--accent); background: var(--accent-doux); }

.scenario-liste-actions { display: flex; flex-direction: column; gap: 5px; }
.scenario-action {
  display: flex; align-items: center; gap: 6px; padding: 7px 8px;
  border-radius: var(--r-xs); background: var(--surface); font-size: var(--t-12);
}
.scenario-action-texte { flex: 1; min-width: 0; }
.scenario-action .bouton { width: auto; margin: 0; padding: 4px 9px; font-size: var(--t-12); }
.scenario-vide { font-size: var(--t-12); color: var(--texte-doux); padding: 6px 2px; }

/* Les trois champs d'ajout tiennent sur une ligne au large, et se
   replient l'un sous l'autre sur un téléphone. */
.scenario-ajout {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin: 10px 0;
}
.scenario-ajout .champ { flex: 1 1 140px; min-width: 0; margin: 0; }
.scenario-ajout .scenario-valeur { flex: 0 0 76px; }
.scenario-ajout .bouton { width: auto; margin: 0; padding: 8px 12px; font-size: var(--t-12); }
.scenario-edition > .bouton.danger { width: 100%; margin: 0; font-size: var(--t-12); }

/* ============================================================
   EDF TEMPO
   La tuile tient deux jours côte à côte, chacun avec sa couleur et ses
   deux prix, puis trois barres pour la saison. Les couleurs sont celles
   d'EDF -- on ne les réinvente pas, c'est tout leur intérêt : on doit
   les reconnaître sans lire.
   ============================================================ */
:root {
  --tempo-bleu:  #2F6FD0;
  --tempo-blanc: #B9B2A6;
  --tempo-rouge: #C8382F;
}
:root:not([data-theme="light"]) { --tempo-blanc: #B9B2A6; }

.tempo-apercu { display: flex; flex-direction: column; gap: 8px; width: 100%; }
.tempo-attente { color: var(--texte-doux); font-size: var(--t-12); }

.tempo-jours { display: flex; gap: 8px; }
.tempo-jour {
  flex: 1 1 0; min-width: 0; display: flex; flex-direction: column;
  align-items: center; gap: 3px; text-align: center;
}
.tempo-quand { font-size: var(--t-11); color: var(--texte-doux); }
.tempo-pastille {
  width: 100%; padding: 5px 4px; border-radius: var(--r-xs);
  font-size: var(--t-12); font-weight: 700; color: #fff;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tempo-pastille.bleu  { background: var(--tempo-bleu); }
.tempo-pastille.rouge { background: var(--tempo-rouge); }
/* Le jour blanc est le seul dont le texte ne peut pas rester blanc. */
.tempo-pastille.blanc { background: var(--tempo-blanc); color: #241F19; }
.tempo-pastille.inconnue {
  background: transparent; color: var(--texte-doux);
  border: 1px dashed var(--trait-fort);
}
.tempo-prix {
  display: flex; gap: 6px; font-size: var(--t-11); color: var(--texte-doux);
  font-variant-numeric: tabular-nums;
}
.tempo-prix-absent { font-style: italic; }

.tempo-compteurs { display: flex; flex-direction: column; gap: 3px; }
.tempo-compteur { display: flex; align-items: center; gap: 6px; }
.tempo-barre {
  flex: 1; height: 5px; border-radius: 999px;
  background: var(--surface-creuse); overflow: hidden;
}
.tempo-barre i { display: block; height: 100%; border-radius: 999px; }
.tempo-barre i.bleu  { background: var(--tempo-bleu); }
.tempo-barre i.blanc { background: var(--tempo-blanc); }
.tempo-barre i.rouge { background: var(--tempo-rouge); }
.tempo-chiffres {
  font-size: var(--t-11); color: var(--texte-doux);
  font-variant-numeric: tabular-nums; min-width: 52px; text-align: right;
}

/* ----- le calendrier ----- */
.fenetre-tempo { max-width: 620px; }
.resume-tempo {
  display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: center;
  padding: 0 0 12px; font-size: var(--t-12);
}
.tempo-legende { display: flex; align-items: center; gap: 6px; }
.tempo-legende i { width: 11px; height: 11px; border-radius: 3px; display: block; }
.tempo-legende i.bleu  { background: var(--tempo-bleu); }
.tempo-legende i.blanc { background: var(--tempo-blanc); }
.tempo-legende i.rouge { background: var(--tempo-rouge); }
.tempo-legende-note { color: var(--texte-doux); font-size: var(--t-11); }

.calendrier-tempo {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 14px 16px; align-items: start; max-height: 62vh; overflow-y: auto;
}
.tempo-mois { min-width: 0; }
.tempo-mois-nom {
  font-size: var(--t-12); font-weight: 650; margin-bottom: 5px;
  text-transform: capitalize; color: var(--texte-doux);
}
.tempo-cases {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px;
  align-items: start;
}
.tempo-case {
  aspect-ratio: 1; display: flex; align-items: center; justify-content: center;
  border-radius: 4px; font-size: 10px; color: #fff; font-variant-numeric: tabular-nums;
}
.tempo-case.bleu  { background: var(--tempo-bleu); }
.tempo-case.rouge { background: var(--tempo-rouge); }
.tempo-case.blanc { background: var(--tempo-blanc); color: #241F19; }
/* Un jour à venir : la case existe, mais sa couleur n'est pas tombée. */
.tempo-case.inconnu { background: var(--surface-creuse); color: var(--texte-doux); }
.tempo-vide { color: var(--texte-doux); font-size: var(--t-12); padding: 14px 0; }

/* La pastille Tempo du bandeau porte la couleur du jour : c'est elle
   qu'on lit d'un coup d'oeil, le mot ne fait que la confirmer. */
/* Le libellé porte deux informations (« Tempo · Demain ● ») : cette
   pastille-là ne se laisse pas comprimer sous son texte, quitte à passer
   à la ligne -- le bandeau sait déjà se replier. */
.puce-resume[data-tempo] { min-width: max-content; }
.puce-resume[data-tempo] .chip-icone { color: #fff; }
.puce-resume[data-tempo="bleu"]  .chip-icone { background: var(--tempo-bleu); }
.puce-resume[data-tempo="rouge"] .chip-icone { background: var(--tempo-rouge); }
.puce-resume[data-tempo="blanc"] .chip-icone { background: var(--tempo-blanc); color: #241F19; }
/* Le lendemain : un point au bout du libellé, « Tempo · Demain ● ».
   Le blanc, seul à se confondre avec un fond clair, garde un liseré. */
.tempo-demain {
  display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  vertical-align: -1px; margin-left: 1px;
}
/* Sur téléphone le libellé se réduit à « Demain ● » : l'icône colorée et
   le nom de la couleur disent déjà qu'il s'agit de Tempo. */
@media (max-width: 820px) {
  .puce-resume[data-tempo].avec-demain .tempo-mot { display: none; }
  /* Chaque pastille garde au moins la largeur de son texte : deux tiennent
     côte à côte quand elles sont courtes, sinon celle qui déborde prend sa
     propre ligne -- plutôt qu'une valeur coupée en deux. */
  .puce-resume { min-width: max-content; }
}
.tempo-demain.bleu  { background: var(--tempo-bleu); }
.tempo-demain.rouge { background: var(--tempo-rouge); }
.tempo-demain.blanc { background: var(--tempo-blanc); border: 1px solid rgba(36,31,25,.35); }

/* L'alerte Tempo de la veille. Même forme que le bandeau du mode
   silencieux -- on ne multiplie pas les langages visuels --, mais
   bordée de la couleur du jour annoncé : elle doit se reconnaître
   avant d'être lue. */
.bandeau-tempo {
  position: fixed; left: 50%; top: calc(var(--haut-sur) + 8px); z-index: 24;
  transform: translateX(-50%); display: flex; align-items: center; gap: 10px;
  max-width: calc(100vw - 32px); padding: 8px 8px 8px 12px;
  background: var(--surface); border: 1px solid var(--trait);
  box-shadow: var(--ombre-2); border-radius: var(--r-pilule);
  font-size: var(--t-13); color: var(--texte);
}
.bandeau-tempo[hidden] { display: none; }
.bandeau-tempo-pastille {
  flex: 0 0 auto; padding: 3px 9px; border-radius: var(--r-pilule);
  font-size: var(--t-11); font-weight: 700; color: #fff;
}
.bandeau-tempo-pastille.rouge { background: var(--tempo-rouge); }
.bandeau-tempo-pastille.blanc { background: var(--tempo-blanc); color: #241F19; }
.bandeau-tempo-pastille.bleu  { background: var(--tempo-bleu); }
.bandeau-tempo button {
  flex: 0 0 auto; width: 26px; height: 26px; line-height: 1;
  border: 1px solid var(--trait); background: var(--surface-douce); color: var(--texte-doux);
  font: inherit; font-size: var(--t-13); border-radius: 50%; cursor: pointer;
}
.bandeau-tempo button:hover { background: var(--surface-creuse); color: var(--texte); }
/* Sur un téléphone, la phrase compte plus que la pilule : elle passe à
   la ligne plutôt que d'être tronquée. */
@media (max-width: 480px) {
  .bandeau-tempo { flex-wrap: wrap; border-radius: var(--r-md); }
}

/* ============================================================
   TABLETTE MURALE
   Un écran fixé au mur, allumé en permanence, qu'on utilise debout et
   souvent d'une main encombrée.
   ============================================================ */

/* L'atténuation nocturne. On assombrit sans éteindre : l'heure et les
   alarmes restent lisibles depuis le couloir, et le moindre geste rend
   la pleine lumière. La transition est lente à l'aller (on s'endort),
   immédiate au retour (on se réveille). */
.voile-nuit {
  position: fixed; inset: 0; z-index: 60; background: #000;
  opacity: 0.82;
  /* Le voile ARRÊTE le premier contact au lieu de le laisser passer :
     sans ça, le doigt qui réveille l'écran ouvrirait du même coup le
     volet ou la lampe qui se trouve dessous. Il se retire de lui-même
     dès ce contact (muralReveiller), et le geste suivant agit
     normalement. */
  pointer-events: auto; cursor: pointer;
  animation: voile-arrive 1.6s ease both;
}
/* La force est choisie dans les réglages : de 50 % (pénombre) à 99 %
   (quasi noir). 92 % au départ -- 82 % ne suffisait pas sur un iPad. */
.voile-nuit { opacity: var(--force-nuit, 0.92); }
.voile-nuit[hidden] { display: none; }
@keyframes voile-arrive { from { opacity: 0; } to { opacity: var(--force-nuit, 0.92); } }

/* Zones tactiles élargies. On ne change ni la grille ni les tailles de
   tuiles -- seulement ce qu'on vise : boutons, touches de volet, menu
   du bas. Viser un bouton de 28 px debout, à bout de bras, dans un
   couloir, ne marche pas. */
body.cibles-larges .bouton,
body.cibles-larges .touche-volet,
body.cibles-larges .barre-bas-item,
body.cibles-larges .scenario,
body.cibles-larges .segmente-fav button {
  min-height: 48px;
}
body.cibles-larges .touche-volet { min-width: 48px; }
body.cibles-larges .barre-bas-item { padding-top: 10px; padding-bottom: 10px; }
body.cibles-larges .scenario { padding: 12px 18px 12px 14px; font-size: var(--t-14, 14px); }
/* Les petites croix et pastilles de fermeture deviennent atteignables
   sans viser : on agrandit la zone sensible, pas le dessin. */
body.cibles-larges .fermer-fenetre,
body.cibles-larges .bandeau-tempo button,
body.cibles-larges .bandeau-silencieux button {
  min-width: 44px; min-height: 44px;
}

/* La tuile Tempo dans une case étroite.
   Deux colonnes de prix ne tiennent pas dans 100 px : le texte était
   rogné des deux côtés (« ujourd'hui », « 4C », « 3,56 »). Plutôt que de
   réduire la police jusqu'à l'illisible, on empile — les deux jours l'un
   sous l'autre, et chaque tarif sur sa ligne. La mesure porte sur la
   tuile elle-même, pas sur l'écran : la même tuile s'affiche en colonnes
   sur un téléphone et côte à côte une fois élargie. */
.tempo-apercu { container-type: inline-size; }

@container (max-width: 190px) {
  .tempo-jours { flex-direction: column; gap: 10px; }
  .tempo-prix { flex-direction: column; gap: 0; line-height: 1.35; }
}

/* Dans tous les cas, rien ne doit déborder de sa case. */
.tempo-jour, .tempo-prix, .tempo-pastille { min-width: 0; max-width: 100%; }
.tempo-prix span { white-space: nowrap; }
.tempo-apercu { overflow: hidden; }
/* Pendant qu'on déplace le curseur de réglage : le voile prend sa valeur
   sans fondu, sinon on règle à l'aveugle le temps de l'animation. */
.voile-nuit.sans-fondu { animation: none; }

/* Le voile de la photo, en thème sombre.
   Il valait 25 % dans les deux thèmes : une photo de plein jour restait
   donc aux trois quarts de sa luminosité sous une interface sombre, et
   éblouissait le soir. Il a désormais son propre réglage (Réglages →
   Image de fond → « Voile en thème sombre »), à 80 % par défaut. */
html[data-theme="sombre"] body.avec-image::after {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--fond-page)
      calc(var(--voile-fond-sombre, .8) * 100%), transparent) 0%,
    color-mix(in srgb, var(--fond-page)
      calc(min(var(--voile-fond-sombre, .8) + .08, .99) * 100%), transparent) 100%);
}

/* ============================================================
   LA VOITURE
   Le pourcentage en gros, une jauge avec la cible de charge, l'autonomie
   et l'état en une ligne, et surtout la date du relevé -- grisée quand
   elle vieillit, parce qu'un 70 % de la nuit dernière ne dit rien de ce
   qu'il y a dans la batterie maintenant.
   ============================================================ */
.voiture-apercu { display: flex; flex-direction: column; gap: 5px; width: 100%; min-width: 0; }
.voiture-attente { color: var(--texte-doux); font-size: var(--t-12); line-height: 1.35; }
.voiture-niveau { display: flex; align-items: center; gap: 10px; }
.voiture-pct { font-size: 26px; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.voiture-jauge {
  position: relative; flex: 1; height: 8px; border-radius: 999px;
  background: var(--surface-creuse); overflow: visible;
}
.voiture-jauge i { display: block; height: 100%; border-radius: 999px; background: var(--accent); }
/* La cible de charge réglée dans la voiture : un trait sur la jauge. */
.voiture-jauge b {
  position: absolute; top: -3px; width: 2px; height: 14px; margin-left: -1px;
  background: var(--texte-doux); border-radius: 1px;
}
.voiture-ligne { font-size: var(--t-13); font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.voiture-ligne span { font-weight: 500; color: var(--texte-doux); }
.voiture-doux { font-weight: 500; color: var(--texte-doux); font-size: var(--t-12); }
.voiture-releve { font-size: var(--t-11); color: var(--texte-doux); }
.voiture-releve.vieux { color: var(--danger); }

/* ------------------------------------------------------------
   PAGE VENTILATION
   Le dessin occupe toute la largeur et garde ses proportions ; les
   cartes et les commandes viennent dessous, comme sur la page
   Sécurité. Les couleurs de la scène (terre, herbe, mur) sont
   écrites en dur : c'est un décor, il ne doit pas s'inverser avec le
   thème -- seules ses valeurs de nuit sont adoucies.
   ------------------------------------------------------------ */
/* Même mécanique que les autres pages : plein écran, masquée tant
   qu'on n'y est pas. */
.page-ventilation {
  position: fixed; inset: 0; z-index: 4;
  padding: calc(16px + var(--haut-sur)) 26px calc(104px + env(safe-area-inset-bottom));
  overflow-y: auto; display: none;
}
.page-ventilation.visible { display: block; }
.page-ventilation-contenu { max-width: var(--largeur-max); margin: 0 auto; }
.svg-vmc { width: 100%; height: auto; display: block; }
.vmc-herbe { fill: #7FA05A; }
.vmc-dalle { fill: #B9B4AA; }
.vmc-mur { fill: #EFEAE0; }
.vmc-toit { stroke: #8C7B63; }
.vmc-prise { fill: #9AA0A6; }
.vmc-fente { fill: #6B7075; }
.vmc-gaine { stroke: #6B5335; }
.vmc-ombre { fill: #9A958B; opacity: .4; }
.pastille-vmc rect { fill: #FFFFFF; stroke: #D3D1C7; stroke-width: 1; }
.pv-titre { fill: #2C2C2A; font-size: 14px; font-weight: 650; }
.pv-sous { fill: #5F5E5A; font-size: 11px; font-weight: 500; }
html[data-theme="sombre"] .vmc-mur { fill: #35332F; }
html[data-theme="sombre"] .vmc-dalle { fill: #55524B; }
html[data-theme="sombre"] .vmc-herbe { fill: #4C6138; }
html[data-theme="sombre"] .pastille-vmc rect { fill: #2C2C2A; stroke: #5F5E5A; }
html[data-theme="sombre"] .pv-titre { fill: #F3F0EA; }
html[data-theme="sombre"] .pv-sous { fill: #ACA69C; }

.cartes-vmc {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px; margin-top: 18px;
}
.carte-vmc {
  background: var(--surface); border: 1px solid var(--trait);
  border-radius: var(--r-md); padding: 12px 14px; box-shadow: var(--ombre-1);
}
.carte-vmc.attention { border-color: var(--alerte); }
.carte-vmc.alarme { border-color: var(--danger); }
.cv-titre { font-size: var(--t-11); color: var(--texte-doux); letter-spacing: .02em; }
.cv-valeur {
  font-size: var(--t-21); font-weight: 700; margin-top: 2px;
  font-variant-numeric: tabular-nums; color: var(--texte);
}
.carte-vmc.alarme .cv-valeur { color: var(--danger); }
.cv-detail { font-size: var(--t-11); color: var(--texte-doux); margin-top: 2px; }

.commandes-vmc { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.bouton-vmc { font-variant-numeric: tabular-nums;
  flex: 1 1 130px; padding: 11px 12px; border-radius: 10px; cursor: pointer;
  border: 1px solid var(--trait); background: var(--surface);
  color: var(--texte-doux); font-size: var(--t-13); font-weight: 600;
}
/* Le mode en cours doit se voir de loin : un simple liseré vert sur
   fond clair passait inaperçu. On remplit le bouton de l'accent et on
   écrit dessus en contraste -- le même parti que la barre du bas. */
.bouton-vmc.actif {
  background: var(--accent); border-color: var(--accent);
  color: var(--accent-contraste); font-weight: 700;
  box-shadow: var(--ombre-1);
}
.bouton-vmc:disabled { opacity: .5; }
.vmc-erreurs { margin-top: 12px; font-size: var(--t-11); color: var(--danger); }

/* Sur un écran de Mac ou d'iPad, la page tient en entier : le dessin
   prend la place qui reste une fois les cartes et les commandes posées,
   et rien ne passe sous la barre du bas. Sur un téléphone, on garde le
   défilement -- tout empiler dans 700 px de haut ne serait lisible pour
   personne. */
@media (min-width: 700px) and (min-height: 600px) {
  /* « auto » et non « hidden » : si un écran plus petit que prévu
     ne peut pas tout contenir, mieux vaut un défilement qu'un bas
     de page coupé sans que personne le sache. */
  .page-ventilation { overflow: auto; }
  .page-ventilation-contenu {
    display: flex; flex-direction: column; gap: 14px;
    height: 100%; min-height: 0;
  }
  .page-ventilation .page-titre { margin-bottom: 0; flex: 0 0 auto; }
  #ventilation-contenu {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column; gap: 14px;
  }
  .svg-vmc { flex: 1 1 auto; min-height: 200px; height: 100%; }
  .cartes-vmc, .commandes-vmc { flex: 0 0 auto; margin-top: 0; }
  .commandes-vmc .bouton-vmc { flex: 1 1 110px; padding: 9px 10px; }
}

/* ============================================================
   LE PLANNING DE CHAUFFAGE
   Quatre écrans, comme l'application Netatmo : la semaine en barres,
   le jour en plages, la liste des jeux de températures, et le détail
   d'un jeu pièce par pièce. La teinte du jeu est portée par
   --teinte-jeu, posée au moment du dessin.
   ============================================================ */
.fenetre-planning { max-width: 560px; }
.planning-contenu { padding: 0 16px 20px; overflow-y: auto; }
.planning-contenu.occupe { opacity: .55; pointer-events: none; }
.planning-note { font-size: var(--t-12); color: var(--texte-faible);
  margin: 2px 2px 14px; line-height: 1.45; }
.planning-vide { padding: 24px 4px; color: var(--texte-doux); font-size: var(--t-13); }
.planning-section { font-size: var(--t-13); font-weight: 700; color: var(--accent);
  margin: 18px 2px 8px; }

/* --- la semaine --- */
.planning-semaine { display: flex; flex-direction: column; }
.ps-jour { display: flex; flex-direction: column; gap: 8px; width: 100%;
  background: transparent; border: 0; border-bottom: 0.5px solid var(--trait);
  padding: 14px 2px; cursor: pointer; }
.ps-entete { display: flex; align-items: center; justify-content: space-between; }
.ps-nom { font-size: var(--t-15); font-weight: 600; color: var(--texte); }
.ps-chevron { color: var(--texte-faible); font-size: var(--t-19); line-height: 1; }
.ps-barre { display: flex; gap: 2px; height: 14px; border-radius: 7px; overflow: hidden; }
.ps-tranche { display: block; border-radius: 7px; }

.planning-lien { display: flex; align-items: center; gap: 8px; width: 100%;
  background: transparent; border: 0; padding: 16px 2px; cursor: pointer;
  color: var(--alerte); font-size: var(--t-15); font-weight: 600; }

/* --- le jour --- */
.planning-plage { border-left: 3px solid var(--teinte-jeu); padding: 10px 0 14px 12px;
  margin-bottom: 14px; }
.pp-entete { display: flex; align-items: center; gap: 10px; }
.pj-pastille { display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; background: var(--teinte-jeu); flex: none; }
.pp-titre { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.pp-jeu { font-size: var(--t-15); font-weight: 600; color: var(--texte); }
.pp-horaire { font-size: var(--t-12); color: var(--texte-faible);
  font-variant-numeric: tabular-nums; }
.pp-retirer { border: 0; background: transparent; color: var(--texte-faible);
  font-size: var(--t-19); cursor: pointer; padding: 0 4px; }
.pp-retirer:active { color: var(--danger); }
.pp-heure { display: flex; align-items: center; gap: 8px; margin: 10px 0 2px; }
.pp-valeur { font-size: var(--t-15); font-weight: 700; color: var(--texte);
  font-variant-numeric: tabular-nums; min-width: 52px; text-align: center; }
.pp-legende { font-size: var(--t-12); color: var(--texte-faible); }
.pp-pas { width: 30px; height: 30px; border-radius: 50%; border: 0; flex: none;
  background: var(--surface-douce); color: var(--texte); font-size: var(--t-15);
  line-height: 1; cursor: pointer; }
.pp-pas:active { background: var(--accent); color: var(--accent-contraste); }

.planning-jeux { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.planning-jeu { display: flex; align-items: center; gap: 6px; border: 0; border-radius: 999px;
  padding: 6px 12px; font-size: var(--t-13); background: var(--surface-douce);
  color: var(--texte-doux); cursor: pointer; }
.planning-jeu.actif { background: var(--teinte-jeu); color: #fff; }
.pj-point { width: 8px; height: 8px; border-radius: 50%; background: var(--teinte-jeu); }
.planning-jeu.actif .pj-point { background: #fff; }

.planning-ajout { width: 100%; border: 1px dashed var(--trait); background: transparent;
  color: var(--texte-doux); border-radius: 12px; padding: 12px; font-size: var(--t-13);
  cursor: pointer; margin-top: 4px; }
.planning-ajout:active { border-color: var(--accent); color: var(--accent); }

/* --- les températures --- */
.planning-special { display: flex; align-items: center; gap: 10px; padding: 12px 2px;
  border-bottom: 0.5px solid var(--trait); color: var(--texte-doux); }
.psp-nom { flex: 1; font-size: var(--t-15); color: var(--texte); }
.psp-valeur { font-size: var(--t-15); font-weight: 700; color: var(--texte);
  font-variant-numeric: tabular-nums; min-width: 56px; text-align: center; }
.planning-ligne-jeu { display: flex; align-items: center; gap: 12px; width: 100%;
  background: transparent; border: 0; border-bottom: 0.5px solid var(--trait);
  padding: 12px 2px; cursor: pointer; }
.plj-nom { flex: 1; text-align: left; font-size: var(--t-15); color: var(--texte); }

/* --- un jeu, pièce par pièce --- */
.planning-jeu-entete { display: flex; align-items: center; gap: 12px; padding: 12px 2px; }
.planning-piece { padding: 10px 2px 14px; border-bottom: 0.5px solid var(--trait); }
.ppi-entete { display: flex; align-items: center; justify-content: space-between; }
.ppi-nom { font-size: var(--t-15); color: var(--texte); }
.ppi-valeur { font-size: var(--t-15); font-weight: 700; color: var(--texte);
  font-variant-numeric: tabular-nums; }
.ppi-curseur { width: 100%; margin-top: 10px; accent-color: var(--accent); height: 28px; }

.bouton-planning { margin-top: 8px; border: 0; border-radius: 999px; padding: 6px 14px;
  font-size: var(--t-13); font-weight: 600; cursor: pointer;
  background: var(--surface-douce); color: var(--texte-doux); }
.bouton-planning:active { background: var(--accent); color: var(--accent-contraste); }
.planning-mot { max-height: 0; overflow: hidden; margin: 0 16px;
  font-size: var(--t-12); color: var(--texte-doux); line-height: 1.4;
  transition: max-height var(--moyen) var(--courbe), padding var(--moyen) var(--courbe); }
.planning-mot.visible { max-height: 60px; padding: 8px 0 2px; }
.planning-mot.erreur { color: var(--danger); }
.pp-note { font-size: var(--t-12); color: var(--texte-faible); }
.pp-heures { display: flex; flex-wrap: wrap; gap: 14px; align-items: center;
  margin: 10px 0 2px; }
.pp-borne { display: inline-flex; align-items: center; gap: 6px; }
.planning-plage.neuve { animation: plage-neuve 2.4s var(--courbe); }
@keyframes plage-neuve {
  0%, 60% { background: color-mix(in srgb, var(--teinte-jeu) 14%, transparent); }
  100%    { background: transparent; }
}
.planning-lien.danger { color: var(--danger); }
.pp-sans-reglage { font-size: var(--t-12); color: var(--texte-faible);
  margin: 10px 0 2px; line-height: 1.45; }
.pp-saisie { border: 0; border-radius: 8px; padding: 4px 6px; min-width: 76px;
  background: var(--surface-douce); color: var(--texte); font: inherit;
  font-size: var(--t-15); font-weight: 700; font-variant-numeric: tabular-nums;
  text-align: center; }
.pp-saisie:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.planning-copie { display: flex; flex-wrap: wrap; gap: 4px 18px; margin-top: 6px;
  border-top: 0.5px solid var(--trait); }
.planning-copie .planning-lien { width: auto; padding: 14px 0; }

/* La touche unique de la tuile de chauffage : elle porte un mot plus
   long que les anciennes (« Confort · 21:15 », « Manuel · 2 h 47 »),
   donc elle prend toute la largeur libre et coupe proprement. */
.touches-chauffage .touche-mode { flex: 1 1 auto; min-width: 0; }
.touches-chauffage .touche-mode em { overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-style: normal; }
/* La croix garde un fond rouge très dilué, dessiné dans l'icône : la
   zone à toucher se voit sans tacher la tuile. Sa surface tactile
   déborde le dessin, pour rester confortable au doigt. */
.touches-chauffage .touche-croix { display: inline-flex; align-items: center;
  justify-content: center; margin-left: 2px; padding: 4px 2px; flex: 0 0 auto;
  margin-right: -2px; color: var(--danger); cursor: pointer; }
.touches-chauffage .touche-croix:active { opacity: .6; }

/* La flamme de la tuile de chauffage : coin haut droit, au-dessus de la
   couronne, sans gêner le doigt qui la règle. */
.chauffage-flamme { position: absolute; top: 8px; right: 10px; pointer-events: none;
  filter: drop-shadow(0 0 3px rgba(232, 130, 47, .45)); }

/* ------------------------------------------------------------
   COÛT DE L'ÉLECTRICITÉ
   Deux couleurs, toujours les mêmes : l'ambre pour la maison, l'indigo
   pour les bornes. Aucune ne reprend une couleur Tempo -- le bleu du
   jour bleu, par exemple, aurait fait croire à un lien qui n'existe pas.
   ------------------------------------------------------------ */
/* Palette n°4 (26/09/2026) : ardoise pour la maison, vert électrique
   pour la voiture ; clair = heures creuses, foncé = heures pleines. */
:root { --cout-maison: #5B6B7F; --cout-bornes: #16996A;
        --cout-maison-hc: #9AA7B8; --cout-maison-hp: #3E4C5E; --cout-bornes-hc: #7DD8B6; --cout-bornes-hp: #0B7A52; }
html[data-theme="sombre"] { --cout-maison: #A8B5C6; --cout-bornes: #52D1A0;
        --cout-maison-hc: #6F7D90; --cout-maison-hp: #C4CFDC; --cout-bornes-hc: #2E8C69; --cout-bornes-hp: #7FE6BE; }

.cout-apercu {
  display: flex; flex-direction: column; gap: 4px; width: 100%; min-width: 0;
  font-variant-numeric: tabular-nums;
}
.cout-attente { color: var(--texte-doux); font-size: var(--t-12); }
.cout-prix { display: flex; align-items: center; gap: 7px; min-width: 0; }
.tempo-pastille.petite {
  width: auto; display: inline-block; padding: 2px 7px; font-size: var(--t-11);
  flex: 0 0 auto; vertical-align: middle;
}
.cout-prix-texte {
  font-size: var(--t-12); color: var(--texte-doux);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cout-prix-texte b { color: var(--texte); font-weight: 700; }

.cout-tableau { display: flex; flex-direction: column; gap: 2px; }
.cout-ligne {
  display: grid; grid-template-columns: 1fr auto auto; column-gap: 12px; align-items: baseline;
  text-align: left;
}
.cout-ligne > span:first-child { justify-self: start; }
.cout-ligne > span:nth-child(2), .cout-ligne > span:nth-child(3) { text-align: right; min-width: 58px; }
.cout-entete { font-size: var(--t-10); font-weight: 650; text-transform: uppercase; letter-spacing: .04em; }
.cout-quand { font-size: var(--t-12); color: var(--texte-doux); white-space: nowrap; }
.cout-valeur { font-size: var(--t-15); font-weight: 700; }
.cout-apercu .maison, .cout-table .maison, .cout-legende .maison { color: var(--cout-maison); }
.cout-apercu .bornes, .cout-table .bornes, .cout-legende .bornes { color: var(--cout-bornes); }

.cout-barres { width: 100%; height: auto; display: block; overflow: visible; }
.cout-barres .pale { opacity: .38; }
.cout-zone { fill: transparent; }
.cout-zone.survolee { fill: var(--texte); fill-opacity: .07; }
.cout-bulle {
  position: fixed; z-index: 80; pointer-events: none;
  display: flex; flex-direction: column; gap: 1px; padding: 6px 9px;
  border-radius: 9px; background: var(--surface); border: 1px solid var(--trait);
  box-shadow: var(--ombre-2); font-size: var(--t-12); color: var(--texte-doux);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.cout-bulle[hidden] { display: none; }
.cout-bulle b { color: var(--texte); font-weight: 650; }
/* Dans la fiche, le choix de période a plus de place. */
.fenetre .cout-periode { margin: 12px 0 4px; gap: 6px; }
.fenetre .cout-periode-choix { font-size: var(--t-13); padding: 5px 4px; }
.fenetre .cout-periode-libelle { font-size: var(--t-15); }
.fenetre .cout-fleche { width: 30px; height: 28px; }
/* Dans la tuile, le graphique occupe ce que le texte laisse. */
.tuile-corps:has(> .cout-apercu) { flex: 1 1 auto; align-items: stretch; justify-content: flex-start; }
/* En mode réglage, deux boutons d'alerte se posent en bas de la tuile
   (coût, puis Tempo au-dessus) : sans cette réserve, ils tombaient en
   plein sur la rangée des tarifs, à peine lisibles par-dessus elle
   (26/09/2026). Le contenu se tasse d'autant, la place vide accueille
   les boutons. */
body.en-edition .tuile:has(.cout-apercu) .tuile-corps { padding-bottom: 66px; }
body.en-edition .carte:has(.condition-pastille.condition-seconde) .carte-corps { padding-bottom: 62px; }
.tuile-corps > .cout-apercu { flex: 1 1 auto; min-height: 0; }
.cout-barres-zone { position: relative; flex: 1 1 0; min-height: 28px; }
.cout-apercu > :not(.cout-barres-zone) { flex-shrink: 0; }
.cout-barres-zone .cout-barres { position: absolute; inset: 0; width: 100%; height: 100%; }
.cout-ligne-kwh .cout-valeur { font-size: var(--t-12); font-weight: 600; opacity: .8; }
.cout-valeur sup { font-size: .6em; margin-left: 1px; color: var(--texte-doux); }

/* Le choix de période : les cinq périodes sur toute la largeur, puis
   la période affichée entre ses deux flèches. */
.cout-periode { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.cout-periodes {
  display: flex; padding: 2px; gap: 2px;
  border-radius: var(--r-pilule); background: var(--surface-creuse);
}
.cout-periode-choix {
  flex: 1 1 0; min-width: 0; padding: 3px 2px; border-radius: var(--r-pilule);
  text-align: center; font-size: var(--t-11); font-weight: 650; line-height: 1.25;
  color: var(--texte-doux); cursor: pointer; white-space: nowrap;
}
.cout-periode-choix:hover { color: var(--texte); }
.cout-periode-choix.actif { background: var(--surface); color: var(--texte); box-shadow: var(--ombre-1); }
.cout-periode-nav { display: flex; align-items: center; gap: 6px; min-width: 0; }
.cout-fleche {
  flex: none; width: 24px; height: 22px; border-radius: 7px;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--t-17); line-height: 1; cursor: pointer; color: var(--texte);
  background: var(--surface-creuse);
}
.cout-fleche:hover { background: var(--trait); }
.cout-fleche.inactive { opacity: .3; cursor: default; }
.cout-periode-libelle {
  flex: 1; min-width: 0; text-align: center; font-size: var(--t-13); font-weight: 650; color: var(--texte);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cout-periode-libelle[role=button] { cursor: pointer; text-decoration: underline dotted; text-underline-offset: 3px; }
.cout-plage-ligne {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 5px 10px; font-size: var(--t-13);
}
.cout-plage-ligne input { font: inherit; }

/* Les trois couleurs Tempo, en bas : un trait de la couleur à gauche de
   chaque colonne, les deux prix dessous. */
.cout-tarifs {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px;
  padding-top: 4px; border-top: 1px solid var(--trait); text-align: left;
  line-height: 1.2;
}
.cout-tarif {
  display: flex; flex-direction: column; gap: 1px; min-width: 0;
  padding-left: 7px; border-left: 3px solid var(--trait-fort);
}
.cout-tarif.bleu  { border-left-color: var(--tempo-bleu); }
.cout-tarif.blanc { border-left-color: var(--tempo-blanc); }
.cout-tarif.rouge { border-left-color: var(--tempo-rouge); }
.cout-tarif-nom {
  font-size: var(--t-10); font-weight: 650; text-transform: uppercase;
  letter-spacing: .04em; color: var(--texte-doux);
}
.cout-tarif.du-jour .cout-tarif-nom { color: var(--texte); }
.cout-tarif-prix { font-size: var(--t-11); color: var(--texte-doux); white-space: nowrap; }
.cout-tarif-prix b { font-weight: 600; color: var(--texte); }
.cout-tarif-prix.en-cours b { font-weight: 800; }
/* La période qui court : surlignée, comme au feutre, pour qu'on la
   trouve sans lire les six prix. */
.cout-tarif-prix.en-cours {
  color: var(--texte); align-self: flex-start;
  margin-left: -4px; padding: 0 4px; border-radius: 4px;
  background: color-mix(in srgb, var(--accent) 22%, transparent);
}
.cout-barre-maison { fill: var(--cout-maison); }
.cout-barre-bornes { fill: var(--cout-bornes); }
.cout-barre-maison-hc { fill: var(--cout-maison-hc); }
.cout-barre-maison-hp { fill: var(--cout-maison-hp); }
.cout-barre-bornes-hc { fill: var(--cout-bornes-hc); }
.cout-barre-bornes-hp { fill: var(--cout-bornes-hp); }
.cout-jour-tempo.bleu  { fill: var(--tempo-bleu); }
.cout-jour-tempo.blanc { fill: var(--tempo-blanc); }
.cout-jour-tempo.rouge { fill: var(--tempo-rouge); }
.cout-jour-tempo.inconnue { fill: none; stroke: var(--trait-fort); stroke-width: 1; }

.cout-table { width: 100%; border-collapse: collapse; margin-top: 10px; font-variant-numeric: tabular-nums; }
.cout-table th, .cout-table td { padding: 6px 4px; text-align: right; font-size: var(--t-13); vertical-align: top; }
.cout-table thead th { font-size: var(--t-11); color: var(--texte-doux); font-weight: 650; }
.cout-table tbody th { text-align: left; font-weight: 600; color: var(--texte); white-space: nowrap; }
.cout-table tbody tr + tr th, .cout-table tbody tr + tr td { border-top: 1px solid var(--trait); }
.cout-table td { font-weight: 700; }
.cout-table td small { display: block; font-size: var(--t-10); font-weight: 500; color: var(--texte-doux); }
.cout-repartition td { font-weight: 600; }
.cout-legende {
  display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 6px;
  font-size: var(--t-11); color: var(--texte-doux);
}
.cout-legende .maison-hc::before { background: var(--cout-maison-hc); }
.cout-legende .maison-hp::before { background: var(--cout-maison-hp); }
.cout-legende .bornes-hc::before { background: var(--cout-bornes-hc); }
.cout-legende .bornes-hp::before { background: var(--cout-bornes-hp); }
.cout-legende [class^="maison-"]::before, .cout-legende [class^="bornes-"]::before {
  content: ""; display: inline-block; width: 9px; height: 9px; border-radius: 2px; margin-right: 5px; vertical-align: -1px;
}
.cout-legende .maison::before, .cout-legende .bornes::before {
  content: ""; display: inline-block; width: 9px; height: 9px; border-radius: 2px;
  margin-right: 5px; background: currentColor; vertical-align: -1px;
}
.cout-table .cout-partiel { display: block; font-size: var(--t-10); font-weight: 500; color: var(--texte-doux); }
.cout-prevision { font-size: var(--t-11); color: var(--texte-doux); text-align: left; }
.cout-prevision b { color: var(--texte); }
.cout-veille.alerte { font-size: var(--t-11); font-weight: 650; color: var(--danger); text-align: left; }
.cout-prevision-bloc { margin-top: 12px; }
.cout-prevision-chiffre { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: var(--t-13); }
.cout-prevision-chiffre b { font-size: var(--t-19); font-weight: 700; }
.cout-prevision-chiffre.alerte b { color: var(--danger); }
.veille-graphe { width: 100%; height: auto; display: block; margin-top: 6px; }
.veille-barre { fill: var(--cout-maison); opacity: .75; }
.veille-barre.alerte { fill: var(--danger); opacity: 1; }
.veille-repere { stroke: var(--texte-doux); stroke-width: 1; stroke-dasharray: 3 3; }
.tempo-conseil {
  display: flex; align-items: flex-start; gap: 7px; margin-top: 8px; padding: 7px 9px;
  border-radius: 10px; background: var(--surface-creuse); font-size: var(--t-11); line-height: 1.35;
  color: var(--texte-doux); text-align: left;
}
.tempo-conseil svg { width: 15px; height: 15px; flex: none; margin-top: 1px; }
.tempo-conseil.urgent { background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--texte); }
.tempo-conseil.patienter { color: var(--texte); }
.cout-comparaison td.plus { color: var(--danger); }
.cout-comparaison td.moins { color: var(--succes); }
.cout-comparaison tr.moins-cher th::after { content: " ✓"; color: var(--succes); }
.cout-tarifs-form { margin-top: 10px; }
.cout-tarifs-form summary { cursor: pointer; font-size: var(--t-12); font-weight: 600; color: var(--texte-doux); }
.cout-tarifs-form form { margin-top: 8px; }
.cout-tarifs-form .champ-double { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.cout-tarifs-form input { width: 100%; box-sizing: border-box; }

/* ----- Tempo fondu dans la tuile coût (26/09/2026) -----
   Aujourd'hui et demain côte à côte, leurs deux prix dessous, le bouton
   du calendrier au bout de la ligne. */
.cout-tempo {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
  gap: 8px; align-items: start;
  padding-bottom: 5px; border-bottom: 1px solid var(--trait);
}
.cout-tempo-jour { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cout-tempo-tete { display: flex; align-items: center; gap: 6px; min-width: 0; }
.cout-tempo-quand { font-size: var(--t-11); color: var(--texte-doux); white-space: nowrap; }
.cout-tempo-prix { display: flex; gap: 6px; flex-wrap: wrap; line-height: 1.25; }
.cout-tempo-absent { font-size: var(--t-11); color: var(--texte-doux); font-style: italic; }
.cout-calendrier {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: var(--r-sm); cursor: pointer;
  background: var(--surface-creuse); color: var(--texte-doux);
}
.cout-calendrier:hover { background: var(--trait); color: var(--texte); }
.cout-calendrier svg { width: 17px; height: 17px; }
.cout-apercu .tempo-conseil { font-size: var(--t-11); }
.cout-tarif-compte { font-weight: 500; letter-spacing: 0; text-transform: none; opacity: .85; margin-left: 2px; }
/* Le second bouton d'alerte (Tempo) de la tuile coût, au-dessus du premier. */
body.en-edition .tuile .condition-pastille.condition-seconde { bottom: 40px; }
/* Le calendrier : le mois en cours en haut, et le jour même entouré. */
.tempo-mois.en-cours .tempo-mois-nom { color: var(--texte); }
.tempo-case.aujourdhui { box-shadow: 0 0 0 2px var(--texte); }
.cout-tempo.compacte {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding-bottom: 3px;
}
.cout-tempo.compacte .cout-calendrier { width: 26px; height: 22px; margin-left: auto; }
.cout-tempo.compacte .cout-calendrier svg { width: 15px; height: 15px; }
.cout-tempo-courant { font-size: var(--t-12); color: var(--texte-doux); white-space: nowrap; }
.cout-tempo-courant b { color: var(--texte); font-weight: 700; }
/* La pastille de condition, sur une carte d'accueil : le même fond
   plein que sur les tuiles -- sans lui, elle flottait à peine visible
   sur un contenu riche comme celui du coût (26/09/2026). */
body.en-edition .carte .condition-pastille {
  left: 8px; right: 8px; bottom: 4px; z-index: 3;
  background: var(--stabilo); border: 1px solid transparent; border-radius: 8px;
  padding: 5px 11px; color: var(--texte); font-size: var(--t-12); font-weight: 650; letter-spacing: 0;
  box-shadow: 0 0 0 3px var(--stabilo-halo), 0 0 12px var(--stabilo-halo);
}
body.en-edition .carte .condition-pastille:hover { background: var(--stabilo-fort); }
body.en-edition .carte .condition-pastille.sans-regle {
  background: transparent; border-color: var(--trait); box-shadow: none;
  color: var(--texte-doux); font-weight: 600;
}
body.en-edition .carte .condition-pastille.sans-regle:hover { background: var(--stabilo-doux); }
body.en-edition .carte .condition-pastille.condition-seconde { bottom: 38px; }
/* Une carte trop basse pour le bouton reçoit de la place en mode réglage. */
body.en-edition .carte[data-reglable] .carte-corps { padding-bottom: 30px; }

/* Le nom et le compteur de la saison tiennent sur une ligne : une
   rangée de plus ferait rétrécir tout le texte de la tuile. */
.cout-tarif-nom { white-space: nowrap; overflow: hidden; text-overflow: clip; }
.cout-tempo.compacte { padding-bottom: 2px; line-height: 1.1; }
.cout-tempo.compacte .cout-calendrier { height: 18px; width: 24px; }
.cout-tempo.compacte .cout-calendrier svg { width: 14px; height: 14px; }
.cout-tarif-compte { margin-left: 0; }

/* La couleur Tempo sous chaque barre de la tuile : un petit rond. */
.cout-barres-zone .cout-barres { bottom: auto; height: calc(100% - 8px); }
.cout-points {
  position: absolute; left: 0; right: 0; bottom: 0; height: 6px;
  display: grid; align-items: center; justify-items: center; pointer-events: none;
}
.cout-points i { display: block; width: 5px; height: 5px; border-radius: 50%; }
.cout-points i.bleu  { background: var(--tempo-bleu); }
.cout-points i.blanc { background: var(--tempo-blanc); box-shadow: inset 0 0 0 0.5px var(--trait-fort); }
.cout-points i.rouge { background: var(--tempo-rouge); }
.cout-points i.pale { opacity: .38; }

/* ----- Les trois phases en une tuile (26/09/2026) -----
   Total en grand, une jauge verte par phase ; jauge pleine = le tiers
   de la puissance souscrite. */
.tuile-corps:has(> .phases-apercu) { align-items: stretch; justify-content: flex-start; }
.phases-apercu { display: flex; flex-direction: column; gap: 5px; width: 100%; min-width: 0; font-variant-numeric: tabular-nums; }
.phases-total { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.phases-total b { font-size: var(--t-24); font-weight: 700; color: var(--texte); }
.phases-total span { font-size: var(--t-11); color: var(--texte-doux); white-space: nowrap; }
.phases-ligne {
  display: grid; grid-template-columns: 22px minmax(0, 1fr) 56px; gap: 8px; align-items: center;
  cursor: pointer; border-radius: 6px;
}
.phases-ligne:hover .phases-nom { color: var(--texte); }
.phases-nom { font-size: var(--t-12); color: var(--texte-doux); font-weight: 600; }
.phases-jauge { height: 8px; border-radius: 999px; background: var(--surface-creuse); overflow: hidden; }
.phases-jauge i { display: block; height: 100%; border-radius: 999px; background: var(--vert-phase, #1D9E75); }
.phases-valeur { font-size: var(--t-13); font-weight: 650; text-align: right; white-space: nowrap; }
.phases-note { font-size: var(--t-10); color: var(--texte-doux); }
:root[data-theme="sombre"] { --vert-phase: #3FC193; }

/* Le bouton du calendrier porte son nom, en petit, à côté de l'icône
   (26/09/2026). Deux lignes courtes : la bande Tempo garde sa hauteur. */
.cout-calendrier, .cout-tempo.compacte .cout-calendrier {
  width: auto; gap: 4px; padding: 2px 6px 2px 4px; flex: 0 0 auto;
}
.cout-calendrier-texte {
  font-size: var(--t-9); line-height: 1.05; font-weight: 600; text-align: left;
  white-space: nowrap; color: inherit;
}
.fenetre .cout-calendrier-texte { font-size: var(--t-10); }
/* Une tuile étroite n'a pas la place pour tout : le prix qui court
   s'efface de la bande (il reste surligné dans la rangée des tarifs, en
   bas), et le nom du calendrier garde sa place. */
.cout-apercu { container: cout-apercu / inline-size; }
.cout-tempo.compacte > * { flex-shrink: 0; }
@container cout-apercu (max-width: 294px) {
  .cout-tempo.compacte .cout-tempo-courant { display: none; }
}

/* La fenêtre de réglage d'une tuile se prend par sa barre de titre
   (26/09/2026). En feuille, sur téléphone, elle ne bouge pas. */
@media (min-width: 821px) {
  .fenetre.fenetre-deplacable .fenetre-entete { cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; }
  .fenetre.fenetre-deplacable .fenetre-entete .fermer-fenetre { cursor: pointer; }
  .fenetre.fenetre-en-deplacement, .fenetre.fenetre-en-deplacement .fenetre-entete { cursor: grabbing; }
  .fenetre.fenetre-deplacable .fenetre-entete::before {
    content: ""; position: absolute; left: 50%; top: 8px; width: 36px; height: 4px;
    margin-left: -18px; border-radius: 999px; background: var(--trait-fort); opacity: .7;
  }
}
body.attente-calendrier, body.attente-calendrier * { cursor: progress !important; }
.veille-alerte { color: var(--danger); }

/* « Demain rouge » : la pastille est entièrement rouge, en tête de la
   barre (26/09/2026). */
.alerte-haut.alerte-rouge { background: var(--tempo-rouge); border-color: var(--tempo-rouge); color: #fff; }
.alerte-haut.alerte-rouge .chip-icone { background: rgba(255,255,255,.22); color: #fff; }
.alerte-haut.alerte-rouge .alerte-haut-etat { color: #fff; }
.appareil-choix.alerte-rouge { background: var(--tempo-rouge); color: #fff; }
.appareil-choix.alerte-rouge .chip-icone { background: rgba(255,255,255,.22); color: #fff; }
.appareil-choix.alerte-rouge .piece-choix { color: #fff; font-weight: 650; }

/* Le menu de réglage d'une condition se prend par son titre
   (26/09/2026) : un trait de préhension le signale. */
#condition-menu .plan-menu-titre {
  position: relative; padding-top: 13px; cursor: grab;
  touch-action: none; user-select: none; -webkit-user-select: none;
}
#condition-menu .plan-menu-titre::before {
  content: ""; position: absolute; left: 50%; top: 4px; width: 36px; height: 4px;
  margin-left: -18px; border-radius: 999px; background: var(--trait-fort); opacity: .7;
}
#condition-menu.en-deplacement, #condition-menu.en-deplacement .plan-menu-titre { cursor: grabbing; }
/* La grandeur d'une condition, quand l'appareil en mesure plusieurs. */
.ligne-condition .condition-champ { max-width: 46%; }
.ligne-condition .condition-champ[hidden] { display: none; }
/* La saisie d'une condition suit le genre de la grandeur : une date ou
   une heure ont leur sélecteur, un marche/arrêt n'a rien à saisir. */
.ligne-condition input[data-role="valeur"][hidden] { display: none; }
.ligne-condition input[type="date"], .ligne-condition input[type="time"] { min-width: 120px; }

/* ----- Conditions d'étiquette et d'heure du jour (27/09/2026) -----
   Décisions 1 et 3 de Fred. Ce que moteur.js (ajouterLigne) pose :
   - ligne d'étiquette : .ligne-condition.condition-etiquette, avec ses
     menus propres select.condition-groupe (la grandeur : « Volets ·
     ouvert ») et select.condition-quant (au moins un, tous, aucun,
     moyenne…) ;
   - ligne d'heure : .ligne-condition.condition-heure, les deux champs
     input[type="time"] (« de », « à ») dans un span.condition-plage,
     chacun dans un label avec son mot.
   Ces lignes vivent dans un menu de 320 px au plus ou dans le panneau :
   elles sont étroites partout, pas seulement sur téléphone. */

/* Étiquette : deux lignes -- ce qu'on regarde (l'étiquette, la
   grandeur), puis comment on en juge (quantificateur, comparaison,
   valeur, unité, croix). Chacune des deux premières prend la moitié de
   la première ligne ; un libellé trop long est coupé, pas la ligne. */
.ligne-condition.condition-etiquette select { min-width: 0; text-overflow: ellipsis; }
.ligne-condition.condition-etiquette select[data-role="appareil"],
.ligne-condition.condition-etiquette .condition-groupe { flex: 1 1 calc(50% - 3px); max-width: none; }
.ligne-condition.condition-etiquette .condition-quant,
.ligne-condition.condition-etiquette select[data-role="operateur"] { flex: 1 1 0; }
.ligne-condition .condition-groupe[hidden], .ligne-condition .condition-quant[hidden] { display: none; }
/* Grandeur unique (menu caché) : l'étiquette garde la ligne pour elle. */
.ligne-condition.condition-etiquette .condition-groupe[hidden] + .condition-quant { flex-basis: calc(50% - 3px); }

/* Heure du jour : les deux heures côte à côte, qui se partagent ce que
   le menu laisse -- ou toute une ligne quand il n'en laisse pas assez. */
.condition-plage { display: flex; align-items: center; gap: 6px; flex: 2 1 220px; min-width: 0; }
.condition-plage label {
  display: inline-flex; align-items: center; gap: 5px; flex: 1 1 0; min-width: 0;
  font-size: var(--t-12); color: var(--texte-doux); white-space: nowrap;
}
.ligne-condition .condition-plage input[type="time"],
.ligne-condition.condition-heure input[type="time"] { flex: 1 1 auto; width: 100%; min-width: 0; }
@media (max-width: 640px) {
  .ligne-condition.condition-heure select[data-role="appareil"] { flex-basis: 100%; }
  .condition-plage { flex-basis: 100%; }
}

/* La notification d'une tuile, sous son alerte dans le même menu. */
.bloc-notification-tuile { border-top: 1px solid var(--trait); margin-top: 10px; padding-top: 4px; }
.bloc-notification-tuile .plan-menu-titre { padding-left: 0; padding-right: 0; }
.bloc-notification-tuile .champ input { width: 100%; box-sizing: border-box; }

/* Réglages → Notifications : la liste des règles et l'éditeur d'une règle. */
.ligne-notification {
  display: flex; align-items: center; gap: 8px; padding: 8px 0;
  border-bottom: 1px solid var(--trait); font-size: var(--t-13);
}
.ligne-notification-texte { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
/* Les boutons du panneau sont en pleine largeur par défaut : ici ils
   restent à leur taille, sinon le texte de la règle se retrouvait écrasé
   sur une colonne d'une lettre (26/09/2026). */
#panneau .ligne-notification .bouton, .ligne-notification .bouton {
  flex: 0 0 auto; width: auto; margin: 0; padding: 6px 10px; font-size: var(--t-12); white-space: nowrap;
}
/* « Envoyer un essai » et « Désactiver » côte à côte, à parts égales
   (26/09/2026, demande de Fred) : le texte se plie ou se resserre pour
   tenir dans sa moitié plutôt que d'empiler les boutons. Seul, « Activer
   sur cet appareil » garde toute la largeur. */
.boutons-notifications { display: flex; gap: 8px; align-items: stretch; }
#panneau .boutons-notifications .bouton {
  flex: 1 1 0; min-width: 0; width: auto; margin: 0; padding: 10px 8px;
  white-space: normal; line-height: 1.25; font-size: var(--t-12);
  display: flex; align-items: center; justify-content: center; text-align: center;
}
#panneau .boutons-notifications .bouton[hidden] { display: none; }
#panneau .editeur-notification .fermer-fenetre { width: 30px; height: 30px; flex: none; margin: 0; }
#panneau .bloc-notification-tuile .champ input { width: 100%; }
.editeur-notification {
  border: 1px solid var(--trait); border-radius: var(--r-md); padding: 10px 12px;
  background: var(--surface-creuse);
}
.editeur-notification-tete { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }
.editeur-notification .bloc-notification-tuile { border-top: none; margin-top: 0; padding-top: 0; }
/* Le choix de la tuile, en tête de la fenêtre de création : la pièce en
   gros une seule fois, ses catégories en intertitres, puis les tuiles. */
.choix-tuile-notification {
  max-height: min(52vh, 420px); overflow-y: auto; margin: 6px -4px 4px; padding: 0 4px 6px;
  overscroll-behavior: contain;
}
.choix-tuile-notification[hidden], .tuile-notification-choisie[hidden] { display: none; }
.ctn-piece {
  font-size: var(--t-15); font-weight: 700; color: var(--texte);
  margin: 16px 0 2px; padding-bottom: 4px; border-bottom: 1px solid var(--trait);
}
.ctn-piece:first-child { margin-top: 4px; }
.ctn-categorie {
  font-size: var(--t-11); font-weight: 700; color: var(--texte-doux);
  text-transform: uppercase; letter-spacing: .07em; margin: 10px 0 2px 2px;
}
#panneau .ctn-tuile {
  display: block; width: 100%; margin: 0; padding: 8px 10px; box-sizing: border-box;
  background: none; border: 0; border-radius: var(--r-xs); text-align: left;
  color: var(--texte); font-size: var(--t-13); font-weight: 500; cursor: pointer;
}
#panneau .ctn-tuile:hover { background: var(--surface-survol); }
#panneau .ctn-tuile.choisie { background: var(--stabilo-doux); }
.tuile-notification-choisie {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 6px 0 10px; padding: 8px 10px; border-radius: var(--r-sm); background: var(--surface);
}
.ctn-resume { display: flex; flex-direction: column; min-width: 0; }
.ctn-resume b { font-size: var(--t-15); }
.ctn-resume-piece { font-size: var(--t-11); color: var(--texte-doux); text-transform: uppercase; letter-spacing: .06em; }
#panneau .tuile-notification-choisie .bouton { width: auto; flex: none; margin: 0; padding: 6px 12px; font-size: var(--t-12); }
/* Le bleu du bouton « Affichage conditionnel » : un vrai bleu, pas la
   couleur d'accent du thème (verte). */
:root {
  --bleu-condition: #2F6FDB;
  --stabilo: rgba(47, 111, 219, .26);        /* le trait du stabilo */
  --stabilo-doux: rgba(47, 111, 219, .16);   /* sans règle : plus léger */
  --stabilo-fort: rgba(47, 111, 219, .38);   /* au survol */
  --stabilo-halo: rgba(47, 111, 219, .14);   /* les bords diffus */
}
html[data-theme="sombre"] {
  --bleu-condition: #3B7BE8;
  --stabilo: rgba(96, 156, 255, .34); --stabilo-doux: rgba(96, 156, 255, .2);
  --stabilo-fort: rgba(96, 156, 255, .46); --stabilo-halo: rgba(96, 156, 255, .16);
}

/* Le libellé du bouton : long sur un grand écran, « Cond. » sur un
   téléphone où la tuile est étroite -- sinon la condition, l'important,
   était coupée (26/09/2026). */
.condition-pastille .cp-court { display: none; }
@media (max-width: 820px) {
  .condition-pastille .cp-long { display: none; }
  .condition-pastille .cp-court { display: inline; }
  /* Et le bouton peut prendre deux lignes : « Tempo · Cond. : si demain
     est rouge » ne tient pas sur une tuile de 130 px. */
  body.en-edition .tuile .condition-pastille, body.en-edition .carte .condition-pastille {
    white-space: normal; text-overflow: clip; line-height: 1.2; padding: 4px 9px;
  }
  body.en-edition .tuile .condition-pastille.condition-seconde,
  body.en-edition .carte .condition-pastille.condition-seconde { bottom: 46px; }
}
/* Un bouton rond caché (le thème, retiré du haut de page) doit vraiment disparaître : la règle .icone-ronde le mettait en flex malgré hidden. */
.icone-ronde[hidden] { display: none; }

/* ============================================================
   ZONES (GROUPES DE PIÈCES) ET ÉTIQUETTES — 27/09/2026
   Préfixes .zm- (zones) et .etiq- (étiquettes), jamais « .zone » ni
   « .etiquette » : ces noms servent déjà au planning et aux courbes,
   et .etiquettes est masquée dans le plan. Tout passe par les
   variables du thème : le sombre n'a presque rien à redire.
   ============================================================ */

/* Page Pièces : sous la rangée des étages, une seconde rangée, une
   pilule par zone. Elle porte aussi .filtres-types, donc défile, se
   cache si vide et disparaît en mode réglage comme celle du dessus ;
   les deux règles sont redites ici pour ne pas dépendre de la première
   classe. Elle se rapproche de la rangée des étages pour que les deux
   se lisent comme un seul en-tête. */
.zm-filtres { margin-top: -7px; }
.zm-filtres:empty { display: none; }
body.en-edition .zm-filtres { display: none; }
/* Une zone n'est pas un étage : la pilule est pointillée, comme le
   fourre-tout des réglages -- « regroupement », pas « filtre ». */
.zm-pastille { border-style: dashed; border-color: var(--trait-fort, var(--trait)); }
.zm-pastille.actif {
  border-style: solid; background: var(--accent); border-color: var(--accent);
  color: var(--accent-contraste);
}
/* L'icône de la zone (27/09/2026, décision 4 de Fred), devant son nom,
   page Pièces comme Plan : 14 px, posée sur la ligne du texte. Les
   icônes tracent en currentColor : elles prennent la couleur de la
   pilule -- douce au repos, contrastée quand elle est active, retournée
   en thème sombre -- sans règle de plus. Contenant convenu : span
   .zm-icone ; une icône posée nue (svg enfant direct) est tenue pareil. */
.zm-pastille .zm-icone {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 14px; height: 14px; margin-right: 6px; vertical-align: -2px;
}
.zm-pastille .zm-icone svg { width: 14px; height: 14px; display: block; }
.zm-pastille > svg { width: 14px; height: 14px; margin-right: 6px; vertical-align: -2px; flex: none; }
.zm-pastille .zm-icone:empty { display: none; }

/* Page d'une zone : la commande de tous ses volets, en tête. C'est un
   bloc, pas une tuile : il se pose AVANT la grille (frère qui précède
   #page-grille-pieces), en prend la largeur, et n'entre pas dans la
   disposition -- une tuile de plus aurait réclamé une place et un
   réglage de taille pour ce qui n'est qu'une barre de commande.
   Une rangée : le titre ; la suivante : les trois touches, le curseur,
   le bouton. Le curseur et le bouton peuvent être des enfants directs
   ou groupés dans .zm-volets-position, le rendu est le même. */
.zm-volets {
  display: grid; grid-template-columns: auto 1fr auto; gap: 10px 14px; align-items: center;
  width: 100%; max-width: var(--largeur-max); margin: 0 auto 14px; box-sizing: border-box;
  padding: 12px 14px; border-radius: var(--r-md); border: 1px solid var(--trait);
  background: var(--surface); color: var(--texte);
  --cat: var(--cat-volets); --cat-fond: var(--cat-volets-fond);
}
.zm-volets-titre {
  grid-column: 1 / -1; font-size: var(--t-13); font-weight: 650; color: var(--texte-doux);
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.zm-volets-titre b, .zm-volets-titre strong { color: var(--texte); font-weight: 700; }
.zm-volets-titre .chip-icone { width: 26px; height: 26px; border-radius: 8px; }
/* Les trois touches : celles d'une tuile de volet, sans la marge du haut
   qui les décalait du curseur, et d'une largeur fixe pour ne pas
   s'étirer sur un grand écran. */
.zm-volets .touches-volet { margin-top: 0; width: auto; grid-auto-columns: 56px; }
.zm-volets-position { display: flex; align-items: center; gap: 10px; min-width: 0; }
.zm-volets input[type="range"] { flex: 1; min-width: 120px; width: 100%; accent-color: var(--cat-volets); margin: 0; }
.zm-volets-valeur {
  font-variant-numeric: tabular-nums; font-weight: 650; min-width: 3.4em; text-align: right;
  color: var(--texte);
}
.zm-volets button:not(.touche-volet) {
  width: auto; margin: 0; flex: none; padding: 9px 12px; white-space: nowrap;
  border-radius: var(--r-sm); border: 1px solid var(--trait-fort);
  background: var(--surface-douce); color: var(--texte); font: inherit;
  font-size: var(--t-12); font-weight: 650; cursor: pointer;
  transition: background var(--vite), border-color var(--vite), transform var(--vite);
}
.zm-volets button:not(.touche-volet):hover { background: var(--surface-survol); border-color: var(--trait-fort); }
.zm-volets button:not(.touche-volet):active { transform: scale(.97); }
.zm-volets button:not(.touche-volet):disabled { opacity: .45; cursor: default; }
/* Une commande partie, pas encore de réponse : le bloc respire comme
   une touche de tuile (même animation). */
.zm-volets.attente .touches-volet { animation: respiration .9s ease-in-out infinite; }
/* Sur un téléphone, tout passe l'un sous l'autre : les touches sur une
   ligne, pleine largeur, puis le curseur, puis le bouton. */
@media (max-width: 640px) {
  .zm-volets { grid-template-columns: 1fr; gap: 10px; padding: 12px; }
  .zm-volets .touches-volet { width: 100%; grid-auto-columns: 1fr; }
  .zm-volets-position { flex-wrap: wrap; }
  .zm-volets input[type="range"] { flex: 1 1 100%; }
  .zm-volets button:not(.touche-volet) { width: 100%; flex: 1 1 100%; }
}
/* Et si le bloc est mis DANS la grille plutôt qu'avant elle : toute la
   largeur, marge d'une tuile. La grille pose ses tuiles à des rangées
   fixes : c'est alors à qui l'y met de le placer (grid-row) et de
   décaler les tuiles d'autant, sinon la première rangée le recouvre. */
.grille-pastilles > .zm-volets {
  grid-column: 1 / -1; align-self: start; width: auto; max-width: none; margin: var(--marge-case);
}

/* Page Catégories : l'intertitre « Étiquettes » entre les tuiles de
   catégories et celles des étiquettes. Même dessin que les intertitres
   du panneau (.sous-liste-titre), une marge au-dessus pour marquer la
   coupure ; dans la grille, il prend toute la largeur.
   Phase 2 (27/09/2026, décision 5 de Fred) : les étiquettes deviennent
   des tuiles ordinaires de la grille, sans intertitre ni seconde grille
   (.etiq-grille, qui n'avait pas de règle). Ces deux règles ne servent
   plus ; laissées, inoffensives, le temps que moteur.js cesse partout
   de poser l'ancien bloc. */
.etiq-titre-bloc {
  font-size: var(--t-11); font-weight: 700; color: var(--texte-doux);
  text-transform: uppercase; letter-spacing: .07em; line-height: 1.3;
  max-width: var(--largeur-max); margin: 22px auto 10px; padding: 0 var(--marge-case, 6px);
}
.grille-pastilles > .etiq-titre-bloc {
  grid-column: 1 / -1; align-self: end; margin: 0 var(--marge-case); padding: 0;
}

/* Pastilles cochables des étiquettes (fiche d'un appareil dans les
   réglages) : mêmes pilules que le choix de fond (.puce-fond), celle qui
   est posée passe en couleur d'accent. */
.etiq-puces { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 10px; }
.etiq-puces:empty { display: none; }
.etiq-puce {
  font-size: var(--t-12); font-weight: 600; padding: 5px 10px; line-height: 1.2;
  border-radius: var(--r-pilule, 999px); border: 1px solid var(--trait-fort);
  background: var(--surface-douce); color: var(--texte); font-family: inherit; cursor: pointer;
  transition: background var(--vite), color var(--vite), border-color var(--vite);
}
.etiq-puce:hover { background: var(--surface-creuse); }
.etiq-puce.actif { background: var(--accent); border-color: var(--accent); color: var(--accent-contraste); }
.etiq-puce:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.etiq-puce:disabled { opacity: .45; cursor: default; }

/* Dans les réglages, les appareils qui portent une étiquette : une
   pastille par appareil (n'importe quel enfant direct), avec sa croix
   .etiq-retirer pour l'en ôter. */
.etiq-liste-appareils { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 10px; }
.etiq-liste-appareils:empty { display: none; }
.etiq-liste-appareils > * {
  display: inline-flex; align-items: center; gap: 6px; max-width: 100%; box-sizing: border-box;
  font-size: var(--t-12); font-weight: 600; line-height: 1.2; padding: 4px 6px 4px 10px;
  border-radius: var(--r-pilule, 999px); border: 1px solid var(--trait);
  background: var(--surface-douce); color: var(--texte);
}
.etiq-retirer {
  width: 20px; height: 20px; border-radius: 50%; border: none; padding: 0; flex: none;
  display: inline-grid; place-items: center; font-size: 13px; line-height: 1; font-family: inherit;
  background: var(--surface-creuse); color: var(--texte-doux); cursor: pointer;
  transition: background var(--vite), color var(--vite);
}
.etiq-retirer:hover { background: var(--danger-doux); color: var(--danger); }
.etiq-retirer:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* La ligne « Ajouter un appareil… » : le menu prend la place, le bouton
   reste à sa taille. */
.etiq-ajout { display: flex; gap: 8px; align-items: center; margin: 4px 0 10px; }
.etiq-ajout select { flex: 1; min-width: 0; }
.etiq-ajout .bouton { width: auto; margin: 0; flex: none; padding: 8px 12px; font-size: var(--t-12); white-space: nowrap; }

/* Thème sombre : les couleurs viennent des variables, déjà retournées ;
   seul le relief change -- un bloc posé sur le fond sombre se détache
   mieux sur la surface douce que sur la surface de base, et les
   pastilles d'appareil se creusent au lieu de se soulever. */
html[data-theme="sombre"] .zm-volets { background: var(--surface-douce); }
html[data-theme="sombre"] .zm-volets button:not(.touche-volet) { background: var(--surface-creuse); }
html[data-theme="sombre"] .zm-volets button:not(.touche-volet):hover { background: var(--surface-survol); }
html[data-theme="sombre"] .etiq-liste-appareils > * { background: var(--surface-creuse); }
html[data-theme="sombre"] .etiq-puce:not(.actif) { background: var(--surface-creuse); }
html[data-theme="sombre"] .zm-pastille:not(.actif) { border-color: var(--trait-fort); }

/* Réglages → Zones : les pièces de la zone, en cases à cocher sur
   plusieurs colonnes (27/09/2026). Une ligne sans fiche (zones vues par
   un compte non administrateur) ne se déplie pas. */
.zm-choix-pieces { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 6px 0 10px; }
.zm-choix-piece { display: inline-flex; align-items: center; gap: 6px; font-size: var(--t-13); color: var(--texte); cursor: pointer; }
.zm-choix-piece input { margin: 0; accent-color: var(--accent); }
.ligne-icone-piece.sans-gestion { cursor: default; }

/* « Aller à cette position » sans avoir touché le curseur : le curseur
   clignote pour inviter à choisir (27/09/2026). */
.zm-volets.zm-a-choisir input[type="range"] { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }

/* ----- Place laissée à la barre du haut (27/09/2026) -----
   Les onglets d'étage du Plan s'arrêtent avant les pastilles d'alerte et
   les boutons ⚙︎ ≡ (largeur mesurée par reserverPlaceHaut) ; sur un écran
   trop étroit, l'en-tête passe juste sous la barre. */
.plan-entete { padding-right: var(--reserve-haut-droite, 110px); }
html.haut-etroit .plan-entete { padding-right: 0; margin-top: max(0px, calc(var(--bas-haut, 56px) - var(--haut-sur, 0px) - 8px)); }
/* Toutes les pièces et les zones, sous les étages du Plan. */
.plan-zones { display: flex; flex-wrap: wrap; gap: 7px; margin: 2px 0 0 58px; flex: none; }
.plan-zones:empty { display: none; }
.plan-zones .compte-type { margin-left: 6px; opacity: .7; font-size: .85em; }
@media (max-width: 820px) { .plan-zones { margin-left: 0; } }

/* Phase 2 (27/09/2026) : une plage d'heures cachée l'est vraiment (le
   display:flex de la ligne l'emportait sur l'attribut hidden), et les
   étiquettes de la liste de création des notifications prennent la
   teinte indigo de leurs tuiles. */
.ligne-condition .condition-plage[hidden] { display: none; }
.ctn-etiquettes { color: var(--cat-indigo); }
#panneau .ctn-tuile.ctn-etiquette { border-left: 3px solid var(--cat-indigo); padding-left: 8px; }

/* Corrections de la relecture (28/09/2026) : ligne de condition
   incomplète (rien ne s'écrit tant qu'elle l'est), message sous les
   lignes, condition proposée pas encore active, notification d'une
   étiquette supprimée. */
.ligne-condition.ligne-incomplete { border-color: var(--danger); background: var(--danger-doux); }
.message-conditions { margin: 0 0 8px; font-size: var(--t-12); color: var(--danger); }
.ligne-condition.condition-proposee { border-style: dashed; opacity: .85; }
.ligne-condition .activer-condition { flex-basis: 100%; }
.ligne-notification.notification-supprimee .ligne-notification-texte { color: var(--texte-doux); }

/* ----- Recherche (28/09/2026, demande de Fred) -----
   La loupe (dans .icones-haut) déplie une ligne à elle, sous la barre du
   haut (--bas-haut, mesuré par reserverPlaceHaut) ; tant qu'elle est
   ouverte, toutes les pages commencent dessous (--place-recherche,
   mesuré par majPlaceRecherche) : rien ne passe sous le champ. */
.barre-recherche {
  position: fixed; z-index: 19; left: 0; right: 0;
  top: calc(var(--bas-haut, 54px) + 8px);
  display: flex; align-items: center; gap: 8px;
  max-width: var(--largeur-max); margin: 0 auto; padding: 0 26px;
  box-sizing: border-box;
}
.barre-recherche[hidden] { display: none; }
.barre-recherche { flex-wrap: wrap; row-gap: 8px; }
/* Les étiquettes proposées sous le champ (28/09/2026). */
.suggestions-recherche {
  flex-basis: 100%; display: flex; gap: 7px; align-items: center;
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; padding-bottom: 2px;
}
.suggestions-recherche::-webkit-scrollbar { display: none; }
.suggestions-recherche[hidden] { display: none; }
.suggestions-recherche .suggestions-titre { flex: none; font-size: var(--t-12); color: var(--texte-doux); margin-right: 2px; }
.saisie-recherche {
  flex: 1; min-width: 0; height: 44px; box-sizing: border-box;
  display: flex; align-items: center; gap: 8px; padding: 0 12px;
  border-radius: var(--r-sm); background: var(--surface);
  border: 1px solid var(--trait); box-shadow: var(--ombre-1);
  color: var(--texte-doux); cursor: text;
}
.saisie-recherche svg { flex: none; }
.saisie-recherche:focus-within { border-color: var(--accent); }
.saisie-recherche input {
  flex: 1; min-width: 0; height: 100%; margin: 0; padding: 0; border: 0;
  background: transparent; color: var(--texte); outline: none;
  font-family: inherit; font-size: 16px;   /* 16 px : iOS ne zoome pas */
  -webkit-appearance: none; appearance: none;
}
.saisie-recherche input::-webkit-search-cancel-button,
.saisie-recherche input::-webkit-search-decoration { -webkit-appearance: none; display: none; }
.aide-recherche { flex: none; font-size: var(--t-12); color: var(--texte-doux); white-space: nowrap; }
.aide-recherche:empty { display: none; }
.fermer-recherche {
  flex: none; width: 44px; height: 44px; border-radius: var(--r-sm);
  background: var(--surface); border: 1px solid var(--trait); box-shadow: var(--ombre-1);
  color: var(--texte); display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.fermer-recherche:hover { background: var(--surface-survol); border-color: var(--trait-fort); }
@media (max-width: 820px) { .barre-recherche { padding: 0 16px; } }
body.recherche-ouverte :is(.accueil, .page-liste, .page-meteo, .page-plan, .page-securite,
  .page-soleil, .page-ventilation, .page-graphiques) { top: var(--place-recherche, 56px); }
/* Sous la ligne de recherche, plus rien n'est à hauteur des boutons du
   haut : les titres reprennent toute la largeur. */
body.recherche-ouverte .page-titre { padding-right: 0; }
body.recherche-ouverte .plan-entete { padding-right: 0; }
html.haut-etroit body.recherche-ouverte .plan-entete { margin-top: 0; }

/* Les titres de page ne passent jamais sous les boutons du haut : on
   leur réserve la largeur réellement occupée (pastilles d'alerte et
   boutons, mesurée par reserverPlaceHaut) au lieu d'un forfait ; un titre
   trop long passe à la ligne. Le Plan a sa propre réserve (.plan-entete). */
.page-titre { padding-right: var(--reserve-haut-droite, 104px); flex-wrap: wrap; row-gap: 6px; }
.plan-entete .page-titre { padding-right: 104px; }
/* Pas la place à côté des boutons (classe posée par reserverPlaceHaut) :
   le titre descend sous la barre et reprend toute la largeur. Jamais un
   mot coupé lettre par lettre (vu sur la page Énergie, 28/09/2026). */
html.titre-sous-barre .page-titre:not(.plan-entete .page-titre) {
  padding-right: 0;
  margin-top: max(0px, calc(var(--bas-haut, 50px) - var(--haut-sur, 0px) - 6px));
}
/* Même sélecteur que ci-dessus, plus précis : sinon il l'emporte et le
   titre garde sa marge sous la ligne de recherche. */
html.titre-sous-barre body.recherche-ouverte .page-titre:not(.plan-entete .page-titre) { margin-top: 0; }

/* Les résultats */
.recherche-raccourcis { max-width: var(--largeur-max); margin: 0 auto 12px; }
.recherche-raccourcis .recherche-sorte { opacity: .65; font-weight: 500; margin-right: 6px; }
.recherche-resultats { max-width: var(--largeur-max); margin: 0 auto; }
.recherche-groupe {
  display: flex; align-items: flex-end; gap: 8px; align-self: end;
  padding: 0 var(--marge-case, 6px) 4px; min-width: 0;
  font-size: var(--t-17); font-weight: 700; color: var(--texte);
}
.recherche-groupe > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.recherche-groupe-icone { display: inline-flex; color: var(--texte-doux); flex: none; }
.recherche-groupe-icone svg { width: 20px; height: 20px; }
.recherche-groupe-niveau { font-size: var(--t-12); font-weight: 500; color: var(--texte-doux); }
.recherche-vide { color: var(--texte-doux); font-size: var(--t-15); margin: 8px 0; }

/* ----- Appareils à plusieurs mesures (28/09/2026) -----
   Sur la tuile, la mesure principale et le compte ; dans la fiche et le
   formulaire, la liste des mesures ; dans la découverte, les blocs d'un
   même appareil repliés sous sa ligne. */
.tuile-sous-groupe { font-size: var(--t-12); color: var(--texte-doux); }
.liste-groupe { display: flex; flex-direction: column; gap: 4px; margin-top: 12px; }
.ligne-groupe {
  display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: var(--r-sm);
  background: var(--surface-douce); font-size: var(--t-13); color: var(--texte);
}
.ligne-groupe.principale { background: var(--accent-doux); }
.ligne-groupe-nom { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.ligne-groupe-valeur { font-weight: 650; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ligne-groupe-marque { color: var(--accent); }
.ligne-groupe .bouton.compact { margin: 0; }
.formulaire-membres { max-height: 240px; overflow-y: auto; margin-bottom: 8px; }
.formulaire-membres .ligne-groupe { cursor: pointer; }
.formulaire-membres input[type="radio"] { margin: 0; accent-color: var(--accent); }
.decouverte-membres { margin: 2px 0 8px 22px; padding-left: 8px; border-left: 2px solid var(--trait); }
.decouverte-membres[hidden] { display: none; }

/* ----- Ajouter un appareil, catalogue Home Assistant (28/09/2026) ----- */
.catalogue-pilules { display: flex; flex-wrap: wrap; gap: 6px; }
.catalogue-etapes { margin: 6px 0 0; padding-left: 18px; font-size: var(--t-13); color: var(--texte); }
.catalogue-etapes li { margin-bottom: 6px; }
.demande-texte {
  width: 100%; box-sizing: border-box; height: 220px; margin: 8px 0; padding: 8px; resize: vertical;
  border-radius: var(--r-sm); border: 1px solid var(--trait); background: var(--surface-douce); color: var(--texte);
  font: 12px/1.45 ui-monospace, "SF Mono", Menlo, monospace;
}
.decouverte-item .decouverte-detail a { color: var(--accent); }

/* ----- Siri et widgets (28/09/2026) ----- */
.siri-apercu { font-size: var(--t-13); color: var(--texte); line-height: 1.45; }
.siri-apercu:empty { display: none; }
.siri-apercu-titre { font-weight: 600; color: var(--texte-doux); margin-right: 4px; }
.siri-cle { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--trait); }
.siri-cle:last-child { border-bottom: none; }
.siri-cle-texte { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.siri-cle-nom { font-size: var(--t-13); font-weight: 600; color: var(--texte); overflow-wrap: anywhere; }
.siri-cle-detail { font-size: 12px; color: var(--texte-doux); }
.siri-nouvelle { margin-top: 12px; padding: 12px; border: 1px solid var(--trait); border-radius: var(--r-md, 12px); background: var(--surface-douce); }
.siri-avertissement { color: var(--alerte); margin-bottom: 8px; }
.siri-copie { display: flex; gap: 6px; align-items: center; margin: 6px 0 2px; min-width: 0; }
.siri-copie input {
  flex: 1; min-width: 0; padding: 6px 8px; border-radius: var(--r-sm); border: 1px solid var(--trait);
  background: var(--surface); color: var(--texte); font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace;
}
.siri-nouvelle code { font-size: 12px; white-space: nowrap; }
.siri-nouvelle .demande-texte[hidden] { display: none; }
