/* ================================================================
   Tokens — color palette (light + dark), shadows
   ================================================================ */
:root{
  --bg:#F7F6F5;
  --surface:#FFFFFF;
  --surface-sunken:#F1EFEE;
  --border:#E7E3E2;
  --border-strong:#D8D3D2;
  --text:#1C1A1B;
  --text-dim:#605A5C;
  --text-faint:#8B8689;
  --accent:#E8547C;
  --accent-soft:#FCE6EC;
  --accent-ring:#F3A9BE;
  --ok:#3FA66B;
  --ok-soft:#E4F3EA;
  --warn:#D68A2B;
  --warn-soft:#FBF0E0;
  --danger:#D64545;
  --danger-soft:#FBE7E7;
  --shadow-card: 0 1px 2px rgba(28,26,27,0.04), 0 1px 1px rgba(28,26,27,0.03);
  --shadow-pop: 0 12px 32px rgba(28,26,27,0.14), 0 2px 8px rgba(28,26,27,0.06);
}

@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --bg:#171515;
    --surface:#211E1F;
    --surface-sunken:#1B1919;
    --border:#332F30;
    --border-strong:#433E3F;
    --text:#F3F1F0;
    --text-dim:#B8B2B3;
    --text-faint:#847E7F;
    --accent:#F0729A;
    --accent-soft:#3A2530;
    --accent-ring:#6B3A4A;
    --ok:#57C687;
    --ok-soft:#1E3327;
    --warn:#E4A44F;
    --warn-soft:#3A2D18;
    --danger:#E76A6A;
    --danger-soft:#3A2020;
    --shadow-card: 0 1px 2px rgba(0,0,0,0.3), 0 1px 1px rgba(0,0,0,0.2);
    --shadow-pop: 0 12px 32px rgba(0,0,0,0.45), 0 2px 8px rgba(0,0,0,0.3);
  }
}
:root[data-theme="dark"]{
  --bg:#171515;
  --surface:#211E1F;
  --surface-sunken:#1B1919;
  --border:#332F30;
  --border-strong:#433E3F;
  --text:#F3F1F0;
  --text-dim:#B8B2B3;
  --text-faint:#847E7F;
  --accent:#F0729A;
  --accent-soft:#3A2530;
  --accent-ring:#6B3A4A;
  --ok:#57C687;
  --ok-soft:#1E3327;
  --warn:#E4A44F;
  --warn-soft:#3A2D18;
  --danger:#E76A6A;
  --danger-soft:#3A2020;
  --shadow-card: 0 1px 2px rgba(0,0,0,0.3), 0 1px 1px rgba(0,0,0,0.2);
  --shadow-pop: 0 12px 32px rgba(0,0,0,0.45), 0 2px 8px rgba(0,0,0,0.3);
}

/* ================================================================
   Base — reset, typography, layout shell, generic components
   ================================================================ */
*{box-sizing:border-box;}
html{color-scheme:light dark;}
html,body{
  /* Safety net: nothing in the page should ever need to scroll sideways —
     any element that overflows its container (e.g. a wide table) must
     scroll inside its own overflow-x:auto wrapper instead. This just
     guarantees a stray overflow never drags the whole page along with it
     on mobile. */
  overflow-x:hidden;
  max-width:100%;
}
body{
  margin:0;
  background:var(--bg);
  color:var(--text);
  font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;
  -webkit-font-smoothing:antialiased;
}
img{max-width:100%;}
[hidden]{display:none!important;}

h1,h2,h3{font-family:Georgia,'Palatino Linotype','Iowan Old Style',serif;text-wrap:balance;margin:0;color:inherit;}
.mono{font-family:ui-monospace,'SF Mono','Cascadia Mono',Menlo,Consolas,monospace;font-variant-numeric:tabular-nums;}
button{font-family:inherit;color:inherit;}
a{color:inherit;text-decoration:none;}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;}

.app{
  max-width:1280px;
  margin:0 auto;
  padding:0 32px 80px;
}
@media (max-width:640px){
  .app{padding:0 16px 56px;}
}

.icon-btn{
  width:30px;height:30px;border-radius:7px;
  border:1px solid transparent;
  background:none;
  color:var(--text-faint);
  cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
}
.icon-btn svg{width:15px;height:15px;}
.icon-btn:hover{background:var(--surface-sunken);color:var(--text);}
.icon-btn.danger:hover{background:var(--danger-soft);color:var(--danger);}

/* ================================================================
   Topbar
   ================================================================ */
.topbar{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:24px;
  padding:26px 32px;
  max-width:1280px;
  margin:0 auto;
  border-bottom:1px solid var(--border);
}
.topbar-left{display:flex;align-items:center;gap:14px;}
.brand{
  display:flex;
  align-items:center;
  gap:10px;
  background:none;
  border:none;
  padding:0;
  margin:0;
  cursor:pointer;
  border-radius:8px;
  transition:opacity .15s ease;
}
.brand:hover{opacity:.75;}
.brand:active{opacity:.6;}
.brand .mark{
  width:28px;height:28px;
  border-radius:7px;
  background:var(--accent);
  display:inline-flex;align-items:center;justify-content:center;
  color:#fff;
  font-family:Georgia,serif;
  font-weight:600;
  font-size:15px;
  flex:none;
}
.brand h1{font-size:21px;font-weight:600;letter-spacing:-0.01em;display:flex;align-items:center;gap:12px;}
.brand-sep{width:1px;height:18px;background:var(--border-strong);flex:none;}
.brand-sub{font-size:15px;font-weight:500;color:var(--text-faint);}
.topbar-right{display:flex;align-items:center;gap:18px;}
.clock{font-size:12.5px;color:var(--text-faint);}

@media (max-width:640px){
  .topbar{padding:18px 16px;}
  .brand h1{font-size:18px;}
}

/* ================================================================
   Overview — salon list
   ================================================================ */
.overview-head{
  padding:44px 0 28px;
  display:flex;
  align-items:flex-end;
  justify-content:space-between;
  gap:24px;
  flex-wrap:wrap;
}
.overview-head h2{font-size:32px;font-weight:500;}
.overview-head p{margin:8px 0 0;color:var(--text-dim);font-size:14.5px;max-width:46ch;}
.summary-strip{
  display:flex;
  gap:28px;
  font-size:13px;
}
.summary-strip .stat{display:flex;flex-direction:column;gap:2px;align-items:flex-end;}
.summary-strip .stat .n{font-family:ui-monospace,'SF Mono','Cascadia Mono',Menlo,Consolas,monospace;font-size:20px;font-weight:500;color:var(--text);}
.summary-strip .stat .l{color:var(--text-faint);font-size:11.5px;text-transform:uppercase;letter-spacing:0.05em;}

.salon-list{
  display:flex;
  flex-direction:column;
  border-top:1px solid var(--border);
}

.salon-row{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:20px;
  width:100%;
  padding:20px 4px;
  background:none;
  border:none;
  border-bottom:1px solid var(--border);
  cursor:pointer;
  text-align:left;
  font-family:inherit;
  transition:padding-left .15s ease, background .15s ease;
}
.salon-row:hover{background:var(--surface-sunken);padding-left:14px;}
.salon-row:hover .salon-row-arrow{color:var(--accent);transform:translateX(2px);}
.salon-row:active{background:var(--accent-soft);}

.salon-row-id{
  display:flex;
  align-items:baseline;
  gap:14px;
  min-width:0;
}
.salon-row-id h3{font-size:19px;font-weight:500;white-space:nowrap;}

.salon-row-meta{
  display:flex;
  align-items:center;
  gap:22px;
  flex:none;
}

.alarm-pill{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  font-size:12px;font-weight:500;
  padding:5px 11px;border-radius:20px;
  background:var(--ok-soft);color:var(--ok);
  white-space:nowrap;flex:none;
  width:98px;box-sizing:border-box;
}
.alarm-pill svg{width:13px;height:13px;}
.alarm-pill.armed{background:var(--danger-soft);color:var(--danger);}
.alarm-pill-empty{background:none;}
.salon-row-count{
  font-size:12.5px;
  color:var(--text-dim);
  white-space:nowrap;
  min-width:170px;
  text-align:right;
}
.salon-row-count .sep{color:var(--border-strong);margin:0 8px;}
.salon-row-count .n{
  font-family:ui-monospace,'SF Mono','Cascadia Mono',Menlo,Consolas,monospace;
  color:var(--text);
  font-weight:500;
}

.salon-row-arrow{
  width:16px;height:16px;
  color:var(--text-faint);
  flex:none;
  transition:transform .15s ease, color .15s ease;
}

@media (max-width:640px){
  .overview-head{padding:28px 0 20px;}
  .overview-head h2{font-size:26px;}
  .overview-head p{font-size:13.5px;}

  .salon-row{flex-wrap:wrap; gap:6px 20px; padding:16px 4px;}
  .salon-row:hover{padding-left:4px;} /* the hover shift only makes sense with room to spare */
  .salon-row-id{flex-wrap:wrap; row-gap:2px;}
  .salon-row-id h3{font-size:17px;}
  .salon-row-meta{order:3; width:100%; justify-content:space-between;}
}

/* ================================================================
   Detail — salon page (head, panels, alarm, cameras, system, VNC)
   ================================================================ */
.detail-head{
  padding:36px 0 22px;
  display:flex;
  align-items:flex-start;
  justify-content:space-between;
  gap:20px;
  flex-wrap:wrap;
  border-bottom:1px solid var(--border);
  margin-bottom:28px;
}
.detail-title{display:flex;align-items:center;gap:14px;flex-wrap:wrap;}
.detail-title h2{font-size:30px;font-weight:500;}

/* #sensorBadgeHost can hold more than one pill (temperature + humidity) —
   this makes it a flex container of its own so they get a small gap
   between them instead of colliding, without affecting spacing at the
   .detail-title level (that gap is only between h2/back-btn/this host). */
#sensorBadgeHost{display:inline-flex;align-items:center;gap:8px;}

.sensor-pill{
  display:inline-flex;align-items:center;gap:6px;
  font-size:13px;font-weight:500;color:var(--text-dim);
  padding:5px 11px;border-radius:20px;
  background:var(--surface-sunken);border:1px solid var(--border);
  white-space:nowrap;
}
.sensor-pill svg{width:14px;height:14px;flex:none;color:var(--text-faint);}

.back-btn{
  width:40px;height:40px;border-radius:10px;flex:none;
  display:flex;align-items:center;justify-content:center;
  border:1px solid var(--border-strong);
  background:var(--surface);color:var(--text);
  cursor:pointer;
}
.back-btn svg{width:18px;height:18px;}
.back-btn:hover{border-color:var(--text-faint);}
.back-btn:active{background:var(--surface-sunken);}

/* Alarm lock toggle — lives in the header now, next to the salon name
   (see .detail-actions below), not in its own panel anymore. */
.alarm-lock-toggle{display:flex;gap:6px;}
.alarm-lock-btn{
  height:40px;border-radius:10px;
  padding:0 14px;
  border:1px solid var(--border-strong);
  background:var(--surface-sunken);color:var(--text-faint);
  cursor:pointer;
  display:flex;align-items:center;justify-content:center;gap:7px;
  font-size:13px;font-weight:500;
}
.alarm-lock-btn svg{width:18px;height:18px;flex:none;}
.alarm-lock-btn:hover{border-color:var(--text-faint);color:var(--text);}
.alarm-lock-btn.locked.active{background:var(--danger-soft);border-color:var(--danger);color:var(--danger);}
.alarm-lock-btn.unlocked.active{background:var(--ok-soft);border-color:var(--ok);color:var(--ok);}

@media (max-width:640px){
  /* The header (back button + salon name) already fills the width on a
     phone, so the alarm toggle drops to its own full-width row below
     rather than fighting for space next to the title — wrapped in a
     light card so it reads as its own module, not a stray leftover
     bumped down by flex-wrap. */
  .detail-actions:has(.alarm-lock-toggle){
    width:100%;
    order:2;
    background:var(--surface-sunken);
    border:1px solid var(--border);
    border-radius:12px;
    padding:10px;
  }
  .alarm-lock-toggle{width:100%;}
  .alarm-lock-btn{flex:1;}
}

.detail-actions{display:flex;gap:10px;flex-wrap:wrap;align-items:center;}
.btn{
  display:inline-flex;align-items:center;gap:7px;
  font-size:13px;font-weight:500;
  padding:9px 15px;
  border-radius:9px;
  border:1px solid var(--border-strong);
  background:var(--surface);
  color:var(--text);
  cursor:pointer;
}
.btn svg{width:14px;height:14px;}
.btn:hover{border-color:var(--text-faint);}
.btn.primary{background:var(--accent);border-color:var(--accent);color:#fff;}
.btn.primary:hover{opacity:.92;}
.btn.danger{background:var(--danger);border-color:var(--danger);color:#fff;}
.btn.danger:hover{opacity:.92;}
.btn:disabled{opacity:.5;cursor:not-allowed;}

.detail-grid{
  display:grid;
  grid-template-columns:1.4fr 1fr;
  gap:24px;
  align-items:start;
}
@media (max-width:900px){.detail-grid{grid-template-columns:1fr;}}

/* One or both columns can be empty depending on the user's permissions on
   this salon (control for the left column; cameras, or system once the
   salon is confirmed online, for the right) — see
   updateDetailGridLayout() in js/app.js, which (re-)applies
   .detail-grid-col-hidden to whichever column has nothing to show, so it
   never reserves dead width next to the column that does. Runs once at
   first render and again once live GetState data has arrived, since the
   right column's system-panel visibility isn't known synchronously. */
.detail-grid.detail-grid-single{grid-template-columns:1fr;}
.detail-grid-col-hidden{display:none;}
/* Both columns hidden (no control, no cameras, no system) — nothing left
   to lay out in a grid at all; the empty-state message lives in the app
   shell above this, not inside .detail-grid itself. */
.detail-grid.detail-grid-empty{display:none;}

.panel{
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:14px;
  box-shadow:var(--shadow-card);
  padding:20px 22px 22px;
}
/* The right column stacks the cameras panel behind #camPanelHost (empty at
   first, filled in by JS) ahead of the system panel, itself behind
   #systemPanelHost (same reason — re-rendered once live computer.name
   arrives, see syncSystemPanel()) — the two hosts, not the .panel
   elements themselves, are what sit directly adjacent, so the selector
   has to target them instead of .panel + .panel, which never matches
   through that extra wrapper level. */
#camPanelHost:has(.panel) + #systemPanelHost:has(.panel){margin-top:18px;}
.panel h3{font-size:14px;font-weight:600;color:var(--text-dim);text-transform:uppercase;letter-spacing:0.04em;margin-bottom:16px;font-family:inherit;}

.panel-head{
  display:flex;align-items:center;justify-content:space-between;
  margin-bottom:16px;
}
.panel-head h3{margin-bottom:0;}

/* devices list */
.device-list{display:flex;flex-direction:column;}
.device{
  display:flex;align-items:center;justify-content:space-between;
  gap:14px;
  padding:14px 0;
  border-bottom:1px solid var(--border);
}
.device:last-child{border-bottom:none;}
.device-id{display:flex;align-items:center;gap:12px;}
.device-icon{
  width:36px;height:36px;border-radius:9px;
  background:var(--surface-sunken);
  display:flex;align-items:center;justify-content:center;
  flex:none;color:var(--text-dim);
}
.device-icon svg{width:18px;height:18px;}
.device.active .device-icon{background:var(--accent-soft);color:var(--accent);}
.device-name{font-size:14px;font-weight:500;}

.device-controls{display:flex;align-items:center;gap:10px;}

.switch{
  width:42px;height:24px;border-radius:20px;
  background:var(--border-strong);
  position:relative;cursor:pointer;
  border:none;flex:none;
  transition:background .15s ease;
}
.switch::after{
  content:'';position:absolute;top:3px;left:3px;
  width:18px;height:18px;border-radius:50%;
  background:var(--surface);
  box-shadow:0 1px 2px rgba(0,0,0,0.25);
  transition:transform .15s ease;
}
.switch.on{background:var(--accent);}
.switch.on::after{transform:translateX(18px);}

.stepper{display:flex;align-items:center;gap:8px;font-family:ui-monospace,'SF Mono','Cascadia Mono',Menlo,Consolas,monospace;font-size:14px;}
.stepper button{
  width:24px;height:24px;border-radius:6px;border:1px solid var(--border-strong);
  background:var(--surface-sunken);color:var(--text);cursor:pointer;
  display:flex;align-items:center;justify-content:center;font-size:14px;line-height:1;
}
.stepper button:hover{border-color:var(--text-faint);}
.stepper .val{min-width:44px;text-align:center;}

.shutter-control{display:flex;align-items:center;gap:8px;}
.shutter-control button{
  width:30px;height:30px;border-radius:7px;border:1px solid var(--border-strong);
  background:var(--surface-sunken);cursor:pointer;
  display:flex;align-items:center;justify-content:center;color:var(--text-dim);
}
.shutter-control button:hover{border-color:var(--text-faint);color:var(--text);}
.shutter-control svg{width:14px;height:14px;}

/* State reported as "Unknown" by GetState — no way to tell which side is
   currently active, so both options are shown plainly side by side rather
   than rendering a switch that would silently guess one of them. */
.unknown-toggle{display:flex;gap:6px;}
.unknown-toggle-btn{
  padding:6px 14px;border-radius:7px;border:1px solid var(--border-strong);
  background:var(--surface-sunken);color:var(--text-dim);cursor:pointer;
  font-size:12.5px;font-weight:500;
}
.unknown-toggle-btn:hover{border-color:var(--text-faint);color:var(--text);}

/* Generic "the command didn't reach Node-RED" feedback — applied to
   whichever control was actually clicked (switch, shutter button, lock
   button...) rather than a separate message, since the state visually
   reverts to what it was before the click anyway. */
.cmd-failed{animation:cmd-failed-shake .4s ease;}
@media not all and (prefers-reduced-motion: reduce){
  @keyframes cmd-failed-shake{
    0%,100%{transform:translateX(0);}
    20%{transform:translateX(-3px);}
    40%{transform:translateX(3px);}
    60%{transform:translateX(-2px);}
    80%{transform:translateX(2px);}
  }
}
.switch.cmd-failed::after{background:var(--danger-soft);}
.shutter-control button.cmd-failed,
.alarm-lock-btn.cmd-failed,
.unknown-toggle-btn.cmd-failed{border-color:var(--danger);color:var(--danger);}

@media (max-width:640px){
  /* Simple devices (a switch, or the two shutter buttons) keep a single
     compact row: name on the left, control on the right, just like desktop.
     Only the AC gets enough stuff (thermo toggle + stepper + switch +
     validate) to need its own row under the name (.device-wide). */
  .shutter-control{justify-content:flex-end;}

  .device-wide{
    flex-direction:column;
    align-items:stretch;
    gap:10px;
  }
  .device-wide .device-controls{flex-wrap:wrap; row-gap:8px; justify-content:flex-end;}
  .device-wide .switch{margin-left:auto;}
}

/* air conditioning widget */
.ac-quick-row{flex-wrap:wrap; row-gap:8px;}

.ac-thermo-toggle{display:flex;gap:2px;background:var(--surface-sunken);padding:2px;border-radius:8px;}
.ac-thermo-toggle button{
  width:30px;height:30px;border-radius:6px;border:none;background:none;
  color:var(--text-faint);cursor:pointer;
  display:flex;align-items:center;justify-content:center;
}
.ac-thermo-toggle svg{width:15px;height:15px;}
.ac-thermo-toggle button.cold.active{background:var(--surface);color:#3D8FE0;box-shadow:var(--shadow-card);}
.ac-thermo-toggle button.hot.active{background:var(--surface);color:var(--warn);box-shadow:var(--shadow-card);}

.ac-validate{padding:8px 14px; font-size:12.5px; min-width:76px; justify-content:center;}
.ac-validate:disabled{opacity:1; cursor:default;} /* stay legible through the sending/confirmation states */

.ac-validate.btn-sending{background:var(--text-faint); border-color:var(--text-faint);}

.ac-validate.btn-sent{
  background:var(--ok); border-color:var(--ok);
  animation:ac-validate-pop .28s cubic-bezier(.2,0,.1,1);
}
.ac-validate.btn-sent svg{width:13px; height:13px;}

.ac-validate.btn-send-failed{background:var(--danger); border-color:var(--danger);}

@media not all and (prefers-reduced-motion: reduce){
  @keyframes ac-validate-pop{
    0%{transform:scale(1);}
    40%{transform:scale(1.08);}
    100%{transform:scale(1);}
  }
}

@media (max-width:640px){
  .ac-quick-row{justify-content:flex-end;}
  .ac-quick-row .stepper{order:1;}
  .ac-thermo-toggle{order:0;}
  .ac-quick-row .switch{order:2; margin-left:0;}
  .ac-validate{order:3;}
}

/* cameras */
.cam-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px;}
.cam-tile{
  position:relative;border-radius:10px;overflow:hidden;
  background:var(--surface-sunken);
  aspect-ratio:16/10;
  border:1px solid var(--border);
  padding:0;
  cursor:pointer;
  display:block;
  width:100%;
}
.cam-tile:hover{border-color:var(--accent-ring);}
.cam-tile img{width:100%;height:100%;display:block;object-fit:cover;}
.cam-label{
  position:absolute;bottom:8px;left:8px;
  font-size:10.5px;color:#fff;background:rgba(28,26,27,0.55);backdrop-filter:blur(4px);
  padding:3px 7px;border-radius:5px;
}
.cam-live{
  position:absolute;top:8px;right:8px;
  display:flex;align-items:center;gap:4px;
  font-size:9.5px;font-weight:600;letter-spacing:0.04em;
  color:#fff;background:rgba(214,69,69,0.85);
  padding:2px 6px;border-radius:4px;
}
.cam-live .dot{width:5px;height:5px;border-radius:50%;background:#fff;animation:cam-live-blink 2s ease-in-out infinite;}

.cam-tile-unavailable{cursor:default;}
.cam-tile-unavailable .cam-live{display:none;}
.cam-unavailable,
.cam-viewer-unavailable{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;
  color:var(--text-faint);font-size:12px;
}
.cam-unavailable{width:100%;height:100%;}
.cam-unavailable svg{width:20px;height:20px;}
.cam-viewer-unavailable{width:100%;min-height:200px;color:#8B8689;font-size:13px;}
.cam-viewer-unavailable svg{width:24px;height:24px;}

@media not all and (prefers-reduced-motion: reduce){
  @keyframes cam-live-blink{
    0%,100%{opacity:1;}
    50%{opacity:.4;}
  }
}

/* full-size camera viewer */
.cam-viewer-backdrop{
  position:fixed;inset:0;
  background:rgba(0,0,0,0.75);
  display:flex;align-items:center;justify-content:center;
  padding:24px;
  z-index:150;
}
.cam-viewer{
  background:var(--surface);
  border-radius:14px;
  overflow:hidden;
  max-width:min(1000px, 100%);
  max-height:100%;
  display:flex;
  flex-direction:column;
  box-shadow:var(--shadow-pop);
}
.cam-viewer-head{
  display:flex;align-items:center;justify-content:space-between;
  padding:12px 16px;
  font-size:13px;font-weight:500;color:var(--text);
  border-bottom:1px solid var(--border);
}
.cam-viewer-stage{
  position:relative;
  background:#000;
  display:flex;align-items:center;justify-content:center;
  min-height:0;
}
.cam-viewer-stage img{
  display:block;
  max-width:100%;
  max-height:calc(100vh - 140px);
}
.cam-viewer-nav{
  position:absolute;top:50%;transform:translateY(-50%);
  width:38px;height:38px;border-radius:50%;
  border:none;
  background:rgba(0,0,0,0.5);
  color:#fff;
  display:flex;align-items:center;justify-content:center;
  cursor:pointer;
}
.cam-viewer-nav svg{width:18px;height:18px;}
.cam-viewer-nav:hover{background:rgba(0,0,0,0.7);}
.cam-viewer-nav.prev{left:12px;}
.cam-viewer-nav.next{right:12px;}

/* full-size VNC viewer (Guacamole iframe) */
.vnc-viewer-backdrop{
  position:fixed;inset:0;
  background:rgba(0,0,0,0.75);
  display:flex;align-items:center;justify-content:center;
  padding:24px;
  z-index:150;
}
.vnc-viewer{
  background:var(--surface);
  border-radius:14px;
  overflow:hidden;
  width:min(1200px, 100%);
  height:min(800px, 100%);
  display:flex;
  flex-direction:column;
  box-shadow:var(--shadow-pop);
}
.vnc-viewer-head{
  display:flex;align-items:center;justify-content:space-between;
  padding:12px 16px;
  font-size:13px;font-weight:500;color:var(--text);
  border-bottom:1px solid var(--border);
  flex:none;
}
.vnc-viewer-head-actions{display:flex;align-items:center;gap:4px;}
.vnc-viewer-stage{
  position:relative;
  background:#000;
  flex:1;
  display:flex;align-items:center;justify-content:center;
  min-height:0;
}
.vnc-viewer-stage iframe{
  display:block;
  width:100%;
  height:100%;
  border:none;
}

/* system / VNC panel */
.sys-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:11px 0;border-bottom:1px solid var(--border);flex-wrap:wrap;}
.sys-row:last-child{border-bottom:none;}
.sys-label{font-size:13px;color:var(--text-dim);}

@media (max-width:640px){
  .detail-head{padding:24px 0 18px; margin-bottom:20px;}
  .detail-title h2{font-size:24px;}

  .back-btn{width:44px;height:44px;}

  .panel{padding:16px 16px 18px;}
  .cam-grid{grid-template-columns:1fr;}

  .cam-viewer-backdrop{padding:0;}
  .cam-viewer{border-radius:0; max-height:100vh; height:100%;}
  .cam-viewer-nav{width:34px;height:34px;}

  .vnc-viewer-backdrop{padding:0;}
  .vnc-viewer{border-radius:0; width:100%; height:100%;}

  .sys-row{padding:10px 0;}
  .sys-row .btn{flex:none;}
}

/* ================================================================
   Views — overview/detail switch, page-enter animation
   ================================================================ */
.overview-container{display:block;}
.detail-container{display:none;}
.detail-container.visible{display:block;}
.overview-container.hidden{display:none;}

@media not all and (prefers-reduced-motion: reduce){
  .view-enter{animation:view-rise .28s cubic-bezier(.2,0,.1,1) both;}
}

@keyframes view-rise{
  from{opacity:0; transform:translateY(8px);}
  to{opacity:1; transform:translateY(0);}
}

/* ================================================================
   Login & Admin — connection screen, account management
   ================================================================ */

.login-screen{
  min-height:100vh;
  display:flex;align-items:center;justify-content:center;
  padding:24px;
  background:var(--bg);
}
.login-card{
  width:100%;max-width:360px;
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:14px;
  box-shadow:var(--shadow-pop);
  padding:28px 26px 26px;
  display:flex;flex-direction:column;gap:16px;
}
.login-brand{display:flex;align-items:center;gap:10px;margin-bottom:6px;}
.login-brand .mark{
  width:28px;height:28px;border-radius:7px;
  background:var(--accent);
  display:inline-flex;align-items:center;justify-content:center;
  color:#fff;font-family:Georgia,serif;font-weight:600;font-size:15px;
  flex:none;
}
.login-brand h1{font-size:19px;font-weight:600;}
.login-error{
  margin:0;padding:9px 12px;border-radius:8px;
  background:var(--danger-soft);color:var(--danger);
  font-size:12.5px;
}
.admin-protected-note{
  margin:0 0 16px;padding:9px 12px;border-radius:8px;
  background:var(--warn-soft);color:var(--warn);
  font-size:12.5px;
}
.login-submit{justify-content:center;width:100%;padding:10px;}

/* Generic form field, shared by the login and admin forms */
.field{display:flex;flex-direction:column;gap:6px;font-size:13px;color:var(--text-dim);}
.field span{font-weight:500;color:var(--text);}
.field input[type=text],
.field input[type=password],
.field input[type=url]{
  font-family:inherit;font-size:14px;
  padding:9px 10px;border-radius:8px;
  border:1px solid var(--border-strong);
  background:var(--surface);color:var(--text);
}
.admin-head{display:flex;align-items:center;gap:14px;padding:36px 0 22px;}
.admin-head h2{font-size:26px;font-weight:500;}

.admin-user-table-wrap{width:100%;overflow-x:auto;}
.admin-user-table{width:100%;border-collapse:collapse;font-size:13px;}
.admin-user-table th{
  text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:0.04em;
  color:var(--text-faint);font-weight:600;padding:0 10px 10px;border-bottom:1px solid var(--border);
}
.admin-user-table td{padding:10px;border-bottom:1px solid var(--border);vertical-align:middle;}
.admin-user-table tr:last-child td{border-bottom:none;}
.admin-ops-cell{text-align:right;white-space:nowrap;}

.admin-status-pill{
  display:inline-flex;align-items:center;gap:6px;
  font-size:11.5px;font-weight:500;
  padding:3px 9px;border-radius:20px;
  background:var(--ok-soft);color:var(--ok);
}
.admin-status-pill::before{content:'';width:6px;height:6px;border-radius:50%;background:currentColor;flex:none;}
.admin-status-pill.inactive{background:var(--surface-sunken);color:var(--text-faint);}

.admin-role-tag{
  display:inline-block;font-size:11px;font-weight:500;
  padding:3px 8px;border-radius:6px;
  background:var(--surface-sunken);color:var(--text-dim);
}
.admin-role-tag.admin{background:var(--accent-soft);color:var(--accent);}

/* Permission cards — one salon per card, chips instead of raw checkboxes.
   Replaces the old 6-column table, which never fit a phone width and had
   no scroll wrapper of its own, so it dragged the whole page sideways. */
.admin-perm-cards{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(220px, 1fr));
  gap:10px;
  width:100%;
}
.admin-perm-card{
  border:1px solid var(--border);
  border-radius:10px;
  padding:12px 14px 14px;
  background:var(--surface-sunken);
}
.admin-perm-card-head{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  margin-bottom:10px;
}
.admin-perm-card-name{font-size:13.5px;font-weight:500;color:var(--text);}
.admin-perm-toggle-all{
  font-size:11px;font-weight:500;color:var(--text-faint);
  background:none;border:none;padding:2px 4px;cursor:pointer;
  text-decoration:underline;text-underline-offset:2px;
}
.admin-perm-toggle-all:hover{color:var(--accent);}

.admin-perm-chips{display:flex;flex-wrap:wrap;gap:6px;}
.admin-perm-chip{
  position:relative;
  font-size:12px;font-weight:500;color:var(--text-dim);
  padding:6px 12px;border-radius:20px;
  background:var(--surface);border:1px solid var(--border-strong);
  cursor:pointer;user-select:none;
  transition:background .12s ease, border-color .12s ease, color .12s ease;
}
.admin-perm-chip input{position:absolute;opacity:0;width:0;height:0;}
.admin-perm-chip:has(input:checked){
  background:var(--accent);border-color:var(--accent);color:#fff;
}
.admin-perm-chip:has(input:focus-visible){outline:2px solid var(--accent);outline-offset:2px;}

.admin-form-panel{
  max-width:520px;
  display:flex;flex-direction:column;gap:14px;
}
#userForm,
#salonForm{display:flex;flex-direction:column;gap:14px;align-items:stretch;}
#userForm fieldset{border:none;padding:0;margin:0;display:flex;flex-direction:column;gap:6px;}
#userForm legend{font-size:13px;font-weight:500;color:var(--text);padding:0;margin-bottom:2px;}

/* Rôle — segmented control (two options side by side, active one filled
   with the accent) instead of two stacked radio rows. */
.admin-segmented{
  display:inline-flex;
  border:1px solid var(--border-strong);
  border-radius:9px;
  padding:3px;
  gap:2px;
  background:var(--surface-sunken);
  width:fit-content;
}
.admin-segmented-opt{
  position:relative;
  font-size:13px;font-weight:500;color:var(--text-dim);
  padding:7px 16px;border-radius:7px;
  cursor:pointer;user-select:none;
  transition:background .12s ease, color .12s ease;
}
.admin-segmented-opt input{position:absolute;opacity:0;width:0;height:0;}
.admin-segmented-opt:has(input:checked){background:var(--accent);color:#fff;}
.admin-segmented-opt:has(input:focus-visible){outline:2px solid var(--accent);outline-offset:2px;}

.admin-form-actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:4px;}
.admin-add-user{margin-top:18px;}

.admin-tabs{display:flex;gap:6px;margin-top:28px;border-bottom:1px solid var(--border);}
.admin-tab{
  padding:10px 16px;font-size:14px;font-weight:500;color:var(--text-faint);
  background:none;border:none;border-bottom:2px solid transparent;cursor:pointer;
  margin-bottom:-1px;
}
.admin-tab:hover{color:var(--text);}
.admin-tab.active{color:var(--text);border-bottom-color:var(--accent);}

@media (max-width:640px){
  .login-card{padding:22px 20px 20px;}
  .admin-head{padding:24px 0 18px;}
  .admin-perm-cards{grid-template-columns:1fr;}
}
