/* lcf-gate — feuille unique, servie en fichier (la CSP interdit l'inline).
   Grammaire reprise de darkvalley.fr : aurore, verre, pastilles, DM Sans 300. */

@font-face{font-family:'DM Sans';font-style:normal;font-weight:200 600;font-display:swap;
  src:url(fonts/DMSans-latin.woff2) format('woff2')}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:300 500;font-display:swap;
  src:url(fonts/JetBrainsMono-latin.woff2) format('woff2')}

:root{
  --mint:#B5D4C8;--gold-l:#e8cd6a;
  --st-open:#7BD8A4;   /* ouvert       */
  --st-shut:#F2645A;   /* fermé        */
  --st-move:#FF8A2B;   /* en mouvement */
  --sans:'DM Sans',system-ui,sans-serif;
  --mono:'JetBrains Mono',monospace;
}
*{box-sizing:border-box;margin:0;padding:0}
[hidden]{display:none !important}
body{background:#0a1810;color:#fff;font-family:var(--sans);font-size:15px;line-height:1.6;
  -webkit-font-smoothing:antialiased;overflow-x:hidden}

/* Aurore figée : cinq halos peints sur le fond, aucun élément, aucun blur,
   aucune animation. Le MCU de la voiture ne recalcule rien après le 1er rendu. */
/* La 1re couche est un voile sombre en composition normale : sans lui, les cinq
   halos en `screen` s'additionnent et lavent tout l'écran. Le défaut ne se voit
   qu'au format large et court de l'écran voiture, où `vmax` rend les dégradés
   énormes par rapport à la hauteur et où seuls leurs cœurs restent visibles. */
.stage{position:relative;min-height:100dvh;overflow:hidden;display:flex;
  background-color:#0a1810;
  background-image:
    linear-gradient(rgba(8,19,14,.46),rgba(8,19,14,.46)),
    radial-gradient(58vmax 58vmax at 88% -12%,rgba(60,220,170,.62) 0%,rgba(30,160,120,.30) 34%,transparent 63%),
    radial-gradient(46vmax 46vmax at 54% 4%,rgba(155,238,115,.46) 0%,rgba(90,190,70,.24) 38%,transparent 66%),
    radial-gradient(52vmax 52vmax at 2% -10%,rgba(70,90,230,.42) 0%,rgba(30,50,160,.15) 44%,transparent 69%),
    radial-gradient(40vmax 40vmax at 84% 106%,rgba(235,200,75,.52) 0%,rgba(160,120,20,.18) 44%,transparent 68%),
    radial-gradient(34vmax 34vmax at 0% 38%,rgba(50,140,110,.36) 0%,rgba(30,90,70,.10) 44%,transparent 57%);
  background-blend-mode:normal,screen,screen,screen,screen,screen;background-repeat:no-repeat}
.vignette{position:absolute;left:-20%;bottom:-10%;width:140vw;height:88vh;pointer-events:none;
  background:radial-gradient(ellipse at 50% 100%,rgba(0,0,0,.98) 0%,rgba(0,0,0,.88) 28%,rgba(0,0,0,.45) 55%,transparent 80%)}
.noise{position:absolute;inset:0;opacity:.05;pointer-events:none;background-size:180px;
  background-image:url(noise.svg)}

.app{position:relative;z-index:3;flex:1;display:flex;flex-direction:column;
  gap:clamp(12px,1.8vh,22px);padding:clamp(16px,2.4vh,26px) clamp(20px,3vw,48px) clamp(14px,2vh,22px);
  max-width:1520px;margin:0 auto;width:100%}

/* ── entête ── */
.top{display:flex;align-items:center;justify-content:space-between;gap:16px}
.brand{display:flex;align-items:center;gap:14px;background:rgba(255,255,255,.15);
  border:1px solid rgba(255,255,255,.18);border-radius:999px;padding:6px 22px 6px 8px}
.brand-logo{height:clamp(30px,3vw,40px);width:auto;display:block}
.brand-txt{font-family:var(--mono);font-size:clamp(10px,.85vw,11.5px);font-weight:500;
  letter-spacing:.16em;text-transform:uppercase;color:rgba(255,255,255,.82);white-space:nowrap}
.hdr-right{display:flex;align-items:center;gap:8px}
.pill{display:inline-flex;align-items:center;gap:9px;height:42px;padding:0 20px;border-radius:999px;
  background:rgba(255,255,255,.13);border:1px solid rgba(255,255,255,.15);
  font-family:var(--mono);font-size:11px;font-weight:500;letter-spacing:.1em;
  text-transform:uppercase;color:rgba(255,255,255,.8);white-space:nowrap}
.pill--time{font-size:15px;letter-spacing:.04em;color:#fff;font-variant-numeric:tabular-nums}
.dot{width:7px;height:7px;border-radius:50%;background:var(--mint);flex-shrink:0;
  box-shadow:0 0 0 0 rgba(181,212,200,.5);animation:pulse 2.6s ease-out infinite}
/* La liaison tombée doit se voir : la pastille passe au rouge et cesse de battre. */
.pill[data-link="down"] .dot{background:var(--st-shut);animation:none}
.pill[data-link="down"]{border-color:rgba(242,100,90,.5)}
@keyframes pulse{0%{box-shadow:0 0 0 0 rgba(181,212,200,.45)}70%,100%{box-shadow:0 0 0 10px rgba(181,212,200,0)}}

/* ── titre + relevés ── */
.lede{display:flex;align-items:flex-end;justify-content:space-between;gap:24px;flex-wrap:wrap}
.meta{font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
  color:rgba(255,255,255,.45);margin-bottom:10px}
.hero-h{font-weight:300;font-size:clamp(30px,3.6vw,52px);line-height:.94;letter-spacing:-.03em}
.hero-h em{font-style:normal;font-weight:300;color:var(--mint);letter-spacing:-.04em}

.telem{display:flex;align-items:flex-end;gap:clamp(16px,2.2vw,34px)}
.tel{display:flex;flex-direction:column;gap:7px;text-align:right}
.tel+.tel{padding-left:clamp(16px,2.2vw,34px);border-left:1px solid rgba(255,255,255,.14)}
.tel__k{font-family:var(--mono);font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;
  color:rgba(255,255,255,.45);white-space:nowrap}
.tel__v{display:flex;align-items:baseline;justify-content:flex-end;gap:7px;font-weight:300;
  font-size:clamp(23px,2.5vw,36px);line-height:1;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;white-space:nowrap}
.tel__v--sm{font-size:clamp(17px,1.8vw,25px)}
.tel__u{font-family:var(--mono);font-size:10.5px;font-weight:400;letter-spacing:.12em;
  text-transform:uppercase;color:rgba(255,255,255,.5)}
.tel[data-stale="1"] .tel__v{color:var(--gold-l)}
.tel[data-stale="1"] .tel__u{color:rgba(235,200,75,.7)}

/* ── cartes ouvrants ── */
.grid{flex:1;display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(12px,1.4vw,18px);min-height:0}
.card{position:relative;overflow:hidden;border-radius:14px;background:rgba(255,255,255,.11);
  border:1px solid rgba(255,255,255,.18);display:flex;flex-direction:column;
  align-items:flex-start;justify-content:flex-end;gap:clamp(5px,.8vh,9px);
  padding:clamp(18px,2.6vh,30px) clamp(18px,1.7vw,26px);min-height:clamp(170px,31vh,320px);
  color:#fff;font-family:inherit;text-align:left;cursor:pointer;
  user-select:none;-webkit-user-select:none;-webkit-touch-callout:none;
  touch-action:manipulation;transition:background .3s,border-color .3s;
  --st:rgba(255,255,255,.4)}
/* Tactile : pas de :hover, il reste collé après le tap. */
.card:active{background:rgba(255,255,255,.16)}
.card:focus-visible{outline:2px solid #fff;outline-offset:3px}
.card.is-arming{border-color:rgba(255,138,43,.75)}
.card[data-state="closed"]{--st:var(--st-shut)}
.card[data-state="open"]{--st:var(--st-open)}
.card[data-state="opening"],.card[data-state="closing"]{--st:var(--st-move);cursor:default}
.card.is-arming{--st:var(--st-move)}
.card::after{content:"";position:absolute;left:0;right:0;bottom:0;height:4px;z-index:2;
  background:var(--st);transition:background .3s}
.card[data-state="opening"]::after,.card[data-state="closing"]::after,
.card[data-state="opening"] .state::before,.card[data-state="closing"] .state::before{
  animation:blink 1s steps(2,start) infinite}
@keyframes blink{50%{opacity:.25}}

.fill{position:absolute;left:0;right:0;bottom:0;height:0;z-index:0;opacity:0;pointer-events:none;
  mix-blend-mode:screen;transition:opacity .12s ease;
  background:linear-gradient(to top,rgba(255,138,43,.85) 0%,rgba(255,138,43,.32) 45%,transparent 100%)}
.card.is-arming .fill{opacity:1}

.ico,.name,.state,.hint{position:relative;z-index:1}
.ico{width:clamp(32px,3vw,44px);height:clamp(32px,3vw,44px);color:var(--st);opacity:.8;
  margin-bottom:auto;transition:color .3s}
.name{font-weight:300;font-size:clamp(20px,2.1vw,32px);line-height:1.02;letter-spacing:-.02em}
.state{font-family:var(--mono);font-size:clamp(10px,.92vw,12px);font-weight:500;letter-spacing:.18em;
  text-transform:uppercase;color:var(--st);display:flex;align-items:center;gap:9px;transition:color .3s}
.state::before{content:"";width:8px;height:8px;border-radius:50%;background:currentColor;flex-shrink:0}
.hint{font-family:var(--mono);font-size:9.5px;letter-spacing:.15em;text-transform:uppercase;
  color:rgba(255,255,255,.34)}

/* ── rail bas : modules utilitaires ──
   Classe d'interaction distincte des ouvrants : réversible et instantané, donc
   simple tap, aucun maintien. Et pas de rouge/vert d'état physique ici : ces
   couleurs disent « où en est un ouvrant », elles ne doivent rien dire d'autre. */
.util{display:grid;grid-template-columns:1fr 1fr 1.55fr;gap:clamp(10px,1.2vw,16px)}
.mod{display:flex;align-items:center;gap:clamp(10px,1.1vw,15px);
  height:clamp(56px,7.2vh,70px);padding:0 14px 0 20px;border-radius:999px;
  background:rgba(255,255,255,.11);border:1px solid rgba(255,255,255,.2);
  color:#fff;font-family:inherit;text-align:left;cursor:pointer;
  user-select:none;-webkit-user-select:none;touch-action:manipulation;
  transition:background .3s,border-color .3s}
button.mod:active{background:rgba(255,255,255,.20);border-color:rgba(255,255,255,.42)}
.mod:focus-visible{outline:2px solid #fff;outline-offset:3px}
.mod--therm{cursor:default;padding-right:10px}
.mod__ico{width:clamp(20px,1.9vw,25px);height:clamp(20px,1.9vw,25px);flex-shrink:0;
  color:rgba(255,255,255,.55);transition:color .3s}
.mod__body{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.mod__name{font-size:clamp(13px,1.15vw,15px);font-weight:500;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.mod__sub{font-family:var(--mono);font-size:9.5px;font-weight:500;letter-spacing:.16em;
  text-transform:uppercase;color:rgba(255,255,255,.5);white-space:nowrap}

/* consigne du thermostat */
.step{display:flex;align-items:center;gap:clamp(5px,.6vw,9px);flex-shrink:0}
.step__b{width:clamp(38px,4.6vh,46px);height:clamp(38px,4.6vh,46px);border-radius:50%;
  border:1px solid rgba(255,255,255,.24);background:rgba(255,255,255,.09);color:#fff;
  font-family:var(--sans);font-weight:300;font-size:clamp(19px,2.2vh,24px);line-height:1;
  cursor:pointer;touch-action:manipulation;transition:background .2s,border-color .2s}
.step__b:active{background:rgba(255,255,255,.24);border-color:rgba(255,255,255,.5)}
.step__b:focus-visible{outline:2px solid #fff;outline-offset:2px}
.step__b[disabled]{opacity:.3;cursor:default}
.step__v{min-width:clamp(54px,5vw,70px);text-align:center;font-weight:300;
  font-size:clamp(18px,1.8vw,25px);letter-spacing:-.02em;font-variant-numeric:tabular-nums}

/* interrupteur */
.sw{width:52px;height:30px;border-radius:999px;background:rgba(255,255,255,.12);
  border:1px solid rgba(255,255,255,.25);position:relative;flex-shrink:0;
  transition:background .25s,border-color .25s}
.sw::after{content:"";position:absolute;top:3px;left:3px;width:22px;height:22px;border-radius:50%;
  background:rgba(255,255,255,.72);transition:transform .25s cubic-bezier(.3,.7,.3,1),background .25s}
.sw--btn{padding:0;cursor:pointer}
.sw--btn:focus-visible{outline:2px solid #fff;outline-offset:3px}

.mod[aria-pressed="true"],.mod--therm[data-on="1"]{
  border-color:rgba(181,212,200,.6);background:rgba(181,212,200,.14)}
.mod[aria-pressed="true"] .mod__ico,.mod[aria-pressed="true"] .mod__sub,
.mod--therm[data-on="1"] .mod__ico,.mod--therm[data-on="1"] .mod__sub{color:var(--mint)}
.mod[aria-pressed="true"] .sw,.sw--btn[aria-pressed="true"]{
  background:rgba(181,212,200,.35);border-color:rgba(181,212,200,.6)}
.mod[aria-pressed="true"] .sw::after,.sw--btn[aria-pressed="true"]::after{
  transform:translateX(22px);background:var(--mint)}

/* ── page de code ── */
/* `flex:1` est indispensable : .stage est un conteneur flex, sans quoi .gate
   ne prend que la largeur de son contenu et le pavé reste collé à gauche. */
.gate{flex:1;min-height:100dvh;display:flex;align-items:center;justify-content:center}
.gate__box{display:flex;flex-direction:column;align-items:center;gap:clamp(13px,2.1vh,24px)}
.gate__logo{height:clamp(30px,3.4vh,42px);width:auto;opacity:.9}
.gate__k{font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
  color:rgba(255,255,255,.5);text-align:center;min-height:1.6em}
.gate__k[data-err="1"]{color:var(--st-shut)}
.gate__dots{display:flex;gap:13px}
.gate__d{width:13px;height:13px;border-radius:50%;border:1px solid rgba(255,255,255,.38);
  transition:background .15s,border-color .15s}
.gate__d[data-on="1"]{background:var(--mint);border-color:var(--mint)}
.pad{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(9px,1.3vh,15px)}
.pad button{width:clamp(60px,7vh,82px);height:clamp(60px,7vh,82px);border-radius:999px;
  border:1px solid rgba(255,255,255,.22);background:rgba(255,255,255,.11);color:#fff;
  font-family:var(--sans);font-weight:300;font-size:clamp(21px,2.5vh,29px);cursor:pointer;
  font-variant-numeric:tabular-nums;transition:background .2s,border-color .2s}
.pad button:active{background:rgba(255,255,255,.24);border-color:rgba(255,255,255,.5)}
.pad button:focus-visible{outline:2px solid #fff;outline-offset:3px}
.pad .fn{font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  color:rgba(255,255,255,.6)}

@media (max-width:860px){
  .grid{grid-template-columns:1fr}
  .card{min-height:118px;flex-direction:row;align-items:center;gap:16px;flex-wrap:wrap}
  .ico{margin-bottom:0}
  .name{flex:1;min-width:130px}
  .util{grid-template-columns:1fr}
  .mod--therm{flex-wrap:wrap;height:auto;padding:14px 18px;border-radius:18px}
  .telem{width:100%;justify-content:flex-start}
  .tel{text-align:left}
  .tel__v{justify-content:flex-start}
}
@media (prefers-reduced-motion:reduce){
  .dot{animation:none}
  .card::after,.state::before{animation:none !important}
  .card,.lamp,.sw::after{transition:none}
}
