:root{
  --ink:#161b22; --ink-soft:#3d454e; --paper:#f2f3f5; --surface:#ffffff; --surface-2:#fafbfc;
  --line:#e4e7eb; --line-soft:#edeff2;
  --muted:#6b7480; --muted-2:#8a929d;
  --local:#0f8f72; --local-ink:#0b6e58; --local-bg:#e6f5f0;
  --cloud:#b0700f; --cloud-ink:#8f5c0c; --cloud-bg:#fbf0dc;
  --danger:#c8393c; --danger-ink:#a52d30; --danger-bg:#fbeaea;
  --side:#12161c; --side-2:#181d25; --side-tx:#aab2bd; --side-on-bg:#1f2530; --side-on-tx:#ffffff; --side-line:#232a34;
  --accent-grad:linear-gradient(135deg,#12a37f,#0d7fa8);
  --radius-xs:6px; --radius-sm:9px; --radius-md:10px; --radius:14px; --radius-lg:18px;
  --shadow-xs:0 1px 2px rgba(20,25,32,.04);
  --shadow-sm:0 1px 2px rgba(20,25,32,.05), 0 4px 10px -4px rgba(20,25,32,.08);
  --shadow-md:0 2px 6px rgba(20,25,32,.05), 0 12px 28px -10px rgba(20,25,32,.14);
  --shadow-lg:0 20px 60px -12px rgba(15,20,28,.35);
  --ring:0 0 0 3px rgba(15,143,114,.18);
  --sans:"Inter",system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --mono:ui-monospace,"JetBrains Mono","SF Mono",Menlo,Consolas,monospace;
  --dur:.16s; --ease:cubic-bezier(.2,.7,.3,1);
}
html.dark{
  --ink:#eef1f4; --ink-soft:#c2c9d1; --paper:#0d1015; --surface:#161b22; --surface-2:#1b2129;
  --line:#2a323d; --line-soft:#242b35;
  --muted:#8b95a3; --muted-2:#6e7885;
  --local:#33c79d; --local-ink:#5ee0b8; --local-bg:#132821;
  --cloud:#eab155; --cloud-ink:#f2c67c; --cloud-bg:#332411;
  --danger:#f0787a; --danger-ink:#f6a1a2; --danger-bg:#341c1d;
  --side:#0a0d12; --side-2:#0f131a; --side-tx:#8d96a3; --side-on-bg:#1c222c; --side-on-tx:#ffffff; --side-line:#1c222c;
  --shadow-xs:0 1px 2px rgba(0,0,0,.3);
  --shadow-sm:0 1px 2px rgba(0,0,0,.35), 0 4px 12px -4px rgba(0,0,0,.4);
  --shadow-md:0 2px 8px rgba(0,0,0,.35), 0 16px 34px -12px rgba(0,0,0,.55);
  --shadow-lg:0 24px 70px -14px rgba(0,0,0,.65);
  --ring:0 0 0 3px rgba(51,199,157,.22);
}

*{box-sizing:border-box}
::selection{background:var(--local);color:#fff}
body{
  margin:0;font-family:var(--sans);color:var(--ink);background:var(--paper);line-height:1.55;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  font-size:14.5px;
}
a{color:inherit}
code,.mono{font-family:var(--mono);font-size:.88em}
h1{font-size:1.28rem;margin:0;font-weight:700;letter-spacing:-.01em}
h2{font-size:1.02rem;margin:0 0 .9rem;font-weight:700;letter-spacing:-.005em}
h3{font-size:.88rem;margin:0 0 .5rem;font-weight:700}
p{margin:0 0 .6rem}
.muted{color:var(--muted)} .small{font-size:.85rem}

/* ---------- Layout ---------- */
.app{display:flex;min-height:100vh}

.side{
  width:230px;background:linear-gradient(180deg,var(--side),var(--side-2));color:var(--side-tx);
  display:flex;flex-direction:column;padding:1.2rem .85rem;position:sticky;top:0;height:100vh;
  border-right:1px solid var(--side-line);
}
.brand{display:flex;align-items:center;gap:.65rem;padding:.3rem .3rem 1.4rem}
.brand b{display:block;font-size:1.01rem;color:#fff;letter-spacing:-.01em;font-weight:700}
.brandico{color:#fff}
.mark{
  width:36px;height:36px;border-radius:var(--radius-sm);background:var(--accent-grad);
  display:flex;align-items:center;justify-content:center;flex:0 0 auto;
  box-shadow:0 4px 14px -2px rgba(15,143,114,.55), inset 0 1px 0 rgba(255,255,255,.18);
}
.side nav{display:flex;flex-direction:column;gap:1px;flex:1;margin-top:.2rem}
.side nav a{
  padding:.56rem .7rem;border-radius:9px;text-decoration:none;color:var(--side-tx);
  font-size:.9rem;font-weight:500;position:relative;transition:background var(--dur) var(--ease),color var(--dur) var(--ease);
}
.side nav a:hover{background:var(--side-on-bg);color:#fff}
.side nav a.on{background:var(--side-on-bg);color:var(--side-on-tx);font-weight:600}
.side nav a.on::before{
  content:"";position:absolute;left:-.85rem;top:.35rem;bottom:.35rem;width:3px;border-radius:0 3px 3px 0;
  background:var(--accent-grad);
}
.logout{
  padding:.55rem .7rem;color:var(--muted);text-decoration:none;font-size:.83rem;border-radius:9px;
  transition:background var(--dur) var(--ease),color var(--dur) var(--ease);
}
.logout:hover{color:#fff;background:var(--side-on-bg)}
.logout.on{color:var(--side-on-tx);background:var(--side-on-bg);font-weight:600}

main{flex:1;min-width:0}
.top{
  display:flex;align-items:center;justify-content:space-between;padding:1.05rem 1.8rem;
  border-bottom:1px solid var(--line);background:color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter:saturate(1.4) blur(6px);gap:1rem;position:sticky;top:0;z-index:5;
}
.topright{display:flex;align-items:center;gap:.7rem}
.content{padding:1.8rem;max-width:1120px}

.badge{
  font-size:.74rem;padding:.35rem .7rem;border-radius:999px;font-weight:700;white-space:nowrap;
  display:inline-flex;align-items:center;gap:.4rem;letter-spacing:.01em;
}
.badge::before{content:"";width:6px;height:6px;border-radius:999px;background:currentColor;flex:0 0 auto}
.badge.demo{background:var(--cloud-bg);color:var(--cloud-ink)}
.badge.live{background:var(--local-bg);color:var(--local-ink)}
.badge.who{background:var(--surface-2);color:var(--ink-soft);border:1px solid var(--line)}
.badge.who::before{display:none}
.badge.online{background:var(--local-bg);color:var(--local-ink)}
.badge.offline{background:var(--danger-bg);color:var(--danger-ink)}
.themebtn{
  background:var(--surface);border:1px solid var(--line);color:var(--ink);width:36px;height:36px;
  border-radius:9px;cursor:pointer;font-size:1.05rem;padding:0;transition:all var(--dur) var(--ease);
  box-shadow:var(--shadow-xs);
  display:inline-flex;align-items:center;justify-content:center;text-decoration:none;
}
.themebtn:hover{background:var(--paper);border-color:var(--muted-2);transform:translateY(-1px)}
.themebtn.on{background:var(--side-on-bg);border-color:var(--side-on-bg);color:var(--side-on-tx)}

/* ---------- Dashboard explainer ---------- */
.split-explainer{
  display:grid;grid-template-columns:1fr auto 1fr;align-items:stretch;margin-bottom:1.4rem;
  border:1px solid var(--line);border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-sm);
}
.world{padding:1.25rem 1.4rem}
.world .tag{font-size:.7rem;font-weight:800;text-transform:uppercase;letter-spacing:.07em}
.world p{margin:.5rem 0 0;font-size:.89rem;color:var(--ink-soft)}
.world.local{background:var(--local-bg)} .world.local .tag{color:var(--local-ink)}
.world.cloud{background:var(--cloud-bg)} .world.cloud .tag{color:var(--cloud-ink)}
.split-explainer .arrow{display:flex;align-items:center;padding:0 1rem;background:var(--surface);color:var(--muted-2);font-size:1.3rem}
.tag.cloud{color:var(--cloud-ink);font-weight:800;text-transform:uppercase;font-size:.7rem;letter-spacing:.06em}

.apibox{
  display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap;
  background:var(--surface);border:1px solid var(--line);border-left:3px solid var(--cloud);
  border-radius:var(--radius);padding:.9rem 1.2rem;margin-bottom:1.5rem;font-size:.91rem;box-shadow:var(--shadow-xs);
}

.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(155px,1fr));gap:.9rem;margin-bottom:1.8rem}
.stat{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:1.1rem 1.2rem;
  text-decoration:none;display:flex;flex-direction:column;box-shadow:var(--shadow-xs);
  transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--ease),border-color var(--dur) var(--ease);
  color:var(--ink);
}
.stat b{font-size:1.7rem;line-height:1;letter-spacing:-.02em;font-weight:800}
.stat span{color:var(--muted);font-size:.84rem;margin-top:.4rem;font-weight:500}
.stat:hover{border-color:var(--local);box-shadow:var(--shadow-md);transform:translateY(-2px)}

.steps{margin:.5rem 0 1rem;padding-left:1.25rem}.steps li{margin:.45rem 0;font-size:.9rem}
.inline-assign{margin:0}
/* Select/Input direkt neben .btn.small (Höhe angleichen - Standardgröße .6rem/.7rem Padding
   liesse das Feld sichtbar größer wirken als den kleinen Button daneben). */
.inline-assign select,.inline-assign input{margin-top:0;padding:.4rem .6rem;font-size:.86rem}
.lockchips{display:flex;flex-wrap:wrap;gap:.35rem}
.lockchip{
  background:var(--paper);border:1px solid var(--line);color:var(--ink-soft);font-size:.77rem;
  padding:.2rem .55rem;border-radius:999px;white-space:nowrap;font-weight:500;
}
.lockchip.frozen{opacity:.6;text-decoration:line-through}
.lockchip.missing,.lockchip.expired{background:var(--danger-bg);border-color:var(--danger);color:var(--danger-ink)}
.lockchip.temp{background:var(--cloud-bg);border-color:var(--cloud);color:var(--cloud-ink)}
.legend{display:flex;flex-wrap:wrap;gap:.5rem 1.4rem;margin:0 0 1.1rem;padding:.65rem 1rem;background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius-sm)}
.legenditem{display:inline-flex;align-items:center;gap:.5rem;font-size:.82rem;color:var(--muted)}
.legenddot{display:inline-block;width:.65rem;height:.65rem;border-radius:999px;flex:0 0 auto;background:var(--muted-2)}
.legenddot.missing{background:var(--danger)}
.legenddot.temp{background:var(--cloud)}
.legenddot.frozen{background:var(--muted-2);opacity:.6}
.btn-del{
  background:transparent;color:var(--danger-ink);border:1px solid var(--danger);border-radius:9px;
  padding:.42rem .85rem;font:inherit;font-size:.84rem;font-weight:700;cursor:pointer;white-space:nowrap;
  transition:all var(--dur) var(--ease);
}
.btn-del:hover{background:var(--danger);color:#fff;border-color:var(--danger);box-shadow:var(--shadow-xs)}
.cardtable td{vertical-align:top;padding-top:.85rem}
/* Bewusst KEINE eigene font-size/padding/vertical-align - soll optisch exakt wie jede andere
   Zelle wirken (gleiche Baseline wie z.B. "Gültigkeit"), nur Icon+Name sauber nebeneinander. */
.assignedchip{display:inline-flex;align-items:center;gap:.35rem;text-decoration:none}
.assignedchip:hover{text-decoration:underline}
.assignedchip svg{flex:0 0 auto;color:var(--muted)}
.valperm{color:var(--muted);font-weight:500} .valwin{color:var(--ink)} .valcyc{color:var(--local-ink);font-weight:700;font-size:.85rem}
.periodedit{margin-top:.3rem}
.periodedit summary{cursor:pointer;color:var(--local-ink);font-size:.82rem;font-weight:700;list-style:none}
.periodedit summary::-webkit-details-marker{display:none}
.periodedit summary::before{content:"⚙ ";font-size:.85em}
.periodedit[open]{background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius-md);padding:.7rem .8rem;margin-top:.5rem;box-shadow:var(--shadow-xs)}
.periodedit .radio{display:flex;align-items:center;gap:.45rem;margin:.35rem 0;font-size:.85rem;color:var(--ink)}
.periodedit .radio input{width:auto;margin:0}
.periodedit .sub{margin:.15rem 0 .55rem 1.5rem;font-size:.82rem;color:var(--muted);display:flex;align-items:center;gap:.35rem;flex-wrap:wrap}
.periodedit .sub input{width:auto;margin:0}
.wdays{gap:.2rem}
.wd{display:flex;flex-direction:column;align-items:center;font-size:.72rem;color:var(--ink);gap:.15rem}
.wd input{margin:0}
.btn.small{padding:.4rem .85rem;font-size:.84rem;margin-top:.25rem}

.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(185px,1fr));gap:.9rem;margin-bottom:1.8rem}
.lockcard{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:1rem 1.1rem;
  display:flex;flex-direction:column;gap:.3rem;box-shadow:var(--shadow-xs);
  transition:box-shadow var(--dur) var(--ease),transform var(--dur) var(--ease);
}
.lockcard:hover{box-shadow:var(--shadow-sm);transform:translateY(-1px)}
.lockcard b{font-size:.95rem}
.lockcard .batt{font-weight:700;color:var(--local-ink);font-size:1.05rem;display:inline-flex;align-items:center;gap:.3rem} .lockcard .batt.low{color:var(--danger-ink)}
.battico{flex:0 0 auto}

.grid2{display:grid;grid-template-columns:1fr 1fr;gap:1.3rem}
.panel{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:1.3rem;
  margin-bottom:1.3rem;box-shadow:var(--shadow-xs);
}
label{display:block;font-size:.82rem;color:var(--muted);margin-bottom:.75rem;font-weight:500}
input,select{
  width:100%;margin-top:.3rem;padding:.6rem .7rem;border:1px solid var(--line);border-radius:9px;
  font:inherit;color:var(--ink);background:var(--surface);transition:border-color var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
input:hover,select:hover{border-color:var(--muted-2)}
input:focus,select:focus{outline:none;border-color:var(--local);box-shadow:var(--ring)}
button,.btn{
  cursor:pointer;background:var(--ink);color:var(--surface);border:0;border-radius:9px;padding:.62rem 1.05rem;
  font:inherit;font-weight:600;text-decoration:none;display:inline-block;box-shadow:var(--shadow-xs);
  transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--ease),opacity var(--dur) var(--ease),background var(--dur) var(--ease);
}
button:hover,.btn:hover{transform:translateY(-1px);box-shadow:var(--shadow-sm)}
button:active,.btn:active{transform:translateY(0)}
button:focus-visible,.btn:focus-visible,input:focus-visible,select:focus-visible,
.chip:focus-visible,.stat:focus-visible,.themebtn:focus-visible{outline:none;box-shadow:var(--ring)}
.btn.ghost{background:transparent;color:var(--ink);border:1px solid var(--line);box-shadow:none}
.btn.ghost:hover{background:var(--paper)}
.btn.danger,button.danger{background:var(--danger);color:#fff}
.btn.danger:hover,button.danger:hover{background:var(--danger-ink)}
.linkbtn{
  background:transparent;border:0;color:var(--local-ink);cursor:pointer;font:inherit;font-size:.85rem;
  padding:.2rem .3rem;font-weight:700;border-radius:var(--radius-xs);transition:background var(--dur) var(--ease);
}
.linkbtn:hover{background:var(--local-bg)}
.linkbtn.danger{color:var(--danger-ink)}
.linkbtn.danger:hover{background:var(--danger-bg)}
.linkbtn.iconbtn{display:inline-flex;align-items:center;vertical-align:middle;padding:.25rem}

.checkgroup{margin-bottom:1rem}
.checklabel{display:block;font-size:.82rem;color:var(--muted);margin-bottom:.45rem;font-weight:500}
.check{display:flex;align-items:center;gap:.5rem;font-size:.92rem;color:var(--ink);margin-bottom:.4rem;cursor:pointer}
.check input{width:auto;margin:0}

table{width:100%;border-collapse:collapse;background:var(--surface)}
.list,.records,.mini{border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;box-shadow:var(--shadow-xs)}
/* Ausnahme fuer die Transponder-Tabelle: das "+ Schloss"-Dropdown (.addlockmenu, siehe
   .hlockmenu-body) ist ein absolut positioniertes Popover, das ueber die Zeile hinausragen
   soll - overflow:hidden von .records hat es an der Tabellenkante abgeschnitten, dadurch war
   "Uebernehmen" in unteren Zeilen nicht mehr klickbar. */
.cardtable{overflow:visible}
th{
  text-align:left;font-size:.71rem;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);
  padding:.7rem .9rem;background:var(--surface-2);border-bottom:1px solid var(--line);font-weight:700;
}
td{padding:.68rem .9rem;border-bottom:1px solid var(--line-soft);font-size:.89rem}
tbody tr{transition:background var(--dur) var(--ease)}
tbody tr:hover{background:var(--surface-2)}
tr:last-child td{border-bottom:0}
.localchip{color:var(--local-ink);font-weight:700}
.cloudchip{background:var(--cloud-bg);color:var(--cloud-ink);padding:.15rem .5rem;border-radius:7px;font-weight:600}
/* Menschlich vergebenes Identitaets-Pseudonym (tenants.person_pseudonym) - bewusst neutral statt
   cloud-farbig, das ist NICHT das TTLock-Pseudonym (siehe Db.php-Kommentar dazu). */
.pseudochip{background:var(--surface-2);border:1px solid var(--line);color:var(--muted);padding:.15rem .5rem;border-radius:7px;font-weight:600}
.rolechip{
  display:inline-block;background:var(--accent-grad);color:#fff;padding:.15rem .55rem;border-radius:999px;
  font-size:.72rem;font-weight:700;letter-spacing:.01em;vertical-align:middle;margin-left:.4rem;
}
.fail{color:var(--danger-ink);font-weight:800}

.personfilter{margin-bottom:1rem}
.personfilter input{
  max-width:340px;background:var(--surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238a929d' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E") no-repeat .65rem center;
  padding-left:2rem;
}

.person{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:1.1rem 1.2rem;
  margin-bottom:1.1rem;box-shadow:var(--shadow-xs);transition:box-shadow var(--dur) var(--ease);
}
.person:hover{box-shadow:var(--shadow-sm)}
.person-head{display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap;margin-bottom:.7rem}
.person-head form{margin:0}
.revokebtns{display:flex;gap:.4rem;flex-wrap:wrap}
.actionchipform{margin:0}
.actionchip{
  display:inline-flex;align-items:center;gap:.4rem;padding:.4rem .75rem;border-radius:var(--radius-sm);
  font:inherit;font-size:.82rem;font-weight:600;cursor:pointer;border:1px solid transparent;
  background:transparent;transition:background var(--dur) var(--ease),border-color var(--dur) var(--ease),color var(--dur) var(--ease),transform var(--dur) var(--ease);
}
.actionchip:hover{transform:translateY(-1px)}
.actionchip svg{flex:0 0 auto}
/* muted: reversibel oder nur ein Teilzugang - keine dauerhafte Konsequenz fuer den Datensatz */
.actionchip.chip-muted{color:var(--muted);border-color:var(--line);background:var(--surface-2)}
.actionchip.chip-muted:hover{color:var(--ink);border-color:var(--muted-2)}
/* ok: stellt etwas wieder her (Entsperren) */
.actionchip.chip-ok{color:var(--local-ink);border-color:var(--local);background:var(--local-bg)}
.actionchip.chip-ok:hover{background:var(--local);color:#fff}
/* warn: entzieht echte Zugaenge dauerhaft, die Person selbst bleibt aber im System */
.actionchip.chip-warn{color:var(--cloud-ink);border-color:var(--cloud);background:var(--cloud-bg)}
.actionchip.chip-warn:hover{background:var(--cloud);color:#fff}
/* danger: entfernt die Person selbst aus der Liste - einzige wirklich "rote" Aktion */
.actionchip.chip-danger{color:var(--danger-ink);border-color:var(--danger);background:var(--danger-bg)}
.actionchip.chip-danger:hover{background:var(--danger);color:#fff}
.person-head b{font-size:1rem}
.mini{margin-top:.5rem}.mini td,.mini th{padding:.5rem .75rem}
.mini form{margin:0;display:inline}
tr.rev{opacity:.5}

.persondrop{margin-top:.2rem}
.persondrop summary{
  cursor:pointer;list-style:none;color:var(--muted);font-size:.85rem;font-weight:600;
  padding:.4rem 0;display:flex;align-items:center;gap:.4rem;user-select:none;
}
.persondrop summary::-webkit-details-marker{display:none}
.persondrop summary::before{
  content:"›";display:inline-block;font-size:1.1rem;line-height:1;transition:transform var(--dur) var(--ease);color:var(--muted-2);
}
.persondrop[open] summary::before{transform:rotate(90deg)}
.persondrop summary:hover{color:var(--ink)}
.persondrop summary .count{color:var(--muted-2);font-weight:500}
.persondrop-body{padding-top:.3rem}
.btn.small.danger, .btn.danger.small{padding:.4rem .8rem;font-size:.82rem}
.rowform{display:grid;grid-template-columns:repeat(5,1fr) auto;gap:.75rem;align-items:end}
.rowform label{margin-bottom:0}.rowform button{height:min-content}
/* Select ohne eigenes <label> (z.B. "Schloss zuordnen") sitzt direkt neben .btn.small - gleiche
   Höhenangleichung wie .inline-assign, siehe dort. */
.rowform>select{padding:.4rem .6rem;font-size:.86rem}

/* Mitarbeiter anlegen: eigenes Grid statt starrer 5 Spalten - Felder atmen, statt
   gequetscht zu wirken, und brechen bei schmalen Fenstern sauber um. */
.newtenant{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:1rem 1.1rem;align-items:center}
.newtenant label{margin-bottom:0}
.newtenant .span2{grid-column:span 2}
.newtenant .check{align-self:center;margin-bottom:0}
.newtenant button{grid-column:1/-1;justify-self:start;margin-top:.2rem}
.req{color:var(--danger-ink);font-weight:700;margin-left:.2rem}
/* Pseudonym-Nummernband-Hinweis (z.B. "00300-00399") darf nie umbrechen - sonst wird das
   Label zweizeilig und zieht die ganze Grid-Zeile auseinander (siehe Style-Nachbesserung). */
.pseudohint{white-space:nowrap}
@media (max-width:640px){
  .newtenant{grid-template-columns:1fr}
  .newtenant .span2{grid-column:auto}
}

.filterbar{display:flex;gap:.45rem;flex-wrap:wrap;margin-bottom:1.1rem}
.chip{
  padding:.4rem .85rem;border:1px solid var(--line);border-radius:999px;text-decoration:none;font-size:.85rem;
  color:var(--muted);background:var(--surface);font-weight:500;transition:all var(--dur) var(--ease);
}
.chip:hover{border-color:var(--local);color:var(--local-ink)}
.chip.on{background:var(--ink);color:var(--surface);border-color:var(--ink);font-weight:600}

/* Kurzer Toast statt stiller Inline-Box: oben rechts eingeblendet, damit eine Aktion
   (anlegen/loeschen/aendern) sofort sichtbar bestaetigt wird, statt im Seiteninhalt unterzugehen.
   Blendet nach ein paar Sekunden von selbst wieder aus (reines CSS, kein JS noetig). */
.flash{
  position:fixed;top:1.1rem;right:1.1rem;z-index:1000;max-width:min(380px,calc(100vw - 2.2rem));
  display:flex;align-items:center;gap:.55rem;
  background:var(--local-bg);color:var(--local-ink);border:1px solid transparent;padding:.75rem 1.05rem;
  border-radius:var(--radius-md);font-size:.9rem;font-weight:500;box-shadow:var(--shadow-sm);
  animation:flash-in .25s ease-out, flash-out .5s ease-in 3.5s forwards;
}
.flash svg{flex:0 0 auto}
.flash.err{background:var(--danger-bg);color:var(--danger-ink)}
@keyframes flash-in{from{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}
@keyframes flash-out{to{opacity:0;transform:translateY(-10px)}}
.bar{display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap;margin-bottom:1.1rem}
.barbtns{display:flex;align-items:center;gap:1rem}
h2{margin-top:1.8rem}.content>h2:first-child{margin-top:0}
.empty{padding:2.2rem;text-align:center;color:var(--muted);border:1px dashed var(--line);border-radius:var(--radius)}
.ok{color:var(--local-ink);font-weight:700}.miss{color:var(--danger-ink);font-weight:700}.expiredtxt{color:var(--danger-ink);font-weight:700}.temptxt{color:var(--cloud-ink);font-weight:700}

.handover{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-lg);padding:1.6rem;max-width:560px;box-shadow:var(--shadow-md)}
.creds{background:var(--surface-2);border:1px solid var(--line-soft);border-radius:var(--radius-md);padding:1.1rem 1.2rem;margin:1.1rem 0}
.credrow{display:flex;justify-content:space-between;align-items:center;padding:.45rem 0;border-bottom:1px solid var(--line)}
.credrow:last-child{border-bottom:0}
.credrow code{background:var(--surface);padding:.28rem .55rem;border-radius:7px;border:1px solid var(--line)}
.credval{display:flex;align-items:center;gap:.4rem}
.credrow-single{justify-content:flex-end}
.copybtn{white-space:nowrap}
.warn{color:var(--cloud-ink);font-size:.85rem;margin:.65rem 0 0}

.login-body{
  display:flex;align-items:center;justify-content:center;min-height:100vh;
  background:radial-gradient(1200px 700px at 20% 10%, #1a2129 0%, var(--side) 55%, #090b0e 100%);
}
.login{background:var(--surface);padding:2.2rem;border-radius:18px;width:330px;box-shadow:var(--shadow-lg);border:1px solid var(--line-soft)}
.login .brand.big{padding-bottom:.7rem}
.login p.muted{font-size:.85rem;margin:.25rem 0 1.3rem}
.login button{width:100%;margin-top:.5rem}
.err{background:var(--danger-bg);color:var(--danger-ink);padding:.55rem .75rem;border-radius:var(--radius-md);font-size:.85rem;margin-bottom:.65rem;font-weight:500}

::-webkit-scrollbar{width:11px;height:11px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--line);border-radius:99px;border:3px solid var(--paper)}
::-webkit-scrollbar-thumb:hover{background:var(--muted-2)}

@media(max-width:820px){
  .app{flex-direction:column}
  .side{width:auto;height:auto;position:static;flex-direction:row;flex-wrap:wrap;align-items:center;gap:.3rem}
  .brand{padding:0 .6rem 0 .2rem}.brand b{font-size:.95rem}
  .side nav{flex-direction:row;flex-wrap:wrap;gap:.2rem;margin-top:0}
  .side nav a.on::before{display:none}
  .logout{margin-left:auto}
  .content{padding:1.1rem}
  .grid2{grid-template-columns:1fr}
  .split-explainer{grid-template-columns:1fr}
  .split-explainer .arrow{transform:rotate(90deg);padding:.3rem}
  .rowform{grid-template-columns:1fr 1fr}
  .top{padding:.9rem 1rem}
  .person-head{flex-direction:column;align-items:flex-start}
  table{font-size:.85rem}
  th,td{padding:.55rem .6rem}
}
@media(max-width:480px){
  .stats{grid-template-columns:1fr 1fr}
  .rowform{grid-template-columns:1fr}
  .records thead{display:none}
  .records tr{display:grid;grid-template-columns:1fr 1fr;gap:.2rem;padding:.55rem .65rem;border-bottom:1px solid var(--line)}
  .records td{border:0;padding:.15rem 0}
}

/* Hierarchie-Prototyp: einklappbarer Baum statt Wand aus offenen Formularen */
.hnode > summary{cursor:pointer;font-weight:700;padding:.5rem .4rem;list-style:none;display:flex;align-items:center;gap:.5rem}
.hnode > summary::-webkit-details-marker{display:none}
.hnode > summary::before{content:"▸";color:var(--muted);font-size:.75em;display:inline-block;transition:transform var(--dur) var(--ease);flex:0 0 auto}
.hnode[open] > summary::before{transform:rotate(90deg)}
.hnode > summary:hover{background:var(--surface-2);border-radius:8px}
.hsummary-text{flex:1;min-width:0}
.hnode-del{flex:0 0 auto;margin:0}
.hbadge{background:var(--surface-2);border:1px solid var(--line);color:var(--muted);font-size:.68rem;text-transform:uppercase;letter-spacing:.04em;padding:.1rem .45rem;border-radius:999px;font-weight:700}
/* Markiert frei erfundene Test-Schloesser (keine echte TTLock-Gegenstelle) - amber statt neutral,
   damit sie im Live-Betrieb nie mit echten Schloessern verwechselt werden. */
.testbadge{background:var(--cloud-bg);border:1px solid var(--cloud);color:var(--cloud-ink);font-size:.68rem;text-transform:uppercase;letter-spacing:.04em;padding:.1rem .45rem;border-radius:999px;font-weight:700}
.hcount{color:var(--muted);font-weight:500;font-size:.82rem}
.hbody{padding:.1rem 0 .7rem .15rem}

/* Bereiche (oberste Ebene): eigene, klar umrandete Karte mit spuerbarem Abstand zueinander -
   verhindert, dass mehrere Bereiche optisch ineinanderlaufen. */
.hnode-top{
  background:var(--surface);border:1px solid var(--line);border-left:4px solid var(--ink);
  border-radius:var(--radius);padding:.1rem 1rem .5rem;margin:0 0 1.2rem;box-shadow:var(--shadow-sm);
}
.hnode-top > summary{font-size:1.03rem;padding:.65rem .3rem}
.hnode-top > .hbody{padding-left:.25rem}
html.dark .hnode-top{border-left-color:var(--local)}

/* Unterbereiche/Zonen: schlanker und erkennbar "untergeordnet", mit Trennlinie zwischen
   Geschwister-Knoten derselben Ebene statt nur minimalem Abstand. Verbindungslinie kraeftiger
   (var(--line) statt --line-soft) und deutlich mehr Innenabstand, damit die Verschachtelung
   auch ohne die zusaetzliche Tiefen-Einrueckung (siehe access_render_nodes()) klar erkennbar ist. */
.hnode-nested{border-left:2px solid var(--line);margin:.7rem 0;padding-left:1.3rem}
.hnode-nested + .hnode-nested{border-top:1px dashed var(--line-soft);padding-top:.7rem;margin-top:0}
.hnode-nested > summary{font-size:.93rem;font-weight:600}

.hbadge-bereich{background:var(--ink);border-color:var(--ink);color:var(--surface)}
.hbadge-unterbereich{background:var(--surface-2);color:var(--ink-soft)}
.hbadge-zone{background:transparent;color:var(--muted-2)}
.hlockrow{display:flex;flex-wrap:wrap;gap:.5rem;align-items:center;margin-bottom:.6rem}
.hlock{display:inline-flex;align-items:center;gap:.3rem}
.hlock-form{display:inline}
/* Weiterhin genutzt fuer "Knoten loeschen" und "Mitarbeiter aus Knoten entfernen" (einzelnes x,
   kein Chip-Paar noetig) - nicht mit den Lock-Aktionen unten verwechseln. */
.hlock-x{background:transparent;border:0;cursor:pointer;color:var(--muted);font-weight:700;padding:.1rem .3rem;font-size:.95rem;line-height:1;border-radius:var(--radius-xs)}
.hlock-x:hover{background:var(--danger-bg);color:var(--danger-ink)}
.hlock-x-danger{color:var(--danger-ink);opacity:.75}
.hlock-x-danger:hover{opacity:1}
/* Kompaktes "..."-Menu statt permanent ausgeschriebener "Nur hier"/"Ueberall"-Buttons - bei vielen
   geteilten Schloessern (Tor-Fall) summierte sich der Text sonst pro Schloss auf und liess die Zeile
   umbrechen. Der volle, eindeutige Text steht jetzt nur noch im aufgeklappten Dropdown. */
.hlockmenu{position:relative;display:inline-flex}
.hlockmenu summary{
  list-style:none;cursor:pointer;width:20px;height:20px;display:inline-flex;align-items:center;
  justify-content:center;border-radius:var(--radius-xs);color:var(--muted);font-weight:700;line-height:1;
}
.hlockmenu summary::-webkit-details-marker{display:none}
.hlockmenu summary:hover{background:var(--paper);color:var(--ink)}
.hlockmenu[open] summary{background:var(--paper);color:var(--ink)}
.hlockmenu-body{
  position:absolute;top:calc(100% + .3rem);right:0;z-index:20;min-width:220px;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-md);box-shadow:var(--shadow-sm);
  padding:.35rem;display:flex;flex-direction:column;gap:.15rem;
}
.hlockmenu-body .actionchipform{width:100%}
.hlockmenu-body .actionchip{width:100%;justify-content:flex-start;background:transparent;border-color:transparent}
/* Gleiche Dropdown-Optik, aber der Ausloeser hat hier ein Text-Label ("+ Schloss") statt nur "..." -
   braucht deshalb eine variable statt fixer 20px Breite. */
.addlockmenu summary{width:auto;padding:.15rem .5rem;font-size:.78rem;font-weight:600;white-space:nowrap}
.addlockmenu .hlockmenu-body{min-width:200px}
.addlockmenu .inline-assign{display:flex;flex-direction:column;gap:.35rem}
.addlockmenu select{margin:0}
/* Eigene Zeile unter den Schloss-Chips (Transponder-Tabelle) - immer an derselben Stelle,
   statt im flex-wrap der Chips mitzuschwimmen und je nach Zeilenumbruch woanders zu landen. */
.addlockrow{margin-top:.4rem}
.hlockmenu-body .chip-muted:hover{background:var(--surface-2);border-color:var(--line)}
.hlockmenu-body .chip-danger:hover{background:var(--danger-bg);border-color:var(--danger)}
.hlock-add{display:inline-flex;gap:.35rem;align-items:center}
.hlock-add select{width:auto;margin:0;padding:.4rem .6rem;font-size:.86rem}
.hcreate{margin-top:.35rem}
.hcreate summary{cursor:pointer;color:var(--local-ink);font-size:.82rem;font-weight:700;list-style:none}
.hcreate summary::-webkit-details-marker{display:none}
.hcreate summary::before{content:"";}
.hcreate[open]{background:var(--surface-2);border:1px solid var(--line);border-radius:10px;padding:.7rem .8rem;margin-top:.4rem}

/* ---------- Hierarchie-Redesign: Knoten-Karte (Kopf/Schloesser/Mitarbeiter/Aktionen) ---------- */

/* Ebene farblich unterscheidbar statt nur Helligkeitsstufen - bestehende Farb-Tokens
   wiederverwendet (lokal=Bereich, cloud=Unterbereich, neutral=Zone), keine neuen Farben. */
.hbadge-bereich{background:var(--local-bg);border-color:var(--local);color:var(--local-ink)}
.hbadge-unterbereich{background:var(--cloud-bg);border-color:var(--cloud);color:var(--cloud-ink)}
.hbadge-zone{background:var(--surface-2);border-color:var(--line);color:var(--muted)}
.hbadge-objekt{background:var(--ink);border-color:var(--ink);color:var(--surface)}
html.dark .hbadge-objekt{background:var(--local);border-color:var(--local);color:#0d1015}

/* Schloesser-/Aktions-Abschnitt je Knoten: kleines Label + Chips/Buttons darunter. */
.hsection{margin-bottom:.6rem}
.hsection:last-child{margin-bottom:0}

/* Objekt-Karte oben: eigene, deutlich abgesetzte Optik statt fast identisch zu den Bereichs-
   Karten darunter - farbiger Verlaufskopf + kraeftigerer Rahmen, damit "das ist die Wurzel"
   auf den ersten Blick klar ist. Kein <details> (nicht einklappbar - kurze, meist
   ueberschaubare Liste, Fokus liegt auf den Bereichen darunter). */
.hnode-object{
  padding-bottom:.5rem;border-width:2px;border-color:var(--ink);
  box-shadow:var(--shadow-md);margin-bottom:1.6rem;
}
html.dark .hnode-object{border-color:var(--local)}
.hobject-head{
  display:flex;align-items:center;gap:.6rem;font-weight:800;font-size:1.2rem;
  padding:.85rem 1rem;margin:-1px -1rem 0;border-radius:calc(var(--radius) - 1px) calc(var(--radius) - 1px) 0 0;
  background:var(--accent-grad);color:#fff;
}
.hobject-head .hbadge-objekt{background:rgba(255,255,255,.22);border-color:rgba(255,255,255,.4);color:#fff}
.htreetitle{margin-top:1.2rem}

/* Aktionszeile am Ende eines Knotens: Icon+Label-Chips statt gestapelter Textlinks. */
.hactions{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.7rem}
.hactions-top{margin:0 0 1.1rem}
/* .hlockmenu summary ist fuer den fixen 20px-"..."-Ausloeser gedacht - hier sitzt stattdessen
   ein voll bemessener .actionchip drin, braucht deshalb variable Groesse wie .addlockmenu. */
.hactionmenu summary{width:auto;height:auto;padding:0}
.actionchip{text-decoration:none}
button.actionchip{font:inherit}

/* Echtes Pop-up (natives <dialog>) fuer mehrfeldrige Formulare ("Verwalter ernennen") -
   das schmale .hlockmenu-body-Popover (~220px) hat 5 Formularfelder viel zu eng gequetscht.
   showModal()/close() sind eine Zeile Inline-JS, gleiches minimalistisches Muster wie die
   bestehenden onclick-Handler (Theme-Toggle, confirm()-Dialoge) im Rest der App. */
.hmodal{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-lg);
  padding:1.5rem;max-width:520px;width:calc(100vw - 2.4rem);box-shadow:var(--shadow-lg);
}
.hmodal::backdrop{background:rgba(10,13,18,.55)}
.hmodal h3{margin:0 0 1rem;font-size:1rem}
.hmodal .rowform{grid-template-columns:1fr 1fr}
.hmodal-actions{grid-column:1/-1;display:flex;justify-content:flex-end;gap:.5rem;margin-top:.3rem}
@media(max-width:480px){.hmodal .rowform{grid-template-columns:1fr}}
