:root {
    --bg:        #09090f;
    --bg2:       #0f101a;
    --bg3:       #161726;
    --border:    rgba(255,190,50,0.13);
    --amber:     #ffbe32;
    --amber2:    #ff9500;
    --amber3:    #ffe08a;
    --green:     #3ddc84;
    --blue:      #4fc3f7;
    --red:       #ff6b6b;
    --text:      #e8e9f3;
    --text2:     #9091a8;
    --glow:      0 0 24px rgba(255,190,50,0.25);
    --card-r:    14px;
  }
  * { box-sizing: border-box; margin: 0; padding: 0; }
  body {
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-body, 'DM Sans'), sans-serif;
    min-height: 100vh;
    overflow-x: hidden;
  }

  /* ── HOURLY TABLE ── */
  .hourly-bar {
    display: inline-block; height: 8px; border-radius: 99px;
    vertical-align: middle; min-width: 2px;
    transition: width .4s ease;
  }
  .hourly-now  { background: linear-gradient(90deg, var(--amber2), var(--amber)); }
  .hourly-yday { background: rgba(255,255,255,.18); }
  .delta-pos { color: var(--green); }
  .delta-neg { color: var(--red); }
  .delta-eq  { color: var(--text2); }

  /* ── THEME PANEL ── */
  .theme-tabs {
    display: flex; gap: 4px; margin-bottom: 20px;
    background: var(--bg); border: 1px solid var(--border);
    border-radius: 10px; padding: 4px; width: fit-content;
    /* Sur petit écran : permettre le scroll horizontal sans déborder du viewport.
       max-width: 100% empêche le débordement, overflow-x: auto active le scroll
       au doigt, et flex-shrink: 0 sur les onglets garde leur taille naturelle. */
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
  }
  .theme-tabs::-webkit-scrollbar { height: 4px; }
  .theme-tabs::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
  .theme-tab {
    background: none; border: none; cursor: pointer;
    color: var(--text2); font-family: var(--font-body,'DM Sans'), sans-serif;
    font-size: .82rem; padding: 7px 16px;
    border-radius: 7px; transition: all .2s;
    flex-shrink: 0;        /* pas de compression : chaque onglet garde sa taille */
    white-space: nowrap;   /* « Forme & Layout » ne se coupe pas en deux lignes */
  }
  .theme-tab.active { background: var(--amber); color: #000; font-weight: 700; }
  .theme-tab:not(.active):hover { color: var(--text); background: var(--bg3); }

  .theme-section { display: none; }
  .theme-section.active { display: block; }

  /* ════════════════════════════════════════════════════════════════
     SIMULATEUR D'APPAREIL — éditeur layout multi-format
  ════════════════════════════════════════════════════════════════ */
  .device-sim-toolbar {
    display: flex; gap: 10px; flex-wrap: wrap; align-items: center;
    background: var(--bg2); border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px 14px;
    margin-bottom: 16px;
  }
  .device-sim-toolbar select,
  .device-sim-toolbar input[type="number"] {
    background: var(--bg); color: var(--text);
    border: 1px solid var(--border); border-radius: 7px;
    padding: 7px 10px; font-size: .82rem;
    font-family: var(--font-body, 'DM Sans'), sans-serif;
  }
  .device-sim-toolbar input[type="number"] { width: 80px; }
  .device-sim-toolbar label {
    font-size: .75rem; color: var(--text2);
    display: inline-flex; align-items: center; gap: 6px;
  }
  .device-sim-toolbar button {
    background: var(--bg); color: var(--text);
    border: 1px solid var(--border); border-radius: 7px;
    padding: 7px 12px; cursor: pointer;
    font-size: .82rem;
    font-family: var(--font-body, 'DM Sans'), sans-serif;
    transition: all .15s;
  }
  .device-sim-toolbar button:hover { border-color: var(--amber); color: var(--amber); }
  .device-sim-toolbar button.primary {
    background: var(--amber); color: #000; font-weight: 700;
    border-color: var(--amber);
  }
  .device-sim-toolbar button.primary:hover { filter: brightness(1.1); color: #000; }
  .device-sim-toolbar .sim-info {
    font-size: .72rem; color: var(--text2);
    margin-left: auto;
    font-family: 'Orbitron', monospace;
  }

  /* Cadre extérieur (look "device frame") */
  .device-sim-stage {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 24px;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    display: flex;
    justify-content: center;
    /* min-height retiré : la stage prend la hauteur du device-frame
       (calée par JS via updateSimFrame) + padding. Garder un min-height
       trop grand empêche d'accéder aux boutons de sauvegarde sur petit écran. */
  }
  .device-frame {
    background: #050507;
    border: 8px solid #1a1a22;
    border-radius: 28px;
    box-shadow: 0 18px 50px rgba(0,0,0,.6), 0 0 0 1px rgba(255,255,255,.04);
    overflow: hidden;
    position: relative;
    flex-shrink: 0;
    transition: width .3s ease, height .3s ease;
  }
  .device-frame.tablet { border-radius: 22px; border-width: 12px; }
  .device-frame.desktop {
    border-radius: 14px; border-width: 4px 4px 28px 4px;
    background: var(--bg);
  }
  /* "Pied" du cadre desktop */
  .device-frame.desktop::after {
    content: '';
    position: absolute;
    bottom: -22px; left: 50%;
    transform: translateX(-50%);
    width: 32%; height: 14px;
    background: #1a1a22;
    border-radius: 0 0 8px 8px;
  }
  /* Notch téléphone */
  .device-frame.phone::before {
    content: '';
    position: absolute;
    top: 8px; left: 50%;
    transform: translateX(-50%);
    width: 90px; height: 18px;
    background: #050507;
    border-radius: 99px;
    z-index: 10;
    pointer-events: none;
  }
  /* Le viewport interne — reproduit les breakpoints du dashboard
     selon la classe appliquée par le JS (sim-mode-narrow / -tablet / -wide). */
  .device-viewport {
    width: 100%; height: 100%;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    background: var(--bg);
  }
  /* ── Mode TABLETTE : 12 colonnes (granularité fine, anciens layouts migrés ×2) ── */
  .device-viewport.sim-mode-tablet .dash-grid {
    grid-template-columns: repeat(12, 1fr) !important;
    grid-auto-rows: 55px !important;
  }
  .device-viewport.sim-mode-tablet .dash-grid > .dash-tile { height: 100% !important; overflow: hidden !important; }
  .device-viewport.sim-mode-tablet .dash-grid > .dash-tile.chart-card canvas { max-height: none !important; }

  /* ── Mode TÉLÉPHONE / NARROW : 4 colonnes (anciens layouts migrés ×2) ── */
  .device-viewport.sim-mode-narrow .dash-grid {
    grid-template-columns: repeat(4, 1fr) !important;
    grid-auto-rows: 55px !important;
  }
  .device-viewport.sim-mode-narrow .dash-grid > .dash-tile { height: 100% !important; overflow: hidden !important; }
  .device-viewport.sim-mode-narrow .dash-grid > .dash-tile.chart-card canvas { max-height: none !important; }
  /* Forcer mode édition et poignées dans la preview */
  .device-viewport .dash-grid > .dash-tile {
    cursor: grab;
    outline: 2px dashed var(--amber);
    outline-offset: -3px;
    user-select: none;
    -webkit-user-select: none;
    position: relative;
    /* Empêcher le scroll tactile pendant le drag (sinon le doigt scrolle la page
       au lieu de déplacer la tuile). */
    touch-action: none;
  }
  /* Feedback drag dans le simulateur (le sélecteur body.dash-edit ne s'applique
     pas dans la preview qui est toujours en mode édition forcée). */
  .device-viewport .dash-grid > .dash-tile.dragging {
    opacity: .4;
    cursor: grabbing;
  }
  .device-viewport .dash-grid > .dash-tile::before {
    content: '⋮⋮';
    position: absolute;
    top: 6px; right: 10px;
    color: var(--amber);
    font-size: 1.1rem; font-weight: 900;
    letter-spacing: -2px;
    pointer-events: none; z-index: 5; opacity: .7;
  }
  .device-viewport .dash-resize-handle {
    display: block;
    position: absolute;
    bottom: 0; right: 0;
    width: 26px; height: 26px;
    cursor: nwse-resize; z-index: 6;
    border-bottom-right-radius: var(--card-r, 14px);
    background: linear-gradient(135deg, transparent 0%, transparent 50%,
                                 var(--amber) 50%, var(--amber) 60%,
                                 transparent 60%, transparent 70%,
                                 var(--amber) 70%, var(--amber) 80%,
                                 transparent 80%);
    touch-action: none;
  }
  .device-viewport .dash-grid main,
  .device-viewport main { padding: 14px; max-width: none; }

  /* ── CONFIG SUB-TABS (mêmes styles que theme-tabs) ── */
  .config-subtabs {
    display: flex; gap: 4px; margin-bottom: 20px;
    background: var(--bg); border: 1px solid var(--border);
    border-radius: 10px; padding: 4px;
    width: fit-content; max-width: 100%;
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    flex-wrap: nowrap;
  }
  .config-subtab {
    background: none; border: none; cursor: pointer;
    color: var(--text2); font-family: var(--font-body,'DM Sans'), sans-serif;
    font-size: .82rem; padding: 7px 16px;
    border-radius: 7px; transition: all .2s;
    white-space: nowrap; flex-shrink: 0;
  }
  .config-subtab.active { background: var(--amber); color: #000; font-weight: 700; }
  .config-subtab:not(.active):hover { color: var(--text); background: var(--bg3); }
  .config-subsection { display: none; }
  .config-subsection.active { display: block; }

  /* Preset cards */
  .preset-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(140px,1fr)); gap: 10px;
    margin-bottom: 20px;
  }
  .preset-card {
    border-radius: 12px; padding: 14px; cursor: pointer;
    border: 2px solid transparent; position: relative;
    transition: transform .15s, border-color .2s;
    overflow: hidden;
  }
  .preset-card:hover { transform: translateY(-2px); }
  .preset-card.selected { border-color: var(--amber); }
  .preset-card .preset-name {
    font-size: .78rem; font-weight: 700; letter-spacing: .5px; margin-bottom: 6px;
  }
  .preset-swatches {
    display: flex; gap: 4px;
  }
  .preset-swatch { width: 14px; height: 14px; border-radius: 50%; }
  .preset-check {
    position: absolute; top: 8px; right: 8px;
    width: 18px; height: 18px; border-radius: 50%;
    background: var(--amber); color: #000;
    font-size: .65rem; display: none;
    align-items: center; justify-content: center; font-weight: 900;
  }
  .preset-card.selected .preset-check { display: flex; }

  /* Color pickers row */
  .color-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(180px,1fr)); gap: 12px;
    margin-bottom: 20px;
  }
  .color-field { display: flex; flex-direction: column; gap: 6px; }
  .color-field label { font-size: .75rem; color: var(--text2); text-transform: uppercase; letter-spacing: 1px; }
  .color-row { display: flex; gap: 8px; align-items: center; }
  .color-row input[type=color] {
    width: 38px; height: 38px; border: 1px solid var(--border);
    border-radius: 8px; background: none; cursor: pointer; padding: 2px;
  }
  .color-row .color-hex {
    background: var(--bg3); border: 1px solid var(--border);
    color: var(--text); font-family: monospace; font-size: .82rem;
    padding: 8px 10px; border-radius: 8px; width: 90px;
  }

  /* Font selector */
  .font-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(200px,1fr)); gap: 10px;
    margin-bottom: 20px;
  }
  .font-card {
    background: var(--bg3); border: 2px solid var(--border);
    border-radius: 10px; padding: 14px 16px; cursor: pointer;
    transition: all .15s;
  }
  .font-card:hover { border-color: rgba(255,190,50,.4); }
  .font-card.selected { border-color: var(--amber); background: rgba(255,190,50,.07); }
  .font-card .font-preview {
    font-size: 1.2rem; margin-bottom: 4px; color: var(--text);
  }
  .font-card .font-label {
    font-size: .72rem; color: var(--text2); text-transform: uppercase; letter-spacing: 1px;
  }

  /* Sliders */
  .slider-field { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
  .slider-field label { font-size: .75rem; color: var(--text2); text-transform: uppercase; letter-spacing: 1px; display: flex; justify-content: space-between; }
  .slider-field input[type=range] {
    width: 100%; accent-color: var(--amber);
    height: 4px; border-radius: 99px;
  }

  /* Theme action buttons */
  .theme-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 20px; }
  .btn-secondary {
    background: var(--bg3); color: var(--text); border: 1px solid var(--border);
    cursor: pointer; font-family: var(--font-body,'DM Sans'), sans-serif;
    font-weight: 500; font-size: .85rem;
    padding: 9px 20px; border-radius: 9px; transition: all .2s;
  }
  .btn-secondary:hover { border-color: var(--amber); color: var(--amber); }

  /* ── NOISE OVERLAY ── */
  body::before {
    content: '';
    position: fixed; inset: 0;
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.03'/%3E%3C/svg%3E");
    pointer-events: none; z-index: 0; opacity: .5;
  }

  /* ── TOP BAR ── */
  header {
    position: sticky; top: 0; z-index: 100;
    background: rgba(9,9,15,.92);
    -webkit-backdrop-filter: blur(18px);
    backdrop-filter: blur(18px);
    border-bottom: 1px solid var(--border);
    padding: 0 28px;
    display: flex; align-items: center; gap: 24px;
    height: 62px;
    transition: transform .35s ease, opacity .35s ease;
  }
  /* Mode header caché après inactivité */
  body.header-hidden > header {
    transform: translateY(-100%);
    opacity: 0;
    pointer-events: none;
  }
  /* Sur PC : cacher aussi le curseur de la souris pendant l'inactivité.
     Ne s'applique pas sur tactile (pas de curseur visible de toute façon). */
  body.is-desktop.header-hidden,
  body.is-desktop.header-hidden * { cursor: none !important; }

  /* ── MODE IMMERSIF PC : cache header, souris, bottom-nav, dash-edit,
     preset-quick-btn et toute UI flottante en plus du curseur. Le but
     est d'avoir l'écran maximum disponible pour le dashboard. */
  body.is-desktop.header-hidden > .bottom-nav,
  body.is-desktop.header-hidden > .preset-quick-btn,
  body.is-desktop.header-hidden > .dash-edit-bar,
  body.is-desktop.header-hidden > .header-recall-zone {
    opacity: 0 !important;
    pointer-events: none !important;
    transition: opacity .35s ease;
  }
  /* Réafficher dès que le header revient (mouvement souris) */
  body.is-desktop:not(.header-hidden) > .bottom-nav,
  body.is-desktop:not(.header-hidden) > .preset-quick-btn,
  body.is-desktop:not(.header-hidden) > .dash-edit-bar,
  body.is-desktop:not(.header-hidden) > .header-recall-zone {
    transition: opacity .35s ease;
  }
  /* Zone de rappel : survol du haut de l'écran réaffiche le header */
  .header-recall-zone {
    position: fixed;
    top: 0; left: 0; right: 0;
    height: 10px;
    z-index: 99;
    pointer-events: auto;
  }
  .logo {
    font-family: 'Orbitron', monospace;
    font-weight: 900; font-size: 1.1rem;
    color: var(--amber);
    letter-spacing: 2px;
    display: flex; align-items: center; gap: 10px;
  }
  .logo-sun {
    width: 30px; height: 30px;
    background: radial-gradient(circle, #ffbe32 35%, #ff9500 70%, transparent 100%);
    border-radius: 50%;
    box-shadow: 0 0 16px #ffbe3288, 0 0 40px #ff950044;
    animation: pulse-sun 3s ease-in-out infinite;
  }
  @keyframes pulse-sun {
    0%,100% { box-shadow: 0 0 16px #ffbe3288, 0 0 40px #ff950044; }
    50%      { box-shadow: 0 0 28px #ffbe32cc, 0 0 60px #ff950066; }
  }
  nav { display: flex; gap: 4px; margin-left: auto; }
  .nav-btn {
    background: none; border: none; cursor: pointer;
    color: var(--text2); font-family: 'DM Sans', sans-serif;
    font-size: .88rem; font-weight: 500;
    padding: 8px 18px; border-radius: 8px;
    transition: all .2s;
  }
  .nav-btn:hover { color: var(--text); background: var(--bg3); }
  .nav-btn.active { color: var(--amber); background: rgba(255,190,50,.1); }
  .live-dot {
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--green);
    box-shadow: 0 0 8px var(--green);
    animation: blink 2s ease-in-out infinite;
    margin-left: 12px;
  }
  @keyframes blink { 0%,100%{opacity:1} 50%{opacity:.3} }
  .last-update {
    font-size: .75rem; color: var(--text2);
    white-space: nowrap;
  }
  .refresh-btn {
    background: none; border: 1px solid var(--border);
    color: var(--text2); cursor: pointer;
    padding: 6px 14px; border-radius: 8px;
    font-size: .8rem; font-family: 'DM Sans', sans-serif;
    transition: all .2s;
  }
  header {
    position: fixed; top: 0; left: 0; right: 0; z-index: 100;
    background: rgba(9,9,15,.92);
    -webkit-backdrop-filter: blur(18px);
    backdrop-filter: blur(18px);
    border-bottom: 1px solid var(--border);
    padding: 0 28px;
    display: flex; align-items: center; gap: 24px;
    height: 62px;
    transition: transform .35s ease, opacity .35s ease;
  }
  /* Mode header caché : glisse vers le haut, main remonte avec lui */
  body.header-hidden > header {
    transform: translateY(-100%);
    opacity: 0;
    pointer-events: none;
  }

  /* ── MAIN ── */
  main {
    padding: 20px 28px;
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
    /* Le header est fixed : on compense sa hauteur par un margin-top */
    margin-top: 62px;
    height: calc(100vh - 62px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    transition: margin-top .35s ease, height .35s ease;
  }
  /* Quand le header est caché, main remonte et reprend toute la hauteur */
  body.header-hidden > main {
    margin-top: 0;
    height: 100vh;
  }

  /* ── PAGES ── */
  .page { display: none; }
  .page.active {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  /* Pages avec contenu variable : on les sort du flex layout et on les met en block
     normal avec scroll interne. Ça permet au contenu (tableaux, graphiques, sections)
     de couler naturellement de haut en bas sans qu'aucun élément ne soit écrasé par
     le flex-shrink, et au scroll de s'activer correctement quand le contenu déborde.
     IMPORTANT : on doit garder `flex: 1` pour que la page remplisse main, et passer
     en display: block pour que le contenu interne ne soit pas un flex column. */
  /* IMPORTANT : on doit garder `flex: 1` pour que la page remplisse main, et passer
     en display: block pour que le contenu interne ne soit pas un flex column.
     #page-dashboard EST inclus pour que les tuiles débordantes scrollent au lieu
     d'être tronquées par l'overflow:hidden de main. Exception : la vue analytique
     prend toujours 100% de hauteur (cf. .analytics-grid). */
  #page-dashboard.active {
    /* Mode dashboard classique : flex pour permettre au dashGrid (en height:100%)
       de remplir verticalement quand peu de tuiles, et de scroller si trop nombreuses. */
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    overflow-x: hidden;
    min-height: 0;
    height: auto;
  }
  #page-dashboard.active > #dash-classic-view {
    /* Le wrapper de la vue classique prend tout l'espace flex */
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
  }
  #page-dashboard.active > #dash-classic-view > .dash-grid {
    /* La grille prend tout l'espace flex restant → ses rows `1fr` se distribuent */
    flex: 1;
    min-height: 0;
  }
  #page-stats.active,
  #page-history.active,
  #page-inverters.active,
  #page-flux.active,
  #page-settings.active {
    flex: 1;
    display: block;
    overflow-y: auto;
    overflow-x: hidden;
    min-height: 0;
    height: auto;
  }
  /* La vue analytique exige une hauteur stricte (1 écran) — surcharge via la
     classe body.preset-analytics toggled par applyDashboardPreset(). */
  body.preset-analytics #page-dashboard.active {
    overflow: hidden;
    height: 100%;
  }

  /* ── PADDING BAS POUR LA BOTTOM-NAV FIXE (mobile/tablette) ──
     Toutes les pages doivent avoir un padding-bottom suffisant pour que
     leurs derniers éléments (dernière tuile, dernière ligne de tableau,
     dernier réglage) ne soient pas masqués par la bottom-nav fixe (58 px
     + safe-area iPhone). Sans ça, la bottom-nav recouvre le contenu, ce
     qui donne l'impression d'une bande noire qui passe par-dessus. */
  @media (max-width: 980px) {
    body.is-mobile #page-stats.active,
    body.is-mobile #page-history.active,
    body.is-mobile #page-inverters.active,
    body.is-mobile #page-flux.active,
    body.is-mobile #page-settings.active,
    body.is-narrow #page-stats.active,
    body.is-narrow #page-history.active,
    body.is-narrow #page-inverters.active,
    body.is-narrow #page-flux.active,
    body.is-narrow #page-settings.active {
      padding-bottom: calc(70px + env(safe-area-inset-bottom));
    }
  }

  /* Dashboard : remplit tout l'espace disponible (uniquement quand actif) */
  #page-dashboard.active { flex: 1; display: flex; flex-direction: column; }

  /* ── SCROLL VERTICAL DU DASHBOARD SUR MOBILE/TABLETTE ──
     Sur PC les tuiles tiennent dans la hauteur disponible et le dashboard
     hérite de l'overflow:hidden (correct, pas de scroll nécessaire).
     Sur petit écran, le contenu dépasse forcément (chart agrandi + KPIs
     empilés) : il faut activer le scroll interne, sinon le bas du
     dashboard est inaccessible (les autres pages ont déjà cette règle :
     #page-stats.active, #page-settings.active, etc., voir plus haut). */
  @media (max-width: 980px) {
    #page-dashboard.active {
      overflow-y: auto;
      overflow-x: hidden;
      -webkit-overflow-scrolling: touch; /* smooth scroll iOS */
      min-height: 0;
    }
    /* Espace en bas du dashboard pour ne pas être masqué par la bottom-nav fixe */
    #page-dashboard.active > .dash-grid:last-child,
    #page-dashboard.active::after { content: ''; display: block; }
    #page-dashboard.active { padding-bottom: calc(70px + env(safe-area-inset-bottom)); }

    /* ── ESPACEMENT ENTRE TUILES SUR MOBILE — CEINTURE+BRETELLES ──
       Le `gap` de la grille a été observé inopérant sur certains
       Chromium anciens (Samsung Internet sur Galaxy S9+ par exemple) ou
       quand des positions absolues `--tile-y` héritées d'un ancien layout
       PC font se superposer les cellules. Pour garantir l'espacement
       vertical quoi qu'il arrive, on combine 3 mesures :
       1. Neutraliser les positions absolues (grid-column/row-start: auto).
          Sur mobile la grille est trop étroite pour respecter les
          coordonnées calculées en 12 colonnes desktop ; on retombe sur
          le flow naturel.
       2. Désactiver row-gap (peut être bugué) et utiliser margin-bottom
          comme fallback fiable, indépendant du grid layout.
       3. Conserver column-gap pour les tuiles côte-à-côte (KPIs
          demi-largeur) qui restent positionnées par le grid. */
    .dash-grid > .dash-tile {
      grid-column-start: auto !important;
      grid-row-start: auto !important;
    }
    .dash-grid { row-gap: 0 !important; }
    .dash-grid > .dash-tile { margin-bottom: 14px !important; }
    /* La dernière tuile : pas de margin (le padding-bottom du dashboard
       prend le relais sinon ça fait double espace). */
    .dash-grid > .dash-tile:last-child { margin-bottom: 0 !important; }
  }

  /* ── SECTION TITLES ── */
  .section-title {
    font-family: 'Orbitron', monospace;
    font-size: .7rem; letter-spacing: 3px;
    color: var(--text2); text-transform: uppercase;
    margin-bottom: 14px; margin-top: 32px;
  }
  .section-title:first-child { margin-top: 0; }

  /* ── GRID LAYOUTS ── */
  .grid-5 { display: grid; grid-template-columns: repeat(5,1fr); gap: 14px; }
  .grid-4 { display: grid; grid-template-columns: repeat(4,1fr); gap: 14px; }
  .grid-3 { display: grid; grid-template-columns: repeat(3,1fr); gap: 14px; }
  .grid-2 { display: grid; grid-template-columns: repeat(2,1fr); gap: 14px; }
  .grid-21 { display: grid; grid-template-columns: 2fr 1fr; gap: 14px; }
  .grid-12 { display: grid; grid-template-columns: 1fr 2fr; gap: 14px; }
  .col-span-2 { grid-column: span 2; }
  .col-span-3 { grid-column: span 3; }

  /* ════════════════════════════════════════════════════════════════
     DASHBOARD GRID — système réorganisable (drag & drop + resize)
     12 colonnes, chaque tuile prend `data-w` colonnes et `data-h` lignes.
  ════════════════════════════════════════════════════════════════ */
  .dash-grid {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    /* Rows fluides : remplissent verticalement l'espace dispo de #page-dashboard.
       Le code de resize (settings.js) NE LIT PAS cette valeur via parseFloat —
       il mesure la hauteur réelle d'une tuile au moment du resize, ce qui
       fonctionne aussi bien avec `1fr` qu'avec une valeur en px.
       Min de 90px pour éviter l'écrasement si trop de rows simultanées. */
    grid-auto-rows: minmax(90px, 1fr);
    gap: 16px;
    /* Par défaut `row` (sans dense) : ordre strict, chaque tuile reste exactement
       à la position que l'utilisateur lui a donnée. C'est le mode WYSIWYG :
       ce que tu vois pendant l'édition est ce qui sera affiché.
       Le mode "compact" (avec dense) est opt-in via le bouton 📐 dans la barre
       d'édition ou la toolbar du simulateur. */
    grid-auto-flow: row;
    align-items: stretch;
    flex: 1;
    min-height: 0;
  }
  .dash-grid.compact-fill { grid-auto-flow: row dense; }
  /* Les tuiles sont des cards flex — le contenu se centre verticalement */
  .dash-grid > .dash-tile.card {
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
  /* Cartes avec titre en haut + contenu centré : ne pas centrer globalement */
  .dash-grid > .dash-tile.chart-card,
  .dash-grid > .dash-tile.hero-card {
    justify-content: flex-start;
  }
  /* Les tuiles s'étirent à 100% de leur cellule grid */
  .dash-grid > .dash-tile { height: 100%; overflow: hidden; }
  /* Largeur par défaut (avant lecture de data-w) : pleine largeur.
     IMPORTANT : on utilise grid-column-end (longhand) et pas grid-column (shorthand),
     sinon les règles [data-w="N"] qui ne posent que grid-column-end ne s'appliquent pas
     correctement à cause de l'interaction shorthand/longhand. */
  .dash-grid > .dash-tile { grid-column-end: span 12; min-width: 0; }

  /* Container queries : chaque tuile est un contexte de taille. */
  .dash-grid > .dash-tile { container-type: size; container-name: tile; }

  /* ── Placement absolu via CSS custom properties posées par JS ──
     Quand l'utilisateur place une tuile à une position précise, le drag
     définit `style="--tile-x: N; --tile-y: M"` sur la tuile. Le CSS lit
     ces variables pour positionner la tuile en colonne N / ligne M.
     Sans ces variables → flow naturel (auto-placement). C'est le mode hybride :
     les tuiles placées explicitement sont fixées, les autres flottent
     dans les espaces libres. */
  .dash-grid > .dash-tile[style*="--tile-x"] {
    grid-column-start: var(--tile-x);
  }
  .dash-grid > .dash-tile[style*="--tile-y"] {
    grid-row-start: var(--tile-y);
  }

  .dash-grid > .dash-tile[data-w="1"]  { grid-column-end: span 1;  }
  .dash-grid > .dash-tile[data-w="2"]  { grid-column-end: span 2;  }
  .dash-grid > .dash-tile[data-w="3"]  { grid-column-end: span 3;  }
  .dash-grid > .dash-tile[data-w="4"]  { grid-column-end: span 4;  }
  .dash-grid > .dash-tile[data-w="5"]  { grid-column-end: span 5;  }
  .dash-grid > .dash-tile[data-w="6"]  { grid-column-end: span 6;  }
  .dash-grid > .dash-tile[data-w="7"]  { grid-column-end: span 7;  }
  .dash-grid > .dash-tile[data-w="8"]  { grid-column-end: span 8;  }
  .dash-grid > .dash-tile[data-w="9"]  { grid-column-end: span 9;  }
  .dash-grid > .dash-tile[data-w="10"] { grid-column-end: span 10; }
  .dash-grid > .dash-tile[data-w="11"] { grid-column-end: span 11; }
  .dash-grid > .dash-tile[data-w="12"] { grid-column-end: span 12; }
  /* Hauteur en lignes */
  .dash-grid > .dash-tile[data-h="1"] {
    grid-row-end: span 1;
    padding: 10px 14px;
  }
  /* Compactage du contenu pour rester lisible en demi-hauteur */
  .dash-grid > .dash-tile[data-h="1"] .stat-label { margin-bottom: 2px; font-size: .68rem; }
  .dash-grid > .dash-tile[data-h="1"] .stat-val   { font-size: 1.3rem; line-height: 1; margin: 0; }
  .dash-grid > .dash-tile[data-h="1"] .stat-trend,
  .dash-grid > .dash-tile[data-h="1"] .power-bar-wrap,
  .dash-grid > .dash-tile[data-h="1"] .inv-levels-wrap,
  .dash-grid > .dash-tile[data-h="1"] .envoy-mini-leds,
  .dash-grid > .dash-tile[data-h="1"] .gauge-svg,
  .dash-grid > .dash-tile[data-h="1"] .flux-footer,
  .dash-grid > .dash-tile[data-h="1"] #tuyaAutoconsWrap { display: none !important; }
  /* Le « stat-val » du hero (Puissance instantanée) plus discret en compact */
  .dash-grid > .dash-tile[data-h="1"].hero-card .power-val  { font-size: 1.5rem; }
  .dash-grid > .dash-tile[data-h="1"].hero-card .power-unit { font-size: .8rem; }
  .dash-grid > .dash-tile[data-h="1"].hero-card .power-label { font-size: .68rem; }
  .dash-grid > .dash-tile[data-h="2"] { grid-row-end: span 2; }
  .dash-grid > .dash-tile[data-h="3"] { grid-row-end: span 3; }
  .dash-grid > .dash-tile[data-h="4"] { grid-row-end: span 4; }
  .dash-grid > .dash-tile[data-h="5"] { grid-row-end: span 5; }
  .dash-grid > .dash-tile[data-h="6"] { grid-row-end: span 6; }
  .dash-grid > .dash-tile[data-h="7"] { grid-row-end: span 7; }
  .dash-grid > .dash-tile[data-h="8"] { grid-row-end: span 8; }
  .dash-grid > .dash-tile[data-h="9"]  { grid-row-end: span 9;  }
  .dash-grid > .dash-tile[data-h="10"] { grid-row-end: span 10; }
  .dash-grid > .dash-tile[data-h="11"] { grid-row-end: span 11; }
  .dash-grid > .dash-tile[data-h="12"] { grid-row-end: span 12; }
  .dash-grid > .dash-tile[data-h="13"] { grid-row-end: span 13; }
  .dash-grid > .dash-tile[data-h="14"] { grid-row-end: span 14; }
  .dash-grid > .dash-tile[data-h="15"] { grid-row-end: span 15; }
  .dash-grid > .dash-tile[data-h="16"] { grid-row-end: span 16; }
  /* Le canvas du chart doit pouvoir grandir/rétrécir avec la tuile */
  .dash-grid > .dash-tile.chart-card { display: flex; flex-direction: column; }
  /* ── chart-canvas-wrap : pattern Chart.js officiel pour responsive ──
     Le canvas Chart.js est positionné en absolute à l'intérieur d'un
     wrapper flex:1 + position:relative. Cette technique permet à
     Chart.js (avec responsive:true + maintainAspectRatio:false) de
     détecter exactement la taille disponible et de redessiner sans
     déborder. C'est la même méthode que sur le site officiel Chart.js. */
  .chart-canvas-wrap {
    position: relative;
    flex: 1;
    min-height: 0;
    width: 100%;
    overflow: hidden;
  }
  .dash-grid > .dash-tile.chart-card canvas,
  .chart-canvas-wrap > canvas {
    position: absolute;
    inset: 0;
    width: 100% !important;
    height: 100% !important;
    max-width: 100% !important;
    max-height: 100% !important;
    display: block;
  }

  /* ── Snapping responsive par défaut ──
     Ces règles imposent une grille 6 cols (tablette) ou 2 cols (mobile)
     pour donner un rendu correct AVANT toute personnalisation.
     Dès qu'un layout custom est chargé (body.layout-custom), elles sont
     neutralisées et data-w est respecté à la lettre — sans ça, l'utilisateur
     ne peut pas placer librement ses tuiles sur petit écran. */
  @media (max-width: 980px) {
    .dash-grid { grid-template-columns: repeat(12, 1fr) !important; grid-auto-rows: auto !important; }
    .dash-grid > .dash-tile { height: auto !important; overflow: visible !important; }
    .dash-grid > .dash-tile,
    .dash-grid > .dash-tile[data-w="7"],
    .dash-grid > .dash-tile[data-w="8"],
    .dash-grid > .dash-tile[data-w="9"],
    .dash-grid > .dash-tile[data-w="10"],
    .dash-grid > .dash-tile[data-w="11"],
    .dash-grid > .dash-tile[data-w="12"] { grid-column: span 12 !important; }
    .dash-grid > .dash-tile[data-w="6"]  { grid-column: span 12 !important; }
    .dash-grid > .dash-tile[data-w="5"]  { grid-column: span 6 !important; }
    .dash-grid > .dash-tile[data-w="4"]  { grid-column: span 6 !important; }
    .dash-grid > .dash-tile[data-w="3"]  { grid-column: span 6 !important; }
    .dash-grid > .dash-tile[data-w="2"]  { grid-column: span 4 !important; }
    .dash-grid > .dash-tile[data-h="1"],
    .dash-grid > .dash-tile[data-h="2"],
    .dash-grid > .dash-tile[data-h="3"],
    .dash-grid > .dash-tile[data-h="4"],
    .dash-grid > .dash-tile[data-h="5"],
    .dash-grid > .dash-tile[data-h="6"] { grid-row: span 1 !important; max-height: none !important; overflow: visible !important; padding: 18px !important; }
    /* ── Hauteur minimum par data-h pour les tuiles non-chart ──
       Sans ces planchers, les container queries ne peuvent pas calculer
       correctement la taille du texte (cqh = % de hauteur). Résultat :
       le texte tombe à sa borne minimale (1rem) ET la cellule est trop
       basse pour le contenir → débordement visible.
       Ces min-height donnent à chaque tuile une hauteur prévisible
       proportionnelle à son data-h. */
    .dash-grid > .dash-tile[data-h="1"]:not(.chart-card) { min-height: 78px; }
    .dash-grid > .dash-tile[data-h="2"]:not(.chart-card) { min-height: 145px; }
    .dash-grid > .dash-tile[data-h="3"]:not(.chart-card) { min-height: 180px; }
    .dash-grid > .dash-tile[data-h="4"]:not(.chart-card) { min-height: 220px; }
    .dash-grid > .dash-tile[data-h="5"]:not(.chart-card) { min-height: 260px; }
    .dash-grid > .dash-tile[data-h="6"]:not(.chart-card) { min-height: 300px; }
    /* Padding interne plus serré sur les tuiles KPI mobiles pour libérer
       de la place pour les 3 zones (label / val / trend). */
    .dash-grid > .dash-tile[data-h="1"]:not(.chart-card):not(.hero-card),
    .dash-grid > .dash-tile[data-h="2"]:not(.chart-card):not(.hero-card) {
      padding: 12px 14px !important;
    }
    /* ── Protection débordement texte sur mobile ──
       Si malgré tout une valeur est trop longue (ex. "1 234,56 kWh" en
       demi-largeur de 170px), on tronque le LABEL avec une ellipse,
       mais PAS la valeur (qui doit toujours être lisible — la container
       query la dimensionne pour qu'elle tienne). */
    .dash-grid > .dash-tile .stat-label {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      max-width: 100%;
    }
    /* La valeur peut wrapper si nécessaire, mais ne doit JAMAIS être tronquée */
    .dash-grid > .dash-tile .stat-val {
      overflow: visible;
      white-space: nowrap;
      max-width: 100%;
    }
    /* ── Exception pour la tuile « Courbe de production » ──
       Sans cette règle, le snapping ci-dessus aplatit le chart à grid-row: span 1
       et le canvas se retrouve plafonné par .chart-card canvas { max-height: 280px }
       en bas de feuille — ce qui rend la courbe quasi invisible sur téléphone.
       On laisse ici la tuile dimensionner son canvas selon son data-h,
       avec un plancher confortable. */
    .dash-grid > .dash-tile.chart-card { grid-row: auto !important; }
    .dash-grid > .dash-tile.chart-card[data-h="2"] { min-height: 280px; }
    .dash-grid > .dash-tile.chart-card[data-h="3"] { min-height: 360px; }
    .dash-grid > .dash-tile.chart-card[data-h="4"] { min-height: 440px; }
    .dash-grid > .dash-tile.chart-card[data-h="5"] { min-height: 520px; }
    .dash-grid > .dash-tile.chart-card[data-h="6"] { min-height: 600px; }
    /* Canvas Chart.js sur mobile : la nouvelle structure avec
       chart-canvas-wrap (position:relative, flex:1) + canvas (absolute)
       garantit le bon dimensionnement. On garde juste un min-height
       de fallback pour les très petites tuiles. */
    .dash-grid > .dash-tile.chart-card .chart-canvas-wrap {
      min-height: 200px;
    }
    .dash-grid > .dash-tile .stat-trend,
    .dash-grid > .dash-tile .power-bar-wrap,
    .dash-grid > .dash-tile .inv-levels-wrap,
    .dash-grid > .dash-tile .envoy-mini-leds,
    .dash-grid > .dash-tile .gauge-svg,
    .dash-grid > .dash-tile .flux-footer,
    .dash-grid > .dash-tile #tuyaAutoconsWrap { display: revert !important; }
  }
  @media (max-width: 600px) {
    .dash-grid { grid-template-columns: repeat(4, 1fr) !important; }
    .dash-grid > .dash-tile,
    .dash-grid > .dash-tile[data-w="5"],
    .dash-grid > .dash-tile[data-w="6"],
    .dash-grid > .dash-tile[data-w="7"],
    .dash-grid > .dash-tile[data-w="8"],
    .dash-grid > .dash-tile[data-w="9"],
    .dash-grid > .dash-tile[data-w="10"],
    .dash-grid > .dash-tile[data-w="11"],
    .dash-grid > .dash-tile[data-w="12"] { grid-column: span 4 !important; }
    .dash-grid > .dash-tile[data-w="2"],
    .dash-grid > .dash-tile[data-w="3"],
    .dash-grid > .dash-tile[data-w="4"]  { grid-column: span 2 !important; }
  }

  /* ── MODE ÉDITION ── */
  /* ── DÉSACTIVATION D'ÉDITION SUR TACTILE (téléphone / tablette) ──
     Sur tactile, on n'autorise QUE le choix d'un profil (basique/simple/complet).
     La classe is-touch-device est posée par applyDeviceCategoryClasses() en
     fonction du résultat de getDeviceCategory() (cf. JS).
     Le bouton « ✎ Réorganiser », la barre d'édition flottante, les poignées
     de redimensionnement et le bouton 👁 « masquer » sont entièrement masqués. */
  body.is-touch-device .dash-edit-toggle,
  body.is-touch-device .dash-edit-bar,
  body.is-touch-device .dash-edge,
  body.is-touch-device .dash-resize-handle,
  body.is-touch-device .dash-hide-btn { display: none !important; }
  /* Et on retire le curseur "grab" éventuellement laissé par le mode édition */
  body.is-touch-device.dash-edit .dash-grid > .dash-tile { cursor: default !important; outline: none !important; }
  body.is-touch-device.dash-edit .dash-grid > .dash-tile::before { display: none !important; }

  /* ── ÉDITEUR PAR APPAREIL : sur tactile, on cache le simulateur entier ──
     Le simulateur n'a de sens que sur PC (manipulation à la souris d'un
     écran de référence). Sur téléphone/tablette, on n'affiche que le
     sélecteur de profils prédéfinis. */
  body.is-touch-device #simulatorWrap { display: none !important; }

  /* ── BLOC « PROFIL DE DISPOSITION » (téléphone / tablette / desktop) ── */
  .preset-picker {
    margin: 0 0 22px;
    padding: 16px 18px;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--card-r, 14px);
  }
  .preset-picker-title {
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--amber);
    margin: 0 0 4px;
  }
  .preset-picker-sub {
    font-size: .82rem;
    color: var(--text2);
    margin: 0 0 16px;
    line-height: 1.5;
  }
  .preset-picker-current {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px;
    border-radius: 999px;
    background: rgba(255, 190, 50, .12);
    border: 1px solid rgba(255, 190, 50, .35);
    color: var(--amber);
    font-size: .78rem;
    font-weight: 600;
    margin-bottom: 14px;
  }
  .preset-picker-current .pp-cat-icon { font-size: 1rem; }
  .preset-row {
    display: grid;
    grid-template-columns: 200px 1fr;
    align-items: center;
    gap: 14px;
    padding: 12px 0;
    border-top: 1px solid var(--border);
  }
  .preset-row:first-of-type { border-top: 0; }
  .preset-row-label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: .9rem;
    font-weight: 600;
    color: var(--text);
  }
  .preset-row-label .pr-icon { font-size: 1.2rem; }
  .preset-row-label .pr-current-badge {
    display: inline-block;
    margin-left: 4px;
    padding: 2px 8px;
    background: var(--amber);
    color: #000;
    border-radius: 999px;
    font-size: .65rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .5px;
  }
  .preset-row-buttons {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
  }
  .preset-btn {
    flex: 1 1 auto;
    min-width: 90px;
    padding: 9px 14px;
    background: var(--bg3);
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--text);
    font-size: .85rem;
    font-weight: 500;
    cursor: pointer;
    transition: background .15s, border-color .15s, color .15s;
  }
  .preset-btn:hover { background: var(--bg4); border-color: var(--amber); }
  .preset-btn.active {
    background: var(--amber);
    border-color: var(--amber);
    color: #000;
    font-weight: 700;
  }
  .preset-btn.active:hover { filter: brightness(1.05); }
  .preset-btn .preset-btn-desc {
    display: block;
    font-size: .68rem;
    margin-top: 2px;
    opacity: .8;
    font-weight: 400;
  }
  .preset-btn.active .preset-btn-desc { opacity: .85; }
  /* Sur tactile : la grille devient mono-colonne pour rester lisible */
  @media (max-width: 700px) {
    .preset-row { grid-template-columns: 1fr; gap: 8px; padding: 14px 0; }
    .preset-row-label { font-size: 1rem; }
  }
  .preset-msg {
    margin-top: 10px;
    padding: 8px 12px;
    border-radius: 6px;
    font-size: .8rem;
    display: none;
  }
  .preset-msg.show { display: block; }
  .preset-msg.success { background: rgba(74, 222, 128, .12); color: #4ade80; }
  .preset-msg.error   { background: rgba(255, 107, 107, .12); color: #ff6b6b; }

  /* Bouton flottant « 🎨 Profil » accessible sur téléphone/tablette uniquement */
  .preset-quick-btn {
    display: none;
    position: fixed;
    right: 16px;
    bottom: 84px;            /* au-dessus de la bottom-nav */
    z-index: 50;
    padding: 10px 16px;
    background: var(--bg2);
    border: 1px solid var(--amber);
    border-radius: 999px;
    color: var(--amber);
    font-size: .8rem;
    font-weight: 600;
    box-shadow: 0 4px 14px rgba(0,0,0,.35);
    cursor: pointer;
  }
  body.is-touch-device.page-dashboard-active .preset-quick-btn { display: inline-flex; align-items: center; gap: 6px; }
  /* Quand l'app est en plein écran ou sans bottom-nav : décaler */
  body.is-touch-device:not(.is-mobile) .preset-quick-btn { bottom: 24px; }
  body.dash-edit .dash-grid > .dash-tile {
    cursor: grab;
    outline: 2px dashed var(--amber);
    outline-offset: -3px;
    user-select: none;
    -webkit-user-select: none;
    transition: outline-color .2s, transform .15s ease;
    position: relative;
    /* Indispensable pour que le drag fonctionne sur tactile (sinon le doigt
       scrolle la page au lieu de glisser la tuile). */
    touch-action: none;
  }
  body.dash-edit .dash-grid > .dash-tile::before {
    content: '⋮⋮';
    position: absolute;
    top: 6px; right: 10px;
    color: var(--amber);
    font-size: 1.1rem;
    font-weight: 900;
    letter-spacing: -2px;
    pointer-events: none;
    z-index: 5;
    opacity: .7;
  }
  body.dash-edit .dash-grid > .dash-tile.dragging {
    opacity: .4;
    cursor: grabbing;
  }
  /* ── Zones de redimensionnement par les bords (visibles en mode édition) ──
     Trois zones : bord droit, bord bas, coin bas-droit. Chaque zone a un
     curseur explicite et déclenche un resize dans la (les) direction(s)
     correspondante(s). Les zones débordent légèrement de la tuile (right/-bottom
     négatifs) pour être faciles à attraper sans masquer le contenu. */
  .dash-edge {
    display: none;
    position: absolute;
    z-index: 6;
    background: transparent;
    touch-action: none;
  }
  .dash-edge-r {
    top: 6px; bottom: 18px;
    right: -3px;
    width: 12px;
    cursor: ew-resize;
  }
  .dash-edge-b {
    left: 6px; right: 18px;
    bottom: -3px;
    height: 12px;
    cursor: ns-resize;
  }
  .dash-edge-br {
    right: -3px; bottom: -3px;
    width: 22px; height: 22px;
    cursor: nwse-resize;
    z-index: 7; /* prioritaire sur les bords droit/bas */
    /* Indicateur visuel ambré dans le coin pour montrer qu'on peut redimensionner */
    background: linear-gradient(135deg,
      transparent 0%, transparent 55%,
      var(--amber) 55%, var(--amber) 65%,
      transparent 65%, transparent 75%,
      var(--amber) 75%, var(--amber) 85%,
      transparent 85%);
    border-bottom-right-radius: var(--card-r, 14px);
    opacity: 0;
    transition: opacity .15s;
  }
  /* Visible uniquement en mode édition (dashboard) ou dans le simulateur */
  body.dash-edit .dash-edge,
  .device-viewport .dash-edge { display: block; }
  body.dash-edit .dash-edge-br,
  .device-viewport .dash-edge-br { opacity: .85; }
  body.dash-edit .dash-edge-br:hover,
  .device-viewport .dash-edge-br:hover { opacity: 1; filter: brightness(1.2); }

  /* Surbrillance subtile des bords au survol (pour indiquer la zone active) */
  body.dash-edit .dash-edge-r:hover,
  body.dash-edit .dash-edge-b:hover,
  .device-viewport .dash-edge-r:hover,
  .device-viewport .dash-edge-b:hover {
    background: rgba(255,190,50,.25);
  }

  /* L'ancienne poignée est neutralisée (mais on garde la classe au cas où
     du code externe la référencerait encore — elle est invisible). */
  .dash-resize-handle { display: none !important; }

  /* ── Bouton "masquer la tuile" — visible en mode édition ── */
  .dash-hide-btn {
    display: none;
    position: absolute;
    top: 6px; left: 8px;
    width: 26px; height: 26px;
    border-radius: 50%;
    background: var(--bg2);
    border: 1px solid var(--border);
    color: var(--text);
    cursor: pointer;
    z-index: 7;
    align-items: center; justify-content: center;
    font-size: .9rem;
    line-height: 1;
    padding: 0;
    transition: all .15s;
  }
  body.dash-edit .dash-hide-btn { display: inline-flex; }
  .dash-hide-btn:hover {
    border-color: var(--red);
    color: var(--red);
    background: rgba(255,107,107,.1);
  }
  /* Dans le simulateur (toujours en mode édition) */
  .device-viewport .dash-hide-btn { display: inline-flex; }

  /* ── Panneau "Tuiles masquées" en mode édition ── */
  .hidden-tiles-panel {
    display: none;
    grid-column: 1 / -1;
    background: rgba(255,190,50,.05);
    border: 1px dashed var(--amber);
    border-radius: var(--card-r, 14px);
    padding: 14px 16px;
    margin-top: 4px;
  }
  body.dash-edit .hidden-tiles-panel,
  .device-viewport .hidden-tiles-panel { display: block; }
  .hidden-tiles-panel-title {
    font-family: 'Orbitron', monospace;
    font-size: .7rem;
    letter-spacing: 2px;
    color: var(--amber);
    text-transform: uppercase;
    margin-bottom: 10px;
  }
  .hidden-tiles-list {
    display: flex; flex-wrap: wrap; gap: 8px;
  }
  .hidden-tile-chip {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 8px 12px;
    font-size: .82rem;
    color: var(--text);
    cursor: pointer;
    display: inline-flex; align-items: center; gap: 7px;
    transition: all .15s;
    font-family: var(--font-body, 'DM Sans'), sans-serif;
  }
  .hidden-tile-chip:hover {
    border-color: var(--amber);
    color: var(--amber);
    background: rgba(255,190,50,.08);
  }
  .hidden-tile-chip-empty {
    font-size: .78rem;
    color: var(--text2);
    font-style: italic;
  }
  /* Pendant le resize, on affiche la taille en chiffres */
  .dash-tile.resizing {
    outline-color: var(--green) !important;
    outline-width: 3px !important;
  }
  .dash-tile.resizing::after {
    content: attr(data-resize-info);
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    background: var(--bg);
    border: 1px solid var(--green);
    color: var(--green);
    padding: 6px 12px;
    border-radius: 8px;
    font-family: 'Orbitron', monospace;
    font-size: .85rem;
    font-weight: 700;
    pointer-events: none;
    z-index: 10;
    white-space: nowrap;
  }
  /* Le ghost qui suit le pointeur */
  .dash-tile-ghost {
    position: fixed;
    pointer-events: none;
    z-index: 9999;
    opacity: .92;
    transform: rotate(1.5deg) scale(1.02);
    box-shadow: 0 12px 36px rgba(0,0,0,.5), 0 0 0 2px var(--amber);
    border-radius: var(--card-r, 14px);
    will-change: transform, top, left;
    transition: none;
  }
  /* ── Overlay de prévisualisation du drop ──
     Pendant le drag, on dessine un rectangle ambré semi-transparent à la
     cellule cible où la tuile va atterrir. Donne un retour visuel précis
     du placement absolu (data-x / data-y). */
  .dash-drop-preview {
    pointer-events: none;
    background: rgba(255, 190, 50, .15);
    border: 2px dashed var(--amber);
    border-radius: var(--card-r, 14px);
    z-index: 4;
    transition: none;
  }
  /* Indicateur drop position : une bordure verte visible et un fond légèrement
     teinté pour bien voir où la tuile va atterrir. */
  .dash-tile.drop-before {
    box-shadow: -4px 0 0 0 var(--green), 0 -4px 0 0 var(--green) !important;
  }
  .dash-tile.drop-after {
    box-shadow: 4px 0 0 0 var(--green), 0 4px 0 0 var(--green) !important;
  }
  /* Désactiver l'ancien drop-target qui faisait scale */
  .dash-tile.drop-target { transform: none; }

  /* ── PANNEAU FLOTTANT MODE ÉDITION ──
     Positionnée EN HAUT (sous le header sticky) pour ne pas masquer
     les tuiles du bas et la bottom-nav mobile. */
  .dash-edit-bar {
    position: fixed;
    left: 50%;
    /* 62px = hauteur du header + 12px de marge */
    top: 74px;
    bottom: auto;
    transform: translateX(-50%);
    z-index: 250;
    background: var(--bg2);
    border: 1px solid var(--amber);
    border-radius: 14px;
    padding: 10px 14px;
    box-shadow: 0 12px 40px rgba(0,0,0,.55), 0 0 0 1px rgba(255,190,50,.2);
    display: none;
    align-items: center; gap: 8px; flex-wrap: wrap;
    max-width: calc(100vw - 24px);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
  }
  body.dash-edit .dash-edit-bar { display: flex; }
  /* Sur mobile / petits écrans : la barre prend toute la largeur en haut */
  @media (max-width: 720px) {
    .dash-edit-bar {
      left: 8px; right: 8px;
      transform: none;
      max-width: none;
      top: calc(70px + env(safe-area-inset-top));
      justify-content: center;
    }
  }
  /* Décaler le contenu vers le bas pendant l'édition pour ne pas
     que la barre flottante recouvre la 1re tuile */
  body.dash-edit main { padding-top: calc(28px + 70px); }
  /* Et laisser de l'espace en bas pour atteindre la bottom-nav sans gêne */
  body.dash-edit main { padding-bottom: 120px; }
  body.is-mobile.dash-edit main { padding-bottom: calc(140px + env(safe-area-inset-bottom)); }
  .dash-edit-bar .bar-info {
    font-size: .76rem; color: var(--text2);
    padding-right: 6px; border-right: 1px solid var(--border);
    margin-right: 4px;
  }
  .dash-edit-bar button {
    background: none; border: 1px solid var(--border);
    color: var(--text);
    border-radius: 8px;
    padding: 6px 11px;
    font-size: .78rem;
    cursor: pointer;
    font-family: var(--font-body, 'DM Sans'), sans-serif;
    transition: all .15s;
    white-space: nowrap;
  }
  .dash-edit-bar button:hover { background: var(--bg3); }
  .dash-edit-bar button.primary {
    background: var(--amber); color: #000; font-weight: 700;
    border-color: var(--amber);
  }
  .dash-edit-bar button.primary:hover { filter: brightness(1.1); }
  .dash-edit-bar button.danger {
    color: var(--red); border-color: var(--red);
  }
  .dash-edit-bar button.danger:hover { background: rgba(255,107,107,.15); }
  /* Bouton ✎ Réorganiser dans le dashboard */
  .dash-edit-toggle {
    display: inline-flex; align-items: center; gap: 6px;
    background: none; border: 1px solid var(--border);
    color: var(--text2);
    padding: 6px 12px;
    border-radius: 8px;
    font-size: .76rem;
    cursor: pointer;
    font-family: var(--font-body, 'DM Sans'), sans-serif;
    transition: all .15s;
    margin-bottom: 14px;
  }
  .dash-edit-toggle:hover { color: var(--amber); border-color: var(--amber); }
  body.dash-edit .dash-edit-toggle { display: none; }
  /* ── Bouton « ✎ Réorganiser » DÉFINITIVEMENT MASQUÉ ──
     L'édition manuelle se fait désormais uniquement via le simulateur dans
     Réglages → Apparence → onglet « Layout par appareil ». Le bouton dans le
     dashboard est conservé dans le DOM (au cas où on voudrait le réactiver)
     mais caché par CSS sur tous les appareils. */
  .dash-edit-toggle { display: none !important; }
  /* ── Bouton flottant « 🎨 Profil » DÉFINITIVEMENT MASQUÉ ──
     Pour changer de profil sur téléphone/tablette : passer par Réglages →
     Apparence → onglet « Layout par appareil ». */
  .preset-quick-btn { display: none !important; }
  /* Long-press feedback : pulse light */
  @keyframes longPressPulse {
    0%   { transform: scale(1); box-shadow: 0 0 0 0 rgba(255,190,50,.6); }
    100% { transform: scale(1.01); box-shadow: 0 0 0 12px rgba(255,190,50,0); }
  }
  .dash-tile.long-press {
    animation: longPressPulse .55s ease-out;
  }

  /* ── CARD ── */
  .card {
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: var(--card-r);
    padding: 20px;
    position: relative; overflow: hidden;
    transition: border-color .2s;
  }
  .card:hover { border-color: rgba(255,190,50,.28); }
  .card::before {
    content: ''; position: absolute; inset: 0;
    background: linear-gradient(135deg, rgba(255,190,50,.03) 0%, transparent 60%);
    pointer-events: none;
  }

  /* ── HERO POWER CARD ── */
  .hero-card {
    background: linear-gradient(135deg, #0f1022 0%, #1a1206 100%);
    border-color: rgba(255,190,50,.3);
    padding: 28px 32px;
    /* Layout vertical : label en haut, valeur au centre (prend tout l'espace
       disponible), barre + légendes en bas. La valeur grossit ou rétrécit
       en fonction de la hauteur réellement disponible entre label et barre. */
    display: flex;
    flex-direction: column;
  }
  /* Zone centrale qui prend l'espace restant entre le label et la barre.
     C'est aussi un container query : la taille de la valeur est calculée
     en % de la hauteur de cette zone (et non de la tuile entière), donc
     elle remplit naturellement tout l'espace disponible quelle que soit
     la hauteur de la tuile. */
  .power-val-wrap {
    flex: 1;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 4px;
    container-type: size;
    container-name: powerwrap;
    overflow: hidden;
  }
  /* La barre et ses légendes restent en bas par défaut (après l'élément flex:1) */
  .power-bar-legend {
    display: flex;
    justify-content: space-between;
    margin-top: 6px;
    font-size: .72rem;
    color: var(--text2);
  }
  .hero-card .power-val {
    font-family: 'Orbitron', monospace;
    font-weight: 900;
    color: var(--amber);
    text-shadow: var(--glow);
    line-height: 1;
    /* font-size : géré par les container queries (cf. @container plus bas)
       et par la règle responsive @media (max-width: 600px) plus bas.
       La container query fait que le texte s'adapte à la hauteur de la
       tuile : plus la tuile est grande, plus la valeur est lisible. */
  }
  .hero-card .power-unit {
    font-family: 'Orbitron', monospace;
    color: var(--amber2);
    margin-left: 8px;
    /* font-size : géré par container query */
  }
  .hero-card .power-label {
    color: var(--text2);
    letter-spacing: 2px; text-transform: uppercase;
    margin-bottom: 8px;
    /* font-size : géré par container query */
  }
  .power-bar-wrap {
    margin-top: 18px;
    height: 6px; border-radius: 99px;
    background: rgba(255,255,255,.06);
    overflow: hidden;
  }
  .power-bar {
    height: 100%; border-radius: 99px;
    background: linear-gradient(90deg, var(--amber2), var(--amber), var(--amber3));
    transition: width 1s ease;
    box-shadow: 0 0 12px var(--amber);
  }

  /* ════════════════════════════════════════════════════════════════
     TEXTES ADAPTATIFS — Container Queries
     Les textes dans les tuiles s'adaptent proportionnellement
     à la taille de la tuile (cqh = % de hauteur du container).
  ════════════════════════════════════════════════════════════════ */

  /* Valeur principale (stat-val : kWh, kg, €…) — adaptée à la tuile.
     min(cqh, cqi) garantit qu'on ne dépasse JAMAIS, ni en hauteur ni en
     largeur. Coefficients calibrés pour que "0.04 kg" tienne sur tuile
     170×130 (téléphone demi-largeur) tout en grossissant joliment sur
     grandes tuiles. */
  @container tile (min-height: 1px) {
    .stat-label {
      font-size: clamp(.55rem, 2cqh, .85rem);
    }
    .stat-val {
      /* Compact : ~1.4-1.8 rem max sur tuile 110 px. cqi seul sans cqh
         (la hauteur n'a plus à brider, le min-height de la tuile garantit
         l'espace pour les 3 zones). */
      font-size: clamp(1.1rem, 11cqi, 1.9rem);
      line-height: 1;
    }
    .stat-val .unit {
      font-size: clamp(.55rem, min(5cqh, 5cqi), 1rem);
    }
    .stat-trend {
      font-size: clamp(.6rem, 2.5cqh, .85rem);
    }
    /* Puissance instantanée — label et légendes : adaptées à la TUILE.
       Coefficients basés sur la largeur (cqi) pour bien remplir les
       grandes tuiles desktop. */
    .dash-grid > .dash-tile.hero-card .power-label {
      font-size: clamp(.65rem, 1.6cqi, 1.1rem);
    }
    .dash-grid > .dash-tile.hero-card .power-bar-legend {
      font-size: clamp(.65rem, 1.3cqi, .95rem);
    }
  }

  /* Puissance instantanée — valeur et unité : adaptées à la ZONE FLEX
     (powerwrap), qui correspond exactement à l'espace disponible entre
     le label et la barre. C'est un container nesté à l'intérieur de la
     tuile. La valeur peut donc remplir toute la hauteur disponible
     sans déborder, quelle que soit la taille de la tuile. */
  @container powerwrap (min-height: 1px) {
    .power-val {
      /* clamp(min, idéal, max) :
         - 1.8rem : taille minimale (pour très petites tuiles compact)
         - min(70cqh, 16cqi) : 70% de la hauteur OU 16% de la largeur,
           le plus petit des deux pour ne jamais déborder
         - 9rem : plafond sur très grands écrans */
      font-size: clamp(1.8rem, min(70cqh, 16cqi), 9rem);
      line-height: 1;
      white-space: nowrap;
    }
    .power-unit {
      font-size: clamp(.8rem, min(28cqh, 6cqi), 2.5rem);
      white-space: nowrap;
    }
  }

  /* Container general pour les autres éléments (label etc.) */
  @container tile (min-height: 1px) {
    /* (suite vide volontaire — les règles spécifiques hero-card sont au-dessus) */
    /* Titres de section dans les tuiles */
    .stat-title, .card-title, .chart-title {
      font-size: clamp(.55rem, 2cqh, .85rem);
    }
    /* Barres et légendes */
    .chart-legend, .chart-legend * {
      font-size: clamp(.55rem, 2cqh, .8rem);
    }
    /* Jauge */
    .gauge-pct {
      font-size: clamp(1rem, 9cqh, 2.5rem);
    }
    .gauge-label {
      font-size: clamp(.55rem, 2.5cqh, .8rem);
    }
  }

  /* ── STAT CARD ── */
  .stat-label {
    font-size: .75rem; color: var(--text2);
    letter-spacing: 1.5px; text-transform: uppercase;
    margin-bottom: 6px;
  }
  .stat-val {
    font-family: 'Orbitron', monospace;
    font-size: 1.6rem; font-weight: 700;
    color: var(--text);
    line-height: 1.1;
  }
  .stat-val .unit { font-size: .9rem; color: var(--text2); margin-left: 4px; }
  .stat-trend {
    font-size: .78rem; margin-top: 4px;
    display: flex; align-items: center; gap: 4px;
  }
  .trend-up   { color: var(--green); }
  .trend-down { color: var(--red); }
  .trend-eq   { color: var(--text2); }

  /* ── KPI TILES (prod, peak, co2, euro, eurCost, eurSaved, eurSold, eurBilan, voltage) : flex column ──
     Pour ces tuiles standards (label + val + trend/info), on applique
     un layout flex column avec 3 zones :
     - .stat-label  : en haut, taille naturelle (flex-shrink: 0)
     - .stat-val    : milieu, prend tout l'espace flex
     - .stat-trend  : en bas, taille naturelle (flex-shrink: 0)
     C'est crucial que stat-trend ait flex-shrink:0 et pas de position
     forcée, sinon il se superpose à la stat-val agrandie. */
  /* Padding interne plus serré sur les tuiles KPI plates (data-h=1)
     pour libérer de la place pour les 3 zones (label / val / trend).
     S'applique à tous les écrans (PC inclus) car ces tuiles sont
     particulièrement contraintes en hauteur. */
  .dash-grid > .dash-tile[data-h="1"]:not(.chart-card):not(.hero-card):not(.gauge-card):not(.enphase-card):not(.flux-card):not(#tuyaConsCard):not(#fluxPanel) {
    padding: 10px 14px !important;
    /* Forcer min-height confortable pour 3 zones — sinon impossible. */
    min-height: 110px !important;
  }
  .dash-grid > .dash-tile:not(.hero-card):not(.chart-card):not(.gauge-card):not(.enphase-card):not(.flux-card):not(#tuyaConsCard):not(#fluxPanel) {
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .dash-grid > .dash-tile:not(.hero-card):not(.chart-card):not(.gauge-card):not(.enphase-card):not(.flux-card):not(#tuyaConsCard):not(#fluxPanel) > .stat-label {
    flex-shrink: 0;
  }
  .dash-grid > .dash-tile:not(.hero-card):not(.chart-card):not(.gauge-card):not(.enphase-card):not(.flux-card):not(#tuyaConsCard):not(#fluxPanel) > .stat-val {
    /* Taille naturelle, ni grow ni shrink. La container query plus bas
       lui donne une font compacte adaptée à la largeur de la tuile. */
    flex: 0 0 auto;
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin: 0;
  }
  .dash-grid > .dash-tile:not(.hero-card):not(.chart-card):not(.gauge-card):not(.enphase-card):not(.flux-card):not(#tuyaConsCard):not(#fluxPanel) > .stat-trend {
    flex-shrink: 0;
    margin-top: auto;
  }

  /* ── SOURCE BADGE ── */
  .source-row {
    display: flex; gap: 8px; margin-bottom: 16px;
    flex-wrap: wrap;
  }
  .source-badge {
    display: flex; align-items: center; gap: 6px;
    background: var(--bg3); border: 1px solid var(--border);
    border-radius: 99px; padding: 5px 14px;
    font-size: .78rem;
  }
  .source-badge .dot {
    width: 7px; height: 7px; border-radius: 50%;
  }
  .dot-enphase { background: var(--amber); box-shadow: 0 0 6px var(--amber); }
  .dot-ok      { background: var(--green); box-shadow: 0 0 6px var(--green); }
  .dot-err     { background: var(--red);   box-shadow: 0 0 6px var(--red); }

  /* ── CHART CARD ── */
  .chart-card { padding: 20px; }
  .chart-card canvas { max-height: 280px; }
  .chart-title {
    font-size: .8rem; color: var(--text2);
    letter-spacing: 1.5px; text-transform: uppercase;
    margin-bottom: 16px;
    display: flex; justify-content: space-between; align-items: center;
  }
  .chart-legend {
    display: flex; gap: 14px; font-size: .75rem;
  }
  .legend-item { display: flex; align-items: center; gap: 6px; }
  .legend-dot { width: 8px; height: 8px; border-radius: 50%; }

  /* ── PERIOD SELECTOR ── */
  .period-sel {
    display: flex; gap: 4px; background: var(--bg);
    border: 1px solid var(--border); border-radius: 10px; padding: 4px;
  }
  .period-btn {
    background: none; border: none; cursor: pointer;
    color: var(--text2); font-family: 'DM Sans', sans-serif;
    font-size: .78rem; padding: 5px 12px;
    border-radius: 7px; transition: all .2s;
  }
  .period-btn.active { background: var(--amber); color: #000; font-weight: 600; }
  .period-btn:not(.active):hover { color: var(--text); background: var(--bg3); }

  .export-date {
    background: var(--bg3);
    border: 1px solid var(--border);
    color: var(--text);
    font-family: 'DM Sans', sans-serif;
    font-size: .78rem;
    padding: 5px 8px;
    border-radius: 7px;
    color-scheme: dark;
  }
  .export-date:focus {
    outline: none;
    border-color: var(--amber);
  }

  /* ── HISTORY TABLE ── */
  .hist-table { width: 100%; border-collapse: collapse; font-size: .85rem; }
  .hist-table th {
    text-align: left; color: var(--text2); font-weight: 500;
    font-size: .72rem; letter-spacing: 1.5px; text-transform: uppercase;
    padding: 10px 14px; border-bottom: 1px solid var(--border);
  }
  .hist-table td { padding: 10px 14px; border-bottom: 1px solid rgba(255,255,255,.04); }
  .hist-table tr:hover td { background: rgba(255,190,50,.03); }
  .hist-table .num {
    font-family: 'Orbitron', monospace; font-size: .85rem;
  }
  .bar-inline {
    height: 4px; background: linear-gradient(90deg,var(--amber2),var(--amber));
    border-radius: 99px; display: inline-block; vertical-align: middle;
    min-width: 2px;
  }

  /* ── LIGNES HISTORIQUE CLIQUABLES (vue jours) ── */
  .hist-row-clickable { cursor: pointer; transition: background-color .15s; }
  .hist-row-clickable:hover td { background: rgba(255,190,50,.06); }
  .hist-row-clickable td:first-child { position: relative; }
  .hist-row-hint {
    margin-left: 8px; opacity: 0.35; font-size: .85em;
    transition: opacity .15s;
  }
  .hist-row-clickable:hover .hist-row-hint { opacity: 0.8; }
  .hist-row.selected td {
    background: rgba(255,190,50,.12) !important;
    border-bottom-color: rgba(255,190,50,.4);
  }
  .hist-row.selected td:first-child {
    border-left: 3px solid var(--amber);
    padding-left: 11px;
  }
  /* Indication Ctrl+Clic au survol en vue jours */
  .hist-row-clickable:hover td:first-child::after {
    content: attr(data-ctrl-hint);
  }
  /* Barre de comparaison multi-jours */
  #compareBar { display: none; }
  #compareBar[style*="flex"] { display: flex !important; }

  /* ── PANNEAU GRAPHIQUE JOURNALIER ── */
  .day-chart-panel {
    margin-top: 16px;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 18px 20px;
    animation: dayPanelSlideIn .25s ease;
  }
  @keyframes dayPanelSlideIn {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0);   }
  }
  .day-chart-head {
    display: flex; justify-content: space-between; align-items: flex-start;
    gap: 12px; margin-bottom: 14px;
  }
  .day-chart-title {
    font-family: 'Orbitron', monospace;
    font-size: .92rem; font-weight: 700;
    color: var(--amber); letter-spacing: 1.5px;
    text-transform: uppercase;
  }
  .day-chart-subtitle {
    font-size: .72rem; color: var(--text2); margin-top: 4px;
  }
  .day-chart-stats {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
    margin-bottom: 16px;
  }
  .day-stat {
    background: var(--bg3);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 10px 14px;
  }
  .day-stat-label {
    font-size: .68rem; color: var(--text2);
    text-transform: uppercase; letter-spacing: 1px;
    margin-bottom: 4px;
  }
  .day-stat-value {
    font-family: 'Orbitron', monospace;
    font-size: 1.15rem; font-weight: 700;
    color: var(--text);
  }
  .day-stat-value .unit {
    font-size: .7rem; color: var(--text2);
    margin-left: 3px; font-weight: 400;
  }
  .day-stat-aux {
    font-size: .7rem; color: var(--text2);
    font-weight: 400; margin-left: 4px;
    font-family: 'DM Sans', sans-serif;
  }
  .day-chart-body {
    height: 280px;
    position: relative;
  }
  @media (max-width: 700px) {
    .day-chart-stats { grid-template-columns: 1fr 1fr; }
  }
  @media (max-width: 400px) {
    .day-chart-stats { grid-template-columns: 1fr; }
  }

  /* ── FENÊTRES GRAPHIQUES FLOTTANTES ── */
  .chart-float-win {
    position: fixed;
    z-index: 8000;
    width: min(680px, calc(100vw - 32px));
    background: var(--bg2);
    border: 1px solid rgba(255,190,50,.25);
    border-radius: 16px;
    box-shadow: 0 24px 64px rgba(0,0,0,.7), 0 0 0 1px rgba(255,190,50,.08);
    overflow: hidden;
    top: 80px;
    left: 50%;
    transform: translateX(-50%);
    animation: cfwIn .22s ease;
    display: flex;
    flex-direction: column;
  }
  @keyframes cfwIn {
    from { opacity: 0; transform: translateX(-50%) scale(.96) translateY(-8px); }
    to   { opacity: 1; transform: translateX(-50%) scale(1)   translateY(0);    }
  }
  /* quand la fenêtre a été déplacée, on retire le centrage */
  .chart-float-win.dragged {
    transform: none;
    left: auto;
  }
  .cfw-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding: 14px 18px 12px;
    cursor: grab;
    background: var(--bg3);
    border-bottom: 1px solid var(--border);
    user-select: none;
    flex-shrink: 0;
  }
  .cfw-header:active { cursor: grabbing; }
  .cfw-close {
    width: 30px; height: 30px;
    background: rgba(255,255,255,.06);
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--text2);
    font-size: .85rem;
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
    transition: background .15s, color .15s;
  }
  .cfw-close:hover { background: rgba(255,107,107,.15); color: var(--red); }
  .cfw-body {
    padding: 16px 18px 18px;
    overflow-y: auto;
    max-height: calc(100vh - 160px);
  }
  @media (max-width: 700px) {
    .chart-float-win { width: calc(100vw - 16px); top: 60px; border-radius: 12px; }
    .cfw-body { padding: 12px 14px 14px; }
  }

  /* ── MINI GAUGE ── */
  .gauge-wrap { display: flex; flex-direction: column; align-items: center; gap: 8px; }
  .gauge-svg { overflow: visible; }
  /* ── Tuile « Taux d'utilisation » (gauge-card) ──
     Structure flex column : la zone SVG prend tout l'espace dispo,
     le label « Taux d'utilisation » reste en bas. Le SVG est carré
     (aspect-ratio: 1) et prend la plus petite des deux dimensions du
     wrap pour ne jamais déborder. */
  .dash-grid > .dash-tile.gauge-card {
    display: flex;
    flex-direction: column;
    align-items: stretch;     /* enfants en pleine largeur */
    gap: 8px;
  }
  .gauge-svg-wrap {
    flex: 1;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .dash-grid > .dash-tile.gauge-card .gauge-svg {
    /* Le SVG prend toute la hauteur du wrap, et reste carré.
       Si la tuile est plus large que haute, height limite ;
       si elle est plus haute que large, max-width limite via aspect-ratio. */
    height: 100%;
    width: auto;
    max-width: 100%;
    max-height: 100%;
    aspect-ratio: 1;
  }
  /* Label « Taux d'utilisation » sous la jauge */
  .gauge-foot {
    color: var(--text2);
    text-align: center;
    font-size: .75rem;
    flex-shrink: 0;
  }
  .dash-grid > .dash-tile.gauge-card .gauge-foot {
    font-size: clamp(.65rem, 1.6cqi, 1rem);
  }

  /* ── ALERTS / STATUS ── */
  .alert { border-radius: 10px; padding: 12px 16px; font-size: .82rem; margin-bottom: 14px; }
  .alert-warn { background: rgba(255,190,50,.1); border: 1px solid rgba(255,190,50,.3); color: var(--amber3); }
  .alert-err  { background: rgba(255,107,107,.1); border: 1px solid rgba(255,107,107,.3); color: var(--red); }
  .alert-ok   { background: rgba(61,220,132,.1);  border: 1px solid rgba(61,220,132,.3);  color: var(--green); }

  /* ── LOADING SPINNER ── */
  .spinner {
    width: 28px; height: 28px;
    border: 2px solid var(--border);
    border-top-color: var(--amber);
    border-radius: 50%;
    animation: spin .7s linear infinite;
  }
  @keyframes spin { to { transform: rotate(360deg); } }
  .loading-row { display: flex; align-items: center; gap: 12px; color: var(--text2); font-size: .85rem; padding: 20px 0; }

  /* ── SETTINGS ── */
  .settings-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }

  /* ── TOGGLE SWITCH (cases à cocher dans Réglages) ── */
  .toggle-row {
    display: flex; align-items: center;
    gap: 14px; cursor: pointer; user-select: none;
    padding: 4px 0;
  }
  .toggle-row input[type="checkbox"] {
    position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none;
  }
  .toggle-slider {
    position: relative; flex-shrink: 0;
    width: 42px; height: 22px;
    background: var(--bg3);
    border: 1px solid var(--border);
    border-radius: 99px;
    transition: background-color .2s, border-color .2s;
  }
  .toggle-slider::before {
    content: ''; position: absolute;
    top: 2px; left: 2px;
    width: 16px; height: 16px;
    background: var(--text2);
    border-radius: 50%;
    transition: transform .2s, background-color .2s;
  }
  .toggle-row input:checked ~ .toggle-slider {
    background: var(--amber); border-color: var(--amber);
  }
  .toggle-row input:checked ~ .toggle-slider::before {
    transform: translateX(20px);
    background: #000;
  }
  .toggle-text { display: flex; flex-direction: column; gap: 2px; }
  .toggle-title { font-size: .9rem; color: var(--text); font-weight: 500; }
  .toggle-desc  { font-size: .75rem; color: var(--text2); }
  .field-group { display: flex; flex-direction: column; gap: 6px; }
  .field-label { font-size: .78rem; color: var(--text2); letter-spacing: 1px; text-transform: uppercase; }
  .field-input {
    background: var(--bg3); border: 1px solid var(--border);
    color: var(--text); font-family: 'DM Sans', sans-serif; font-size: .9rem;
    padding: 10px 14px; border-radius: 8px; width: 100%;
    transition: border-color .2s;
  }
  .field-input:focus { outline: none; border-color: var(--amber); }
  .btn-primary {
    background: var(--amber); color: #000; border: none; cursor: pointer;
    font-family: 'DM Sans', sans-serif; font-weight: 700; font-size: .9rem;
    padding: 11px 28px; border-radius: 9px; transition: all .2s;
  }
  .btn-primary:hover { background: var(--amber3); }

  /* ── SETTINGS TABS (niveau page) ── */
  .settings-tabs {
    display: flex; gap: 4px; margin-bottom: 22px;
    background: var(--bg2); border: 1px solid var(--border);
    border-radius: 11px; padding: 5px; width: fit-content;
    flex-wrap: wrap;
  }
  .settings-tab {
    background: none; border: none; cursor: pointer;
    color: var(--text2);
    font-family: var(--font-body, 'DM Sans'), sans-serif;
    font-size: .85rem; font-weight: 500;
    padding: 8px 18px; border-radius: 8px;
    transition: all .2s;
    display: inline-flex; align-items: center; gap: 6px;
  }
  .settings-tab.active {
    background: var(--amber); color: #000; font-weight: 700;
  }
  .settings-tab:not(.active):hover { color: var(--text); background: var(--bg3); }
  .settings-pane { display: none; }
  .settings-pane.active { display: block; }

  /* ── FULLSCREEN BUTTON (header) ── */
  .fs-btn {
    background: none;
    border: 1px solid var(--border);
    color: var(--text2);
    cursor: pointer;
    width: 32px; height: 32px;
    border-radius: 8px;
    display: inline-flex; align-items: center; justify-content: center;
    transition: all .2s;
    margin-left: 4px;
    padding: 0;
  }
  .fs-btn:hover { border-color: var(--amber); color: var(--amber); }
  .fs-btn svg { width: 16px; height: 16px; display: block; }

  /* ── WAKE LOCK INDICATOR ── */
  .wl-indicator {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px;
    border-radius: 50%;
    margin-left: 6px;
    font-size: .7rem;
    color: var(--text2);
    transition: color .2s, text-shadow .2s;
    cursor: help;
  }
  .wl-indicator.active {
    color: var(--green);
    text-shadow: 0 0 6px var(--green);
  }
  .wl-indicator.error {
    color: var(--red);
    text-shadow: 0 0 6px var(--red);
  }

  /* ── FULLSCREEN MODAL ── */
  .fs-modal-overlay {
    position: fixed; inset: 0;
    background: rgba(0,0,0,.78);
    backdrop-filter: blur(8px);
    z-index: 9998;
    display: none;
    align-items: center; justify-content: center;
    padding: 20px;
    animation: fsFadeIn .25s ease;
  }
  .fs-modal-overlay.show { display: flex; }
  @keyframes fsFadeIn { from { opacity: 0; } to { opacity: 1; } }

  .fs-modal-card {
    background: linear-gradient(135deg, var(--bg2) 0%, var(--bg3) 100%);
    border: 1px solid rgba(255,190,50,.35);
    border-radius: 16px;
    padding: 28px 30px;
    max-width: 440px;
    width: 100%;
    box-shadow: 0 20px 60px rgba(0,0,0,.6), 0 0 40px rgba(255,190,50,.12);
    text-align: center;
    animation: fsSlideUp .3s ease;
  }
  @keyframes fsSlideUp {
    from { transform: translateY(20px); opacity: 0; }
    to   { transform: translateY(0);    opacity: 1; }
  }
  .fs-modal-icon {
    width: 56px; height: 56px;
    margin: 0 auto 14px;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(255,190,50,.2) 0%, transparent 70%);
    display: flex; align-items: center; justify-content: center;
    color: var(--amber);
  }
  .fs-modal-icon svg { width: 28px; height: 28px; }
  .fs-modal-title {
    font-family: 'Orbitron', monospace;
    font-size: 1rem;
    font-weight: 700;
    color: var(--amber);
    letter-spacing: 1.5px;
    margin-bottom: 8px;
  }
  .fs-modal-text {
    font-size: .88rem;
    color: var(--text2);
    line-height: 1.5;
    margin-bottom: 22px;
  }
  .fs-modal-actions {
    display: flex; gap: 10px; justify-content: center;
    flex-wrap: wrap;
  }
  .fs-modal-actions .btn-primary,
  .fs-modal-actions .btn-secondary {
    min-width: 130px;
  }
  .fs-modal-skip {
    margin-top: 14px;
    font-size: .72rem; color: var(--text2);
    display: flex; align-items: center; justify-content: center; gap: 6px;
    cursor: pointer;
    user-select: none;
  }
  .fs-modal-skip input { accent-color: var(--amber); cursor: pointer; }

  /* ── MODE AUTO-ZOOM : enlever le padding pour maximiser l'espace ── */
  body.autozoom > main {
    padding: 8px 12px !important;
  }

  /* ── MASQUAGE APP PENDANT AUTH CHECK ── */
  body.app-hidden > header,
  body.app-hidden > main,
  body.app-hidden > .bottom-nav,
  body.app-hidden > .chart-float-win,
  body.app-hidden > .fs-modal-overlay,
  body.app-hidden > .dash-edit-bar {
    opacity: 0;
    pointer-events: none;
  }
  /* transition douce lors de la révélation */
  header, main, .bottom-nav {
    transition: opacity .35s ease;
  }

  /* ── AUTH OVERLAY ── */
  .auth-overlay {
    position: fixed; inset: 0;
    background: var(--bg);
    z-index: 99999;
    display: flex;
    align-items: center; justify-content: center;
    padding: 20px;
  }
  .auth-box {
    background: var(--bg2);
    border: 1px solid rgba(255,190,50,.3);
    border-radius: 20px;
    padding: 36px 32px;
    max-width: 380px; width: 100%;
    box-shadow: 0 24px 64px rgba(0,0,0,.7), 0 0 50px rgba(255,190,50,.1);
    text-align: center;
    animation: fsSlideUp .3s ease;
  }
  .auth-logo { display: flex; justify-content: center; margin-bottom: 14px; }
  .auth-title {
    font-family: 'Orbitron', monospace;
    font-size: 1.3rem; font-weight: 900;
    color: var(--amber); letter-spacing: 3px;
    margin-bottom: 6px;
  }
  .auth-subtitle {
    font-size: .78rem; color: var(--text2);
    margin-bottom: 26px; line-height: 1.5;
  }
  .auth-input {
    width: 100%;
    background: var(--bg3); color: var(--text);
    border: 1px solid var(--border); border-radius: 10px;
    padding: 12px 16px; font-size: .95rem;
    font-family: var(--font-body, 'DM Sans'), sans-serif;
    outline: none; transition: border-color .2s;
    margin-bottom: 10px;
  }
  .auth-input:focus { border-color: var(--amber); }
  .auth-remember-label {
    display: block; text-align: left;
    font-size: .78rem; color: var(--text2);
    margin: 6px 2px 4px;
  }
  .auth-select {
    appearance: none; -webkit-appearance: none; -moz-appearance: none;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
    background-repeat: no-repeat;
    background-position: right 14px center;
    padding-right: 38px;
    cursor: pointer;
  }
  .auth-btn {
    width: 100%; padding: 13px;
    background: var(--amber); color: #000;
    border: none; border-radius: 10px;
    font-size: .95rem; font-weight: 700;
    font-family: var(--font-body, 'DM Sans'), sans-serif;
    cursor: pointer; margin-top: 6px;
    transition: filter .15s;
  }
  .auth-btn:hover { filter: brightness(1.1); }
  .auth-btn:disabled { opacity: .6; cursor: not-allowed; filter: none; }

  @media (max-width: 900px) {
    .grid-5,.grid-4 { grid-template-columns: repeat(2,1fr); }
    .grid-3 { grid-template-columns: 1fr 1fr; }
    .grid-21,.grid-12 { grid-template-columns: 1fr; }
    .col-span-2,.col-span-3 { grid-column: span 1; }
    .settings-grid { grid-template-columns: 1fr; }
  }
  @media (max-width: 600px) {
    .grid-5,.grid-4,.grid-3,.grid-2 { grid-template-columns: 1fr; }
    main { padding: 16px; }
    /* La taille de power-val sur mobile est désormais gérée par la
       container query (clamp 1.4rem - 16cqh - 4.5rem). On ne hardcode
       plus 2.8rem ici pour laisser la tuile s'adapter à sa hauteur. */
    /* ── Sécurisation du label « PUISSANCE INSTANTANÉE » sur téléphone ──
       Le label est en majuscules avec letter-spacing: 2px, ce qui le
       rend très large pour une tuile de 360px. On réduit l'espacement
       et on ajoute un overflow:ellipsis pour qu'il ne déborde jamais. */
    .hero-card .power-label {
      letter-spacing: 1px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      max-width: 100%;
    }
    /* La valeur (315 W) doit aussi se contenir si l'unité ou le nombre
       devient long (« 12 345 W » par ex.) */
    .hero-card .power-val,
    .hero-card .power-unit { white-space: nowrap; }
    /* Réduire le padding interne de la hero-card pour libérer de la place */
    .dash-grid > .dash-tile.hero-card[data-h="2"],
    .dash-grid > .dash-tile.hero-card[data-h="3"] { padding: 14px 16px !important; }
  }

  /* ── INVERTER GRID ── */
  .inv-summary {
    display: flex; align-items: center; gap: 20px;
    background: var(--bg2); border: 1px solid var(--border);
    border-radius: var(--card-r); padding: 16px 24px;
    margin-bottom: 20px; flex-wrap: wrap;
  }
  .inv-summary-count {
    font-family: 'Orbitron', monospace;
    font-size: 2rem; font-weight: 900; color: var(--amber);
    line-height: 1;
  }
  .inv-summary-label { font-size: .8rem; color: var(--text2); letter-spacing: 1px; text-transform: uppercase; }
  .inv-summary-sep { width: 1px; height: 40px; background: var(--border); }

  /* ── PANNEAU VOYANTS ENVOY ── */
  .envoy-leds { padding: 14px 18px; margin-bottom: 16px; }
  .envoy-leds-head {
    display: flex; align-items: center; gap: 10px;
    margin-bottom: 12px;
  }
  .envoy-leds-title {
    font-family: 'Orbitron', monospace; font-size: .78rem;
    letter-spacing: 2px; color: var(--amber); text-transform: uppercase;
  }
  .envoy-leds-ip {
    font-size: .7rem; color: var(--text2);
    font-family: monospace;
    margin-left: auto;
  }
  .envoy-leds-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
  }
  .envoy-led {
    display: flex; align-items: center; gap: 10px;
    background: var(--bg3); border: 1px solid var(--border);
    border-radius: 10px; padding: 10px 12px;
    cursor: help;
    transition: border-color .2s;
  }
  .envoy-led:hover { border-color: rgba(255,190,50,.35); }
  .envoy-led-dot {
    width: 14px; height: 14px;
    border-radius: 50%;
    flex-shrink: 0;
    background: var(--text2);
    box-shadow: none;
    position: relative;
  }
  .envoy-led-dot.green {
    background: #4ade80;
    box-shadow: 0 0 8px #4ade80, 0 0 14px rgba(74,222,128,.4);
    animation: ledPulse 2s ease-in-out infinite;
  }
  .envoy-led-dot.amber {
    background: var(--amber);
    box-shadow: 0 0 8px var(--amber), 0 0 14px rgba(255,190,50,.4);
    animation: ledPulse 1.2s ease-in-out infinite;
  }
  .envoy-led-dot.red {
    background: #ff6b6b;
    box-shadow: 0 0 8px #ff6b6b, 0 0 14px rgba(255,107,107,.4);
    animation: ledPulse 0.7s ease-in-out infinite;
  }
  .envoy-led-dot.off { background: #444; box-shadow: none; }
  .envoy-led-dot.unknown {
    background: var(--text2);
    box-shadow: 0 0 4px var(--text2);
  }
  /* Pulsation spéciale "export en cours" : clignotement rapide vert
     reproduisant le comportement du voyant réseau Envoy en surproduction. */
  .envoy-led-dot.exporting {
    animation: ledExportPulse 0.6s ease-in-out infinite !important;
  }
  @keyframes ledExportPulse {
    0%, 100% { opacity: 1;   transform: scale(1.05); }
    50%      { opacity: .25; transform: scale(0.85); }
  }
  @keyframes ledPulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: .55; }
  }
  .envoy-led-info { display: flex; flex-direction: column; min-width: 0; }
  .envoy-led-label {
    font-size: .8rem; color: var(--text); font-weight: 600;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .envoy-led-detail {
    font-size: .68rem; color: var(--text2);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  @media (max-width: 900px) {
    .envoy-leds-grid { grid-template-columns: repeat(2, 1fr); }
  }
  @media (max-width: 500px) {
    .envoy-leds-grid { grid-template-columns: 1fr; }
  }

  /* ── CARTE ENPHASE (Dashboard) avec voyants à droite ── */
  .enphase-card-body {
    display: flex;
    align-items: stretch;
    gap: 16px;
  }
  .enphase-card-main { flex: 1; min-width: 0; }
  .envoy-mini-leds {
    display: flex; flex-direction: column;
    justify-content: center; gap: 10px;
    padding-left: 16px;
    border-left: 1px solid var(--border);
    flex-shrink: 0;
  }
  .envoy-mini-led {
    display: flex; align-items: center; gap: 8px;
    font-size: .75rem;
    color: var(--text2);
    cursor: help;
    user-select: none;
    white-space: nowrap;
  }
  .envoy-mini-led .envoy-led-dot { width: 10px; height: 10px; }
  .envoy-mini-led-label { color: var(--text2); }

  /* ── PANNEAU FLUX ÉNERGÉTIQUE ── */
  /* Quand la flux-card est dans le dashboard grid, elle doit s'adapter
     à la hauteur de sa tuile. Layout flex column : title fixe, grid prend
     l'espace dispo, footer fixe. */
  .dash-grid > .dash-tile.flux-card {
    display: flex !important;
    flex-direction: column;
    overflow: hidden;
    padding: 14px 18px;
  }
  .dash-grid > .dash-tile.flux-card .flux-head {
    flex-shrink: 0; margin-bottom: 10px;
  }
  .dash-grid > .dash-tile.flux-card .flux-grid {
    flex: 1 1 auto;
    min-height: 0;
    align-items: stretch;
  }
  .dash-grid > .dash-tile.flux-card .flux-footer { flex-shrink: 0; }

  /* h=2 (~124px) : très compact — on cache le footer ET les flèches,
     on ne garde que les 3 nœuds Solaire/Maison/Réseau pour rester lisible */
  .dash-grid > .dash-tile[data-h="2"].flux-card { padding: 10px 14px; }
  .dash-grid > .dash-tile[data-h="2"].flux-card .flux-head {
    margin-bottom: 8px;
  }
  .dash-grid > .dash-tile[data-h="2"].flux-card .flux-title { font-size: .7rem; letter-spacing: 1px; }
  .dash-grid > .dash-tile[data-h="2"].flux-card .flux-mode { font-size: .65rem; padding: 2px 8px; }
  .dash-grid > .dash-tile[data-h="2"].flux-card .flux-grid {
    grid-template-columns: 1fr 1fr 1fr;
    gap: 8px;
  }
  .dash-grid > .dash-tile[data-h="2"].flux-card .flux-arrow { display: none; }
  .dash-grid > .dash-tile[data-h="2"].flux-card .flux-node {
    padding: 6px 4px; gap: 2px;
  }
  .dash-grid > .dash-tile[data-h="2"].flux-card .flux-node-icon {
    width: 24px; height: 24px;
  }
  .dash-grid > .dash-tile[data-h="2"].flux-card .flux-node-icon svg {
    width: 20px; height: 20px;
  }
  .dash-grid > .dash-tile[data-h="2"].flux-card .flux-node-label { font-size: .58rem; letter-spacing: .8px; }
  .dash-grid > .dash-tile[data-h="2"].flux-card .flux-node-value { font-size: .82rem; }
  .dash-grid > .dash-tile[data-h="2"].flux-card .flux-node-aux { font-size: .55rem; }
  .dash-grid > .dash-tile[data-h="2"].flux-card .flux-footer { display: none; }

  /* h=3 (~193px) : on cache le footer mais on garde les flèches centrales */
  .dash-grid > .dash-tile[data-h="3"].flux-card { padding: 12px 16px; }
  .dash-grid > .dash-tile[data-h="3"].flux-card .flux-head { margin-bottom: 10px; }
  .dash-grid > .dash-tile[data-h="3"].flux-card .flux-grid {
    gap: 0;
  }
  .dash-grid > .dash-tile[data-h="3"].flux-card .flux-node { padding: 9px 6px; gap: 3px; }
  .dash-grid > .dash-tile[data-h="3"].flux-card .flux-node-icon { width: 32px; height: 32px; }
  .dash-grid > .dash-tile[data-h="3"].flux-card .flux-node-icon svg { width: 26px; height: 26px; }
  .dash-grid > .dash-tile[data-h="3"].flux-card .flux-node-label { font-size: .6rem; }
  .dash-grid > .dash-tile[data-h="3"].flux-card .flux-node-value { font-size: .92rem; }
  .dash-grid > .dash-tile[data-h="3"].flux-card .flux-arrow-label { font-size: .58rem; }
  .dash-grid > .dash-tile[data-h="3"].flux-card .flux-arrow-value { font-size: .8rem; }
  .dash-grid > .dash-tile[data-h="3"].flux-card .flux-footer { display: none; }

  /* h=4 (~262px) : tout visible, mais légèrement compact */
  .dash-grid > .dash-tile[data-h="4"].flux-card .flux-footer {
    margin-top: 12px; padding-top: 12px; gap: 8px;
  }

  /* h=1 (~60px, demi-hauteur) : juste le titre */
  .dash-grid > .dash-tile[data-h="1"].flux-card { padding: 10px 14px; }
  .dash-grid > .dash-tile[data-h="1"].flux-card .flux-head { margin-bottom: 0; }
  .dash-grid > .dash-tile[data-h="1"].flux-card .flux-title { font-size: .68rem; }
  .dash-grid > .dash-tile[data-h="1"].flux-card .flux-grid,
  .dash-grid > .dash-tile[data-h="1"].flux-card .flux-footer { display: none; }

  .flux-card {
    padding: 18px 22px;
  }
  .flux-head {
    display: flex; justify-content: space-between; align-items: center;
    margin-bottom: 18px; flex-wrap: wrap; gap: 8px;
  }
  .flux-title {
    font-family: 'Orbitron', monospace;
    font-size: .82rem; letter-spacing: 2px;
    color: var(--amber); text-transform: uppercase;
  }
  .flux-mode {
    font-size: .72rem; color: var(--text2);
    padding: 4px 10px; border-radius: 99px;
    background: var(--bg3); border: 1px solid var(--border);
  }
  .flux-mode.exporting { color: #4ade80; border-color: rgba(74,222,128,.4); }
  .flux-mode.importing { color: #a8c0ff; border-color: rgba(168,192,255,.4); }

  .flux-grid {
    display: grid;
    grid-template-columns: 1fr auto 1fr auto 1fr;
    align-items: center;
    gap: 0; min-height: 180px;
  }
  .flux-node {
    display: flex; flex-direction: column; align-items: center;
    gap: 6px; padding: 14px 10px;
    background: var(--bg3);
    border: 1px solid var(--border);
    border-radius: 14px;
    text-align: center;
  }
  .flux-node-icon {
    width: 44px; height: 44px;
    display: flex; align-items: center; justify-content: center;
  }
  .flux-node-icon svg { width: 38px; height: 38px; }
  .flux-node-label {
    font-size: .7rem; color: var(--text2);
    text-transform: uppercase; letter-spacing: 1.5px;
  }
  .flux-node-value {
    font-family: 'Orbitron', monospace;
    font-size: 1.05rem; font-weight: 700;
    color: var(--text);
  }
  .flux-node-aux {
    font-size: .65rem; color: var(--text2);
    margin-top: 2px;
  }
  .flux-node.solar { color: var(--amber); }
  .flux-node.solar .flux-node-value { color: var(--amber); }
  .flux-node.house { color: #a8c0ff; }
  .flux-node.house .flux-node-value { color: #a8c0ff; }
  .flux-node.grid  { color: var(--text2); }
  /* La couleur du nœud Réseau change selon le sens du flux */
  .flux-node.grid.exporting { color: #4ade80; border-color: rgba(74,222,128,.35); }
  .flux-node.grid.exporting .flux-node-value { color: #4ade80; }
  .flux-node.grid.importing { color: #a8c0ff; border-color: rgba(168,192,255,.35); }
  .flux-node.grid.importing .flux-node-value { color: #a8c0ff; }

  /* Flèches de flux */
  .flux-arrow {
    display: flex; flex-direction: column; align-items: center;
    gap: 5px; padding: 0 12px; min-width: 90px;
  }
  .flux-arrow-label {
    font-size: .6rem; color: var(--text2);
    text-transform: uppercase; letter-spacing: 1px;
  }
  .flux-arrow-line {
    height: 2px; width: 70px;
    border-radius: 99px;
    position: relative;
    background: var(--border);
  }
  .flux-arrow-line::after {
    content: ''; position: absolute; top: -3px; right: -1px;
    width: 0; height: 0;
    border-left: 7px solid currentColor;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    color: var(--border);
  }
  /* Sens inversé (réseau → maison) */
  .flux-arrow-line.reverse::after {
    right: auto; left: -1px;
    border-left: none;
    border-right: 7px solid currentColor;
  }
  .flux-arrow-value {
    font-family: 'Orbitron', monospace;
    font-size: .8rem; font-weight: 700;
    color: var(--text2);
  }

  /* Animations selon l'état */
  .flux-arrow.active .flux-arrow-line {
    animation: fluxPulse 1.5s ease-in-out infinite;
  }
  @keyframes fluxPulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: .35; }
  }
  /* Auto-conso (jaune) */
  .flux-arrow.solar.active .flux-arrow-line {
    background: linear-gradient(90deg, rgba(255,190,50,.25), var(--amber));
    color: var(--amber);
  }
  .flux-arrow.solar.active .flux-arrow-value { color: var(--amber); }
  /* Export (vert) */
  .flux-arrow.exporting .flux-arrow-line {
    background: linear-gradient(90deg, rgba(74,222,128,.25), #4ade80);
    color: #4ade80;
  }
  .flux-arrow.exporting .flux-arrow-value { color: #4ade80; }
  /* Import (bleu) */
  .flux-arrow.importing .flux-arrow-line {
    background: linear-gradient(270deg, rgba(168,192,255,.25), #a8c0ff);
    color: #a8c0ff;
  }
  .flux-arrow.importing .flux-arrow-value { color: #a8c0ff; }

  /* Footer cumulés */
  .flux-footer {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
  }
  .flux-stat {
    display: flex; flex-direction: column; align-items: center;
    gap: 3px; padding: 6px;
  }
  .flux-stat-label {
    font-size: .65rem; color: var(--text2);
    text-transform: uppercase; letter-spacing: 1px;
  }
  .flux-stat-value {
    font-family: 'Orbitron', monospace;
    font-size: .95rem; font-weight: 700;
    color: var(--text);
  }

  /* ═══════════════════════════════════════════════════════════════
     PANNEAU FLUX — RESPONSIVE ADAPTATIF
     ─────────────────────────────────────────────────────────────
     3 modes selon la largeur DU CONTAINER (pas du viewport) :
     - LARGE (≥720px de container) : disposition horizontale
       Solaire | flèche | Maison | flèche | Réseau
     - MEDIUM (450-720px) : version compacte horizontale
       avec icônes réduites et labels courts
     - COMPACT (<450px) : disposition verticale
       Solaire   ↓ flèche   Maison   ↓ flèche   Réseau
     Le flux-card a `container-type: inline-size` pour activer les
     container queries sur sa propre largeur.
  ═══════════════════════════════════════════════════════════════ */
  .flux-card { container-type: inline-size; container-name: fluxc; }

  /* Mode LARGE (par défaut, voir grid 5 cols ci-dessus) — déjà OK */

  /* Mode MEDIUM : 450px ≤ largeur < 720px (tablette portrait, écrans étroits) */
  @container fluxc (max-width: 720px) {
    .flux-grid {
      gap: 4px;
      min-height: 0;
    }
    .flux-node {
      padding: 10px 6px;
      gap: 4px;
    }
    .flux-node-icon { width: 36px; height: 36px; }
    .flux-node-icon svg { width: 30px; height: 30px; }
    .flux-node-label {
      font-size: .58rem;
      letter-spacing: .8px;
    }
    .flux-node-value { font-size: .9rem; }
    .flux-node-aux { font-size: .58rem; }
    .flux-arrow {
      padding: 0 6px;
      min-width: 50px;
    }
    .flux-arrow-line { width: 36px; }
    .flux-arrow-label { font-size: .55rem; letter-spacing: .5px; }
    .flux-arrow-value { font-size: .7rem; }
    .flux-footer {
      grid-template-columns: repeat(2, 1fr);
      gap: 6px;
      margin-top: 12px;
      padding-top: 12px;
    }
    .flux-stat-label { font-size: .55rem; }
    .flux-stat-value { font-size: .82rem; }
  }

  /* Mode COMPACT : largeur < 450px (téléphone, tablette en mode étroit) */
  @container fluxc (max-width: 450px) {
    .flux-grid {
      grid-template-columns: 1fr;
      grid-template-rows: auto auto auto auto auto;
      gap: 6px;
      min-height: 0;
    }
    /* Le node devient horizontal : icône à gauche, infos à droite.
       Comme flux-node-icon/label/value/aux sont des enfants directs,
       on utilise display:grid avec une template qui place l'icône à
       gauche et les 3 textes empilés à droite. */
    .flux-node {
      display: grid;
      grid-template-columns: 38px 1fr;
      grid-template-rows: auto auto auto;
      grid-template-areas:
        "icon label"
        "icon value"
        "icon aux";
      column-gap: 14px;
      row-gap: 1px;
      padding: 10px 14px;
      text-align: left;
      align-items: center;
    }
    .flux-node-icon {
      grid-area: icon;
      width: 38px; height: 38px;
      align-self: center;
    }
    .flux-node-icon svg { width: 32px; height: 32px; }
    .flux-node-label {
      grid-area: label;
      font-size: .62rem;
      align-self: end;
    }
    .flux-node-value {
      grid-area: value;
      font-size: 1.1rem;
      align-self: center;
    }
    .flux-node-aux {
      grid-area: aux;
      font-size: .65rem;
      margin-top: 0;
      align-self: start;
    }

    /* Flèches verticales entre les nœuds */
    .flux-arrow {
      flex-direction: row;
      justify-content: center;
      align-items: center;
      gap: 10px;
      padding: 4px 14px;
      min-width: 0;
    }
    .flux-arrow-line {
      width: 2px;
      height: 24px;
      transform: rotate(0);
    }
    /* Pointe de la flèche : vers le bas par défaut */
    .flux-arrow-line::after {
      top: auto; bottom: -1px; right: -3px;
      border-left: 4px solid transparent;
      border-right: 4px solid transparent;
      border-top: 7px solid currentColor;
      border-bottom: none;
    }
    .flux-arrow-line.reverse::after {
      top: -1px; bottom: auto;
      border-top: none;
      border-bottom: 7px solid currentColor;
    }
    .flux-arrow-label { font-size: .65rem; letter-spacing: .5px; }
    .flux-arrow-value { font-size: .85rem; }

    .flux-footer {
      grid-template-columns: repeat(2, 1fr);
      gap: 8px;
    }
  }

  /* Conserve l'ancien comportement viewport pour les anciens navigateurs
     qui ne supportent pas container queries (rare en 2024 mais bon). */
  @media (max-width: 700px) {
    .flux-grid {
      grid-template-columns: 1fr;
      gap: 8px;
    }
    .flux-arrow {
      flex-direction: row;
      justify-content: center;
      padding: 4px 0;
    }
    .flux-arrow-line {
      width: 2px; height: 30px;
      transform: rotate(0); /* la flèche pointe vers le bas */
    }
    .flux-arrow-line::after {
      top: auto; bottom: -1px; right: -3px;
      border-left: 4px solid transparent;
      border-right: 4px solid transparent;
      border-top: 7px solid currentColor;
      border-bottom: none;
    }
    .flux-arrow-line.reverse::after {
      top: -1px; bottom: auto;
      border-top: none;
      border-bottom: 7px solid currentColor;
    }
    .flux-footer { grid-template-columns: 1fr 1fr; }
  }

  @media (max-width: 600px) {
    .enphase-card-body { flex-direction: column; gap: 12px; }
    .envoy-mini-leds {
      flex-direction: row; flex-wrap: wrap;
      padding-left: 0; padding-top: 12px;
      border-left: none; border-top: 1px solid var(--border);
    }
  }

  .inv-grid {
    display: grid;
    grid-template-columns: repeat(8, 1fr);
    gap: 12px;
    margin-bottom: 20px;
  }
  .inv-card {
    display: flex; flex-direction: column;
    background: var(--bg2);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 16px;
    position: relative; overflow: hidden;
    transition: border-color .2s, transform .15s;
    cursor: default;
  }
  .inv-card:hover { border-color: rgba(255,190,50,.35); transform: translateY(-2px); }
  .inv-card.offline { opacity: .5; }
  .inv-card::before {
    content: ''; position: absolute; inset: 0;
    background: linear-gradient(135deg, rgba(255,190,50,.025) 0%, transparent 60%);
    pointer-events: none;
  }
  .inv-card-head {
    display: flex; justify-content: space-between; align-items: center;
    margin-bottom: 10px;
  }
  .inv-serial {
    font-family: 'Orbitron', monospace;
    font-size: .68rem; font-weight: 700;
    color: var(--amber3); letter-spacing: 1px;
  }
  .inv-status-dot {
    width: 7px; height: 7px; border-radius: 50%;
    flex-shrink: 0;
  }
  .inv-status-dot.online  { background: var(--green); box-shadow: 0 0 6px var(--green); animation: blink 2.5s ease-in-out infinite; }
  .inv-status-dot.offline { background: var(--red);   box-shadow: 0 0 4px var(--red); animation: none; }
  .inv-power {
    font-family: 'Orbitron', monospace;
    font-size: 1.5rem; font-weight: 700;
    color: var(--text); line-height: 1;
    margin-bottom: 2px;
  }
  .inv-power .unit { font-size: .75rem; color: var(--text2); margin-left: 3px; }
  .inv-bar-wrap {
    height: 3px; border-radius: 99px;
    background: rgba(255,255,255,.06);
    overflow: hidden; margin: 8px 0;
  }
  .inv-bar {
    height: 100%; border-radius: 99px;
    background: linear-gradient(90deg, var(--amber2), var(--amber));
    transition: width .8s ease;
  }
  .inv-stats {
    margin-top: auto;
    display: flex; justify-content: space-between;
    font-size: .72rem; color: var(--text2); margin-top: 6px;
  }
  .inv-stats span { display: flex; flex-direction: column; gap: 1px; }
  .inv-stats strong { color: var(--text); font-weight: 600; font-size: .8rem; }



  @media (max-width: 600px) {
    .inv-grid { grid-template-columns: repeat(2, 1fr); }
    .inv-summary-sep { display: none; }
  }

  /* ── INVERTER MINI-LEVELS (dashboard card) ── */
  .inv-levels-wrap {
    margin-top: 14px;
    border-top: 1px solid var(--border);
    padding-top: 12px;
  }
  .inv-levels-title {
    font-size: .68rem; color: var(--text2);
    text-transform: uppercase; letter-spacing: 1.5px;
    margin-bottom: 8px;
    display: flex; justify-content: space-between; align-items: center;
  }
  .inv-levels-title a {
    color: var(--amber); text-decoration: none; font-size: .65rem; letter-spacing: 1px;
    opacity: .7; cursor: pointer;
  }
  .inv-levels-title a:hover { opacity: 1; }
  .inv-level-row {
    display: grid;
    grid-template-columns: 72px 1fr 40px;
    align-items: center; gap: 6px;
    margin-bottom: 5px;
  }
  .inv-level-serial {
    font-family: 'Orbitron', monospace;
    font-size: .6rem; color: var(--amber3);
    letter-spacing: .5px; white-space: nowrap;
  }
  .inv-level-bar-bg {
    height: 5px; border-radius: 99px;
    background: rgba(255,255,255,.06); overflow: hidden;
  }
  .inv-level-bar-fill {
    height: 100%; border-radius: 99px;
    transition: width .8s ease;
  }
  .inv-level-w {
    font-size: .65rem; color: var(--text2);
    text-align: right; white-space: nowrap;
    font-variant-numeric: tabular-nums;
  }
  .inv-level-row.offline .inv-level-serial { opacity: .4; }
  .inv-level-row.offline .inv-level-w      { opacity: .4; }
  .inv-level-missing-dot {
    width: 6px; height: 6px; border-radius: 50%;
    background: var(--red); box-shadow: 0 0 5px var(--red);
    flex-shrink: 0; display: inline-block;
    margin-right: 3px; vertical-align: middle;
  }

  /* ══════════════════════════════════════════════════════════
     NAVIGATION — gérée par JS (applyNavLayout)
     .nav-desktop  → affiché sur bureau (> 900px)
     .nav-mobile   → affiché sur mobile (≤ 900px)
  ══════════════════════════════════════════════════════════ */
  /* Par défaut : nav desktop caché, mobile visible */
  header nav   { display: none; }
  .bottom-nav  { display: block !important; }
  /* Classes ajoutées par JS selon la largeur */
  body.is-desktop header nav  { display: flex; }
  body.is-desktop .bottom-nav { display: none !important; }
  body.is-desktop header      { padding: 0 28px; height: 62px; gap: 24px; }
  body.is-desktop .logo       { font-size: 1.1rem; }
  body.is-desktop .logo-sun   { width: 30px; height: 30px; }
  body.is-mobile  header      { padding: 0 14px; height: 52px; gap: 10px; }
  body.is-mobile  .logo       { font-size: .88rem; }
  body.is-mobile  .logo-sun   { width: 22px; height: 22px; }
  body.is-mobile  .last-update { font-size: .7rem; max-width: 80px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  body.is-mobile  .refresh-btn { padding: 6px 8px; font-size: .78rem; }
  body.is-mobile  main        { margin-top: 52px; height: calc(100vh - 52px - 70px); padding-bottom: 8px; }
  body.is-mobile.header-hidden > main { margin-top: 0; height: calc(100vh - 70px); }

  /* ── Bottom Navigation Bar ── */
  .bottom-nav {
    display: none;
    position: fixed !important;
    bottom: 0 !important;
    left: 0; right: 0;
    z-index: 200;
    background: rgba(9,9,15,.96);
    -webkit-backdrop-filter: blur(18px); /* Samsung Internet / iOS */
    backdrop-filter: blur(18px);
    border-top: 1px solid var(--border);
    padding: 0;
    padding-bottom: env(safe-area-inset-bottom); /* iPhone notch */
    height: calc(58px + env(safe-area-inset-bottom));
    /* Forçage compositing layer GPU : corrige le bug "position:fixed perdu"
       sur Samsung Internet (Galaxy S9+ et antérieurs) et certains Chromium
       anciens où le backdrop-filter casse l'ancrage au viewport. */
    -webkit-transform: translateZ(0);
    transform: translateZ(0);
    will-change: transform;
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
  }
  /* Fallback pour les navigateurs sans backdrop-filter : fond plus opaque
     (sinon la transparence laisse voir le contenu sous la nav). */
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .bottom-nav { background: rgba(9,9,15,.99); }
  }
  .bottom-nav-inner {
    display: flex;
    height: 58px;
  }
  .bnav-btn {
    flex: 1;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px;
    background: none; border: none; cursor: pointer;
    color: var(--text2);
    font-family: 'DM Sans', sans-serif;
    font-size: .62rem; font-weight: 500;
    padding: 6px 2px;
    transition: color .18s;
    -webkit-tap-highlight-color: transparent;
  }
  .bnav-btn svg {
    width: 22px; height: 22px;
    stroke: currentColor; fill: none;
    stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
  }
  .bnav-btn.active {
    color: var(--amber);
  }
  .bnav-btn.active svg {
    filter: drop-shadow(0 0 4px rgba(255,190,50,.5));
  }
  /* bottom-nav affichage géré par JS body.is-mobile / body.is-desktop */

  
  /* ── Hamburger (bureau fenêtré étroit, pointer:fine) ── */
  .hamburger-btn {
    display: none;
    background: none; border: none; cursor: pointer;
    color: var(--text2); padding: 8px; border-radius: 8px;
    transition: all .2s; margin-left: auto;
  }
  .hamburger-btn:hover { color: var(--text); background: var(--bg3); }
  .hamburger-btn svg { width: 22px; height: 22px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; }
  .hamburger-menu {
    display: none; position: absolute; top: 56px; right: 12px;
    background: var(--bg2); border: 1px solid var(--border);
    border-radius: 12px; padding: 6px; z-index: 500;
    box-shadow: 0 8px 32px rgba(0,0,0,.4);
    min-width: 170px;
  }
  .hamburger-menu.open { display: flex; flex-direction: column; gap: 2px; }
  .hamburger-menu .nav-btn {
    text-align: left; padding: 10px 16px; border-radius: 8px; width: 100%;
  }
  /* Hamburger : affiché uniquement sur bureau étroit (géré aussi par JS) */
  body.is-narrow .hamburger-btn { display: flex !important; align-items: center; }
/* Jauge de flux réseau */
.gauge-grid {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}
.grid-gauge-container {
  position: relative;
  margin: 8px 0;
}
.grid-gauge-value {
  font-family: 'Orbitron', monospace;
  font-size: 1.4rem;
  font-weight: 700;
  line-height: 1;
}
.grid-gauge-value .unit {
  font-size: 0.8rem;
  color: var(--text2);
}
.grid-gauge-status {
  font-size: 0.7rem;
  color: var(--text2);
  margin-top: 4px;
  letter-spacing: 1px;
}
/* Version compacte (data-h=1) */
.dash-grid > .dash-tile[data-h="1"].gauge-grid .grid-gauge-container canvas {
  width: 100px !important;
  height: 70px !important;
}
.dash-grid > .dash-tile[data-h="1"].gauge-grid .grid-gauge-value {
  font-size: 1rem;
}
.dash-grid > .dash-tile[data-h="1"].gauge-grid .grid-gauge-status {
  font-size: 0.6rem;
}

/* ═══════════════════════════════════════════════════════════════
   VUE ANALYTIQUE — agencement à 2 colonnes
   (alternative à la grille de tuiles classique)
   ═══════════════════════════════════════════════════════════════ */
.analytics-grid {
  /* Layout 2 colonnes : graphiques étirables à gauche, sidebar fixe à droite.
     Le parent `main` est déjà en height: calc(100vh - 62px) + overflow: hidden,
     donc on prend simplement 100% de la hauteur dispo. */
  display: grid;
  grid-template-columns: minmax(0, 1fr) 290px;
  gap: 12px;
  margin-top: 4px;
  height: 100%;
  min-height: 0;
  overflow: hidden;
}
/* Le dashboard.css impose padding 20/28 sur main → faut compenser pour notre vue */
#dash-analytics-view {
  height: calc(100% - 4px);
  min-height: 0;
}
@media (max-width: 980px) {
  .analytics-grid {
    grid-template-columns: 1fr;
    height: auto;
    overflow: visible;
  }
  #dash-analytics-view {
    height: auto;
    overflow-y: auto;
  }
}

.analytics-main {
  display: grid;
  /* Les deux graphiques occupent la hauteur disponible à parts égales */
  grid-template-rows: 1fr 1fr;
  gap: 12px;
  align-content: stretch;
  min-height: 0;
}
.analytics-side {
  display: grid;
  /* La tuile flux (diagramme) est plus grande que les 3 jauges qui suivent.
     Ratio : flux ~ 2.2 fois la taille d'une jauge. */
  grid-template-rows: 2.2fr 1fr 1fr 1fr;
  gap: 10px;
  align-content: stretch;
  min-height: 0;
}

.analytics-card {
  padding: 12px 14px;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.analytics-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
  flex-wrap: wrap;
  flex-shrink: 0;
}
.analytics-subtitle {
  font-size: .85rem;
  color: var(--amber);
  font-family: 'Orbitron', monospace;
  font-weight: 600;
}
.analytics-legend {
  font-size: .7rem;
  color: var(--text2);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}
.legend-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 5px;
  vertical-align: middle;
}
.analytics-chart-wrap {
  position: relative;
  flex: 1 1 0;
  min-height: 0;
}
@media (max-width: 980px) {
  /* Sur petit écran, on revient à des hauteurs fixes (sans flex-grow viewport) */
  .analytics-chart-wrap { height: 220px; flex: 0 0 220px; }
}
@media (max-width: 600px) {
  .analytics-chart-wrap { height: 180px; flex: 0 0 180px; }
}

/* ── Distribution d'énergie : schéma de flux SVG (T-Junction) ─────── */
.analytics-flux-card {
  padding: 10px 12px 10px;
}
.flux-diagram-wrap {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.flux-diagram-svg {
  width: 100%;
  height: 100%;
  max-height: 100%;
  display: block;
}

/* ── Segments : affichage conditionnel (mode "actif" → 100%, inactif → caché) ── */
#flxSegSolar, #flxSegToGrid, #flxSegToHome {
  transition: opacity .3s;
}
.flx-inactive { opacity: 0; }

/* ── Particules animées : 2 par segment qui glissent en boucle ──────
   Animation via offset-path (moderne, fluide) avec fallback transform.
   Chaque particule suit son segment avec un décalage temporel pour donner
   l'illusion d'un convoyeur. Cycle 2s pour vitesse moyenne. */
.flx-particle {
  /* Position de départ hors écran si pas d'animation */
  opacity: 0;
}

/* Segment Solaire → Jonction (vertical descendant) */
.flx-particle-solar {
  offset-path: path('M 160 102 L 160 175');
  animation: flxFlow 2s linear infinite;
}
.flx-particle-solar2 {
  offset-path: path('M 160 102 L 160 175');
  animation: flxFlow 2s linear infinite;
  animation-delay: -1s;
}

/* Segment Jonction → Réseau (courbe gauche) */
.flx-particle-grid {
  offset-path: path('M 160 175 Q 160 215 102 215');
  animation: flxFlow 2s linear infinite;
}
.flx-particle-grid2 {
  offset-path: path('M 160 175 Q 160 215 102 215');
  animation: flxFlow 2s linear infinite;
  animation-delay: -1s;
}

/* Segment Jonction → Maison (courbe droite) */
.flx-particle-home {
  offset-path: path('M 160 175 Q 160 215 218 215');
  animation: flxFlow 2s linear infinite;
}
.flx-particle-home2 {
  offset-path: path('M 160 175 Q 160 215 218 215');
  animation: flxFlow 2s linear infinite;
  animation-delay: -1s;
}

/* Segment Réseau ↔ Maison (ligne DROITE, sous les cercles, proche) */
.flx-particle-gridhome {
  offset-path: path('M 102 240 L 218 240');
  animation: flxFlow 2s linear infinite;
}
.flx-particle-gridhome2 {
  offset-path: path('M 102 240 L 218 240');
  animation: flxFlow 2s linear infinite;
  animation-delay: -1s;
}

@keyframes flxFlow {
  0%   { offset-distance: 0%;   opacity: 0; }
  10%  { opacity: 1; }
  90%  { opacity: 1; }
  100% { offset-distance: 100%; opacity: 0; }
}

/* Particule sur un segment inactif : masquée */
.flx-particle.flx-inactive {
  animation-play-state: paused;
  opacity: 0 !important;
}

/* ── Jauges circulaires (Chart.js doughnut) ──────────────────────── */
.analytics-gauge-card {
  text-align: center;
  padding: 8px 10px 8px;
  /* La carte remplit la cellule de la grille (grid-template-rows: 1fr).
     Flex column pour que la jauge prenne l'espace restant après le titre. */
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}
.gauge-title {
  font-size: .68rem;
  color: var(--text2);
  text-transform: uppercase;
  letter-spacing: .05em;
  margin-bottom: 4px;
  flex-shrink: 0;
}
.analytics-gauge-wrap {
  position: relative;
  /* La jauge prend toute la hauteur restante dans la carte, et SA HAUTEUR
     pilote sa largeur (pas l'inverse). Width auto + max-width borne
     supérieure pour éviter qu'elle devienne trop large sur écran XXL. */
  flex: 1 1 0;
  min-height: 0;
  width: auto;
  max-width: 100%;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Le canvas Chart.js prend la taille de son parent — on contraint ici. */
.analytics-gauge-wrap > canvas {
  max-width: 100% !important;
  max-height: 100% !important;
  width: auto !important;
  height: 100% !important;
}
.gauge-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Orbitron', monospace;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}

/* ═══════════════════════════════════════════════════════════════
   PREVIEW CARDS — choix de présentation (Réglages → Présentation)
   ═══════════════════════════════════════════════════════════════ */
.preview-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 14px;
  margin-top: 12px;
}
.preview-card {
  display: block;
  cursor: pointer;
  position: relative;
}
.preview-card > input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.preview-card-inner {
  border: 2px solid var(--border);
  border-radius: var(--card-r);
  padding: 12px;
  background: var(--bg2);
  transition: border-color .15s, background .15s;
}
.preview-card:hover .preview-card-inner {
  border-color: rgba(255,190,50,.35);
}
.preview-card > input[type="radio"]:checked + .preview-card-inner {
  border-color: var(--amber);
  background: rgba(255,190,50,.04);
  box-shadow: 0 0 0 3px rgba(255,190,50,.08);
}
.preview-card-meta {
  margin-top: 10px;
}
.preview-card-title {
  font-weight: 600;
  font-size: .95rem;
  margin-bottom: 3px;
}
.preview-card-desc {
  font-size: .78rem;
  color: var(--text2);
  line-height: 1.4;
}

/* ── Mockup mini : grille classique ──────────────────────────────── */
.preview-mockup {
  height: 130px;
  border-radius: 8px;
  background: var(--bg);
  border: 1px solid var(--border);
  padding: 8px;
  display: grid;
  gap: 4px;
}
.preview-mockup-classic {
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 22px;
}
.mock-tile {
  background: rgba(255,190,50,.18);
  border-radius: 4px;
}
.mock-tile-hero { grid-column: span 3; grid-row: span 2; background: rgba(255,190,50,.32); }
.mock-tile-wide { grid-column: span 2; }

/* ── Mockup mini : vue analytique ────────────────────────────────── */
.preview-mockup-analytics {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 6px;
  padding: 8px;
}
.mock-analytics-main { display: grid; grid-template-rows: 1fr 1fr; gap: 4px; }
.mock-analytics-side { display: grid; grid-template-rows: 1.4fr 1fr 1fr 1fr; gap: 4px; }
.mock-bars {
  background: linear-gradient(to top, rgba(79,195,247,.2) 30%, rgba(255,190,50,.4) 30% 70%, rgba(167,139,250,.3) 70%);
  border-radius: 4px;
  position: relative;
}
.mock-bars::after {
  content: "";
  position: absolute;
  left: 4px; right: 4px; bottom: 3px;
  height: 6px;
  background: repeating-linear-gradient(90deg,
    transparent 0 3px,
    rgba(255,255,255,.15) 3px 6px);
}
.mock-bars-prod { background: linear-gradient(to top, rgba(255,190,50,.45), rgba(255,190,50,.15)); }
.mock-flux { background: rgba(255,190,50,.15); border-radius: 4px; }
.mock-gauge {
  background: radial-gradient(circle at 50% 65%,
    rgba(61,220,132,.3) 0 30%,
    transparent 32%);
  border-radius: 4px;
}

/* ═══════════════════════════════════════════════════════════════
   TACHYMÈTRE — Puissance instantanée du réseau (vue analytique)
   Échelle asymétrique : gauche = revente (max = production crête),
   droite = achat (max = capacité compteur).
   ═══════════════════════════════════════════════════════════════ */
/* ═══════════════════════════════════════════════════════════════
   JAUGE NET GRID — Consommation nette du réseau (vue analytique)
   Demi-cercle avec gradient + marqueur qui glisse le long de l'arc.
   ═══════════════════════════════════════════════════════════════ */
.analytics-netgrid-card .netgrid-wrap {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 0;
  overflow: hidden;
  position: relative;
  gap: 2px;
}
.netgrid-svg {
  flex: 1 1 0;
  min-height: 0;
  width: auto;
  max-width: 100%;
  height: auto;
  display: block;
}
.netgrid-value {
  font-family: 'Orbitron', monospace;
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--text);
  letter-spacing: -0.01em;
  text-align: center;
  margin-top: -10px; /* remonte un peu sous l'arc */
}
/* Animation du marqueur : transition douce des coordonnées quand la valeur change */
#netGridMarkerHead, #netGridMarkerStem {
  transition: cx 480ms cubic-bezier(.4, 1.3, .5, 1),
              cy 480ms cubic-bezier(.4, 1.3, .5, 1),
              x1 480ms cubic-bezier(.4, 1.3, .5, 1),
              y1 480ms cubic-bezier(.4, 1.3, .5, 1),
              x2 480ms cubic-bezier(.4, 1.3, .5, 1),
              y2 480ms cubic-bezier(.4, 1.3, .5, 1);
  will-change: cx, cy;
}
.tacho-value {
  /* Hérité — tachymètre supprimé. Style conservé au cas où une autre vue
     l'utilise encore. */
  margin-top: 2px;
  text-align: center;
  font-family: 'Orbitron', monospace;
  font-weight: 700;
  font-size: .95rem;
  letter-spacing: -0.01em;
  line-height: 1.1;
}

/* ═══════════════════════════════════════════════════════════════
   APERÇUS DES PROFILS PRÉDÉFINIS (Réglages → Layout par appareil)
   Chaque bouton de profil devient une carte cliquable avec mini-mockup
   SVG montrant l'arrangement des tuiles.
   ═══════════════════════════════════════════════════════════════ */
.preset-row-buttons {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
@media (max-width: 720px) {
  .preset-row-buttons { grid-template-columns: 1fr; }
}
.preset-btn {
  display: flex !important;
  flex-direction: column;
  align-items: stretch !important;
  gap: 6px;
  padding: 10px !important;
  background: var(--bg2) !important;
  border: 2px solid var(--border) !important;
  border-radius: 10px !important;
  cursor: pointer;
  transition: border-color .15s, background .15s, transform .1s;
  text-align: left !important;
  height: auto !important;
}
.preset-btn:hover {
  border-color: rgba(255,190,50,.4) !important;
  background: rgba(255,190,50,.04) !important;
}
.preset-btn.active,
.preset-btn[data-active="1"] {
  border-color: var(--amber) !important;
  background: rgba(255,190,50,.08) !important;
}
.preset-btn-name {
  font-weight: 600;
  font-size: .82rem;
  color: var(--text);
  margin: 0;
}
.preset-btn-desc {
  display: block !important;
  font-size: .68rem !important;
  font-weight: 400 !important;
  color: var(--text2) !important;
  line-height: 1.3;
  margin-top: 0 !important;
}
.preset-mini-preview {
  width: 100%;
  height: 70px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  display: grid;
  gap: 2px;
  padding: 4px;
  grid-template-columns: repeat(12, 1fr);
  grid-auto-rows: minmax(4px, 1fr);
  align-content: start;
  overflow: hidden;
}
.preset-mini-tile {
  background: rgba(255,190,50,.22);
  border-radius: 2px;
}
.preset-mini-tile.hero    { background: rgba(255,190,50,.45); }
.preset-mini-tile.chart   { background: rgba(79,195,247,.35); }
.preset-mini-tile.gauge   { background: rgba(167,139,250,.35); }
.preset-mini-tile.hidden  { display: none; }
