: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}
/* Sicherheitsnetz gegen horizontales Aufreissen der GANZEN Seite auf schmalen Bildschirmen -
   einzelne breite Elemente (Tabellen etc.) scrollen gezielt in ihrer eigenen .tablewrap-Box
   (overflow-x:auto dort), das hier verhindert nur, dass irgendein uebersehenes/zukuenftiges
   Element den body selbst breiter als den Viewport macht. */
html{overflow-x:hidden}
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;overflow-x:hidden;
}
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:fixed statt sticky: haengt nicht von Flex-Stretch/Hoehen der Geschwister-Elemente
     (main) oder vom Overflow-Verhalten der Vorfahren ab, bleibt daher zuverlaessig beim Scrollen
     stehen. nav hat flex:1, dadurch bleiben Historie/Abmelden unten in der Sidebar. main bekommt
     unten margin-left in Sidebarbreite, damit der Inhalt nicht darunter verschwindet. */
  position:fixed;top:0;left:0;height:100vh;overflow-y:auto;
  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;margin-left:230px}
.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}
/* Personen-Seite: echte Inhalte (Namen, E-Mails, Notizen) brauchen in der 13-spaltigen Tabelle
   mehr Platz, als in 1120px lesbar Platz findet (siehe .widetable unten) - deshalb hier breiter.
   Die Tabelle braucht bei voll ausgeschriebenen Headern/Werten realistisch ca. 1700-1900px (siehe
   .widetable min-width-Summe unten), um alles ohne Abschneiden UND ohne unnoetiges horizontales
   Scrollen zu zeigen. 1900px als Deckel war dafuer zu knapp bemessen - auf normal breiten
   Desktop-Monitoren blieb trotz sichtbar freiem Platz rechts ein paar Pixel zu wenig Raum uebrig
   und .tablewrap scrollte trotzdem (siehe FIX_personen_layout.md, Problem 2, sowie Nutzer-Feedback
   "trotz viel Platz scrollt es noch"). Deckel deshalb spuerbar hoeher als der tatsaechliche Bedarf,
   damit auf breiteren Bildschirmen wirklich Luft bleibt statt knapp am Limit zu haengen. Das "Neue
   Person"-Formular (.newperson-panel) bleibt trotzdem auf normaler Breite, damit nur die Tabelle
   mehr Raum bekommt und nicht ungewollt auch das Formular auseinandergezogen wird. */
.content-tenants{max-width:2400px}
/* 1080px statt 900px: die Kopfzeile (.toprow) braucht neben Name/Vorname genug Raum fuer den
   Pseudonym-Block (Haekchen-Satz + Label + Input) in derselben Zeile, ohne zu quetschen. */
.newperson-panel{max-width:1080px}

.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)}
.badge.warn{background:var(--danger-bg);color:var(--danger-ink)}
.badge.frozen{background:var(--surface-2);color:var(--muted)}
.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)}

.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)}
/* Objekt-Gruppierung der Schloss-Chips (renderCardRow(), Transponder-Tab) - flex-basis:100%
   zwingt das Label in der flex-wrap-Zeile von .lockchips auf eine eigene Zeile, ohne das
   Chip-Layout selbst (flex-wrap normaler Chips) aufzubrechen. */
.lockobjgroup-label{flex-basis:100%;font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--muted);margin:.3rem 0 -.05rem}
.lockobjgroup-label:first-child{margin-top:0}
.chiploc{opacity:.75;font-weight:400}
.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;white-space:nowrap}
.assignedchip:hover{text-decoration:underline}
.assignedchip svg{flex:0 0 auto;color:var(--muted)}
/* "Zugeordnet zu"-Spalte (render_cards()) war zu schmal - table-layout:auto (kein .widetable
   hier) gab ihr als letzter, eher kurzer Spalte kaum Raum, "– nicht zugeordnet –" brach auf
   2 Zeilen um. min-width zwingt den Browser zu mehr Platz, ohne die anderen Spalten (Schlösser,
   die den meisten Raum brauchen) fest zu begrenzen. */
.assignedcol{min-width:12rem}
.nowrap{white-space:nowrap}
.valperm{color:var(--muted);font-weight:500} .valwin{color:var(--ink);font-weight:600} .valcyc{color:var(--local-ink);font-weight:700;font-size:.85rem}
/* Eine Zeile pro Schloss in der Gültigkeit-Zelle (renderCardRow()) - seit Schlösser desselben
   Transponders unterschiedliche Gültigkeit haben können, statt eines einzelnen aggregierten
   Werts. Kleiner Abstand zwischen den Zeilen, sonst kleben sie aneinander. */
.cardvalrow{margin:.1rem 0}
.cardvalrow:first-child{margin-top:0}
.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}
/* Gateway-Kommentar (in der schmalen .gwcard-Kachel): Text bekommt die volle Zeilenbreite zum
   Umbrechen, "ändern"+Stift sitzt rechtsbuendig DARUNTER statt nebendran gequetscht zu werden. */
.commentcell{display:flex;flex-direction:column;gap:.4rem}
.commentcell .commenttext{white-space:pre-line}
.commentcell details.periodedit{margin-top:0;align-self:flex-end}
.commentcell details.periodedit summary{display:inline-flex;align-items:center;gap:.3rem}
.commentcell details.periodedit summary::before{content:none}
.commentcell details.periodedit[open]{align-self:stretch}
/* Transponder-Nr.-Editor (renderCardRow()): eigenes Stift-Icon statt des Standard-Zahnrads
   (::before oben) - gleiche Loesung wie beim Gateway-Kommentar (.commentcell), nur ohne dessen
   Flex-Column-Wrapper, da diese Zelle keinen umbrechenden Fliesstext daneben hat. */
.internalnumedit summary{display:inline-flex;align-items:center;gap:.3rem}
.internalnumedit summary::before{content:none}
.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}

/* Gruppierungs-Ueberschriften im "Schloesser"-Tab (render_locks()): Objekt (h3, oberste Ebene)
   -> Gebaeude/Etage (eigene, kleinere Zwischenzeile je Untergruppe). */
.lockgroup-object{margin-top:1.4rem}
.content>.lockgroup-object:first-of-type{margin-top:0}
.lockgroup-sub{font-size:.78rem;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--muted);margin:.6rem 0 .5rem}
.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}

/* Gateway-Kacheln (Schlösser & Gateways-Reiter): breiter als .lockcard, da Name+Status+MAC+
   Objekt-Zeile+voller Kommentar-Editor+Lock-Chip-Liste gleichzeitig reinpassen muessen. Gleiche
   visuelle Sprache wie .stat/.lockcard (Border/Radius/Shadow/Hover-Lift). */
.gwcards{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:1rem;margin-bottom:1.8rem}
.gwcard{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:1.2rem 1.3rem;
  display:flex;flex-direction:column;gap:.85rem;box-shadow:var(--shadow-xs);
  transition:box-shadow var(--dur) var(--ease),transform var(--dur) var(--ease);
}
.gwcard:hover{box-shadow:var(--shadow-sm);transform:translateY(-1px)}
.gwcard-head{display:flex;align-items:center;justify-content:space-between;gap:.6rem}
.gwcard-head b{font-size:.98rem}
/* Jede Kachel-Zeile: kleines, dezentes Label oben, gut sichtbarer Wert darunter - sonst geht
   z.B. "Objekt" zwischen MAC-Adresse und Kommentar optisch unter. */
.gwcard-row{display:flex;flex-direction:column;gap:.3rem;padding-top:.6rem;border-top:1px solid var(--line)}
.gwcard-row > .rowlabel{text-transform:uppercase;letter-spacing:.04em;font-size:.72rem}
.gwcard-row .rowval{font-weight:600;color:var(--ink);font-size:.92rem}
/* Chip-Liste (Verbundene Schloesser) als EIN Flex-Child der .gwcard-row, damit die Chips
   nebeneinander umbrechen statt als lose Geschwister-Spans einzeln untereinander zu stehen. */
.chiprow{display:flex;flex-wrap:wrap;gap:.35rem}
/* Batterie-% inline in einem Lock-Chip (Gateway-Kachel) - dezenter als .lockcard .batt, da hier
   mehrere Chips pro Kachel nebeneinander stehen. */
.chipbatt{font-weight:700;color:var(--local-ink);font-size:.82rem}
.chipbatt.low{color:var(--danger-ink)}

/* Gateway->Schloss-Signalstaerke (RSSI in dBm) inline im Lock-Chip - schwaches Signal ist die
   haeufigste Ursache dafuer, dass ein Transponder/PIN-Code laut Cloud angelegt ist, aber nie am
   Schloss ankommt (Gateway-Push scheitert dann still, siehe TTLock::listLocksForGateway()). */
.chiprssi{font-weight:700;color:var(--muted);font-size:.82rem}
.chiprssi.weak{color:var(--danger-ink)}

.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);
}
/* h2{margin-top:1.8rem} (weiter unten) gilt global - ohne diese Ausnahme haengt die Ueberschrift
   in kurzen Panels (z.B. "Schlösser") durch den grossen Top-Abstand bei kleinem Bottom-Abstand
   (.9rem) optisch mittig statt oben im Rahmen. */
.panel > h2:first-child{margin-top:0}
/* App-Zugang (eKeys) als eigener, immer ausgeklappter Abschnitt unter der Personenliste (siehe
   render_tenants()/renderEkeysSection()). */
.ekeysection{margin-top:1.8rem}
.ekeysection > h2{margin:0 0 .9rem;display:flex;align-items:center;gap:.5rem}
label{display:block;font-size:.82rem;color:var(--muted);margin-bottom:.75rem;font-weight:500}
input,select,textarea{
  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,textarea:hover{border-color:var(--muted-2)}
input:focus,select:focus,textarea: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;gap:.3rem;vertical-align:middle;padding:.25rem .45rem}

.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}
/* Pfeil-Icon bewusst absolut positioniert (statt als Flex-Item vor dem Text) und leicht negativ
   ausgerueckt - sonst verschiebt das Icon den Textanfang nach rechts, wodurch "Unterschiedlich"
   NICHT mehr an derselben linken Kante startet wie das "ändern →" darunter (siehe .periodedit,
   das keinen Icon-Einzug hat) - genau der gemeldete "drei verschiedene Ausrichtungen"-Effekt in
   der Transponder-Tabelle, Spalte "Gültigkeit". So bleiben Summary-Text UND "ändern →" linksbündig
   auf derselben Kante, das Icon sitzt im Zellen-Padding links davor. */
.persondrop summary{
  cursor:pointer;list-style:none;color:var(--muted);font-size:.85rem;font-weight:600;
  padding:.4rem 0;position:relative;user-select:none;
}
.persondrop summary::-webkit-details-marker{display:none}
.persondrop summary::before{
  content:"›";position:absolute;left:-.75rem;top:50%;transform:translateY(-50%);
  font-size:1.1rem;line-height:1;transition:transform var(--dur) var(--ease);color:var(--muted-2);
}
.persondrop[open] summary::before{transform:translateY(-50%) rotate(90deg)}
.persondrop summary:hover{color:var(--ink)}
.persondrop summary .count{color:var(--muted-2);font-weight:500;margin-left:.4rem}
.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}

/* Person 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:stretch}
.newtenant label{margin-bottom:0}
/* Zeile 2 (Bereich/Zone, E-Mail, Telefon, Abteilung, Kennzeichen, Notiz): NUR die direkten
   Kind-Labels (".toprow" ist ein <div>, matcht ">label" ohnehin nicht - dessen Name/Vorname/
   Pseudonym-Labels haben ihr eigenes Sub-Grid, siehe unten) werden als Flex-Column mit dem Input
   bodenbuendig ausgerichtet, unabhaengig davon, wie viele Zeilen der Label-Text braucht (z.B.
   "Bereich/Zone (nur Organisation, kein Türzugang)" bricht auf 2 Zeilen um, die anderen Labels
   bleiben einzeilig). Vorher (align-items:center am Grid) wurden kuerzere Label+Input-Bloecke
   innerhalb der durch das laengste Label vorgegebenen Zeilenhoehe zentriert, wodurch die Inputs
   auf unterschiedlichen Hoehen starteten statt einheitlich - siehe visual-layout-audit.md Fall B. */
.newtenant>label{display:flex;flex-direction:column;justify-content:flex-end}
.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}
/* Kopfzeile Name/Vorname/Pseudonym-Block als eigenes 3-Spalten x 2-Zeilen-Sub-Grid statt Teil
   des auto-fill-Hauptgrids - garantiert diese feste Konstellation unabhaengig davon, wie viele
   Spalten das Hauptgrid bei aktueller Fensterbreite gerade bildet.
   Name, Vorname UND das Pseudonym-Feld selbst liegen alle gemeinsam in Zeile 2 (explizite
   grid-row, siehe :nth-child unten) - dadurch sind sie von Natur aus gleich hoch/bodenbuendig
   (kein align-items-Trick noetig, siehe FIX_personen_layout_2.md). Das Haekchen sitzt in Zeile 1.
   WICHTIG (siehe fix-neue-person-abstand.md): Zeile 1 ist eine gemeinsame Grid-Zeile ueber ALLE
   drei Spalten - ihre Hoehe richtet sich nach dem hoechsten Element, das dort liegt, auch wenn
   nur EINE Spalte dort ueberhaupt Inhalt hat. War das Haekchen nur in Spalte 3 (1/3 Breite), bricht
   sein langer Text auf 2-3 Zeilen um, macht Zeile 1 dadurch hoch - und diese Hoehe erschien als
   leerer Abstand über Name/Vorname (Spalte 1+2, dort ohne jeden Inhalt in Zeile 1), obwohl er
   inhaltlich nur zum Haekchen gehoert. Fix: Haekchen spannt jetzt die VOLLE Breite (grid-column:
   1/-1) statt nur Spalte 3 - der Text bricht dadurch auf deutlich weniger Zeilen um, Zeile 1 wird
   entsprechend niedriger. Name/Vorname/Pseudonym-Feld bleiben unveraendert in Zeile 2, exakt so
   angeordnet und bodenbuendig wie zuvor - nur der Platz darueber schrumpft. */
.newtenant .toprow{grid-column:1/-1;display:grid;grid-template-columns:1fr 1fr 1fr;grid-template-rows:auto auto;gap:.5rem 1.1rem}
.newtenant .toprow>*:nth-child(1){grid-column:1;grid-row:2} /* Name */
.newtenant .toprow>*:nth-child(2){grid-column:2;grid-row:2} /* Vorname */
.newtenant .toprow>*:nth-child(3){grid-column:1/-1;grid-row:1} /* Haekchen - volle Breite, siehe Kommentar oben */
.newtenant .toprow>*:nth-child(4){grid-column:3;grid-row:2} /* Pseudonym-Feld */
/* Kompakter als Standardtext, damit die Haekchen-Zeile nicht unnoetig hoch wirkt. */
.newtenant .hiderealdata{font-size:.84rem;line-height:1.4}
.req{color:var(--danger-ink);font-weight:700;margin-left:.2rem}
/* Mindestlaengen-Hinweis hinter dem Pseudonym-Label darf nie umbrechen - sonst wird das
   Label zweizeilig und zieht die ganze Grid-Zeile auseinander. */
.pseudohint{white-space:nowrap}
/* white-space:nowrap NUR auf dem Text-Span vor dem <input>, nicht auf dem ganzen Label:
   .pseudohint (siehe oben) verhinderte nur den Umbruch INNERHALB des Hinweis-Texts, das Label
   konnte aber trotzdem VOR dem Hinweis umbrechen ("Pseudonym*" / "(mind. 4 Zeichen)" auf 2
   Zeilen) und wurde dadurch zweizeilig/hoeher als die anderen Felder. Naheliegender erster Fix
   war nowrap auf .pseudolabel selbst - das brach aber den Zeilenumbruch VOR dem <input> mit
   (input hat width:100% und "rutscht" normalerweise per Inline-Umbruch automatisch in die
   naechste Zeile, siehe label{display:block} + input{width:100%} bei allen anderen Feldern
   ebenso) und quetschte Text+Feld in dieselbe Zeile. Nowrap deshalb nur auf .pseudolabeltext
   (umschliesst Label-Text + Pflichtfeld-Stern + Hinweis, aber NICHT das <input>) - der Umbruch
   vor dem Input bleibt erhalten, nur der Text selbst bricht nie mehr mitten drin um. */
.pseudolabel .pseudolabeltext{white-space:nowrap}
@media (max-width:640px){
  .newtenant{grid-template-columns:1fr}
  .newtenant .span2{grid-column:auto}
  /* Nur 1 Spalte auf Mobile - die expliziten grid-column/-row-Platzierungen oben (fuer die
     3-Spalten-Desktop-Anordnung) muessen hier zurueckgesetzt werden, sonst landen die Felder
     wegen grid-column:3 auf einer nicht existierenden Spalte statt normal untereinander in
     Markup-Reihenfolge (Name, Vorname, Haekchen, Pseudonym-Feld). */
  .newtenant .toprow{grid-template-columns:1fr}
  .newtenant .toprow>*:nth-child(1),.newtenant .toprow>*:nth-child(2),
  .newtenant .toprow>*:nth-child(3),.newtenant .toprow>*:nth-child(4){grid-column:1;grid-row: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(420px,calc(100vw - 2.2rem));
  display:flex;align-items:center;gap:.65rem;
  background:var(--local-bg);color:var(--local-ink);border:1px solid transparent;padding:.95rem 1.25rem;
  border-radius:var(--radius-md);font-size:1rem;font-weight:500;box-shadow:var(--shadow-sm);
  animation:flash-in .25s ease-out, flash-out .5s ease-in 3.5s forwards;
  overflow:hidden;
}
.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)}}
/* Ablaufbalken ("Strahl") am unteren Rand - laeuft synchron zur 3.5s-Sichtbarkeitsdauer oben
   herunter, direkt bevor flash-out die Box ausblendet. */
.flash::after{
  content:"";position:absolute;left:0;bottom:0;height:3px;width:100%;background:currentColor;
  opacity:.4;transform-origin:left;animation:flash-shrink 3.5s linear forwards;
}
@keyframes flash-shrink{from{transform:scaleX(1)}to{transform:scaleX(0)}}
.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%);
}
/* min() statt fixem width:330px - auf sehr schmalen Phones (<=320px CSS-Breite, z.B. aeltere/
   kleine Geraete) liesse eine feste Breite die Login-Karte seitlich ueber den Viewport hinausragen
   (330px + Body-Rand > 320px). calc(100vw - 2.4rem) laesst immer mindestens 1.2rem Luft je Seite. */
.login{background:var(--surface);padding:2.2rem;border-radius:18px;width:min(330px, calc(100vw - 2.4rem));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;max-height:none;overflow-y:visible;position:static;flex-direction:row;flex-wrap:wrap;align-items:center;gap:.3rem}
  main{margin-left:0}
  .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}
  .rowform{grid-template-columns:1fr 1fr}
  /* .top (Titel + "Angemeldet als"-Badge + Demo/Live-Badge + ggf. Einstellungen-Link +
     Theme-Toggle) hatte weder auf sich selbst noch auf .topright einen flex-wrap - auf schmalen
     Bildschirmen liefen Titel und die Badges/Buttons daneben dadurch aus dem sticky Header heraus
     statt umzubrechen. */
  .top{padding:.9rem 1rem;flex-wrap:wrap;row-gap:.6rem}
  .topright{flex-wrap:wrap}
  .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}
}
/* Alle Tabellen (.records/.mini/.list/.widetable) stecken jetzt in .tablewrap
   (overflow-x:auto) - eine Tabelle, die trotz kleinerer Schrift/Padding (siehe oben) auf
   schmalen Bildschirmen nicht mehr reinpasst, scrollt lokal innerhalb ihrer eigenen Box, statt
   die ganze Seite horizontal aufzureissen oder ueber den Rand zu laufen. Bewusst KEIN Wechsel
   auf ein Karten-Layout (Header ausblenden, Zeilen als 2-Spalten-Grid) mehr: ohne sichtbare
   Spaltenkoepfe waren die Werte nicht mehr zuzuordnen, bei Tabellen mit verschachtelten Formularen
   (Transponder-Zeilen, Editier-Menues) wirkte das zusammengequetscht statt lesbarer. */
/* Personen-Tabelle hat mit 13 Spalten (Person/Interne Nr./E-Mail/Telefon/Abteilung/Kennzeichen/
   Notiz/Transponder-Nr./Zeitsteuerung/Bereich-Zone/Zugaenge/Status/Aktion) deutlich mehr Felder
   als die anderen .records-Tabellen. table-layout:auto (NICHT fixed) + width:100%: Spaltenbreiten
   richten sich nach ihrem tatsaechlichen Inhalt/Header, keine feste %/px-Colgroup mehr, die
   Inhalte abschneiden konnte, sobald sie laenger als die starre Breite waren (siehe
   FIX_personen_layout.md, Problem 2 - vorher blieb rechts leerer Platz UND einzelne Zellen
   wurden trotzdem mit "…" abgeschnitten). Kein Ellipsis/nowrap mehr auf normalen Zellen - Werte
   brechen bei Bedarf um (white-space:normal). word-break:break-word statt overflow-wrap:anywhere:
   bricht nur, wenn ein einzelnes Wort wirklich nicht in die Spalte passt, nicht schon vorher
   mitten im Wort ("KEN NZEI CHE N", Badge "UNTERBEREI CH" war die fruehere overflow-wrap:anywhere-
   Variante). Breiten-Prioritaet kommt ueber min-width je Spalte (siehe nth-child-Regeln unten):
   Person/Bereich-Zone/Zugaenge breit, meist-leere Spalten (Abt./Kennz./Notiz/Interne Nr.) schmal -
   die zusaetzliche Breite geht an die Inhalts-Spalten, nicht gleichmaessig an alle. */
.widetable{table-layout:auto;width:100%}
.widetable th,.widetable td{white-space:normal;vertical-align:middle;word-break:break-word}
/* Spalten-Ueberschriften IMMER einzeilig (siehe FIX_personen_layout_2.md, Problem 2) - kein
   overflow:hidden/text-overflow:ellipsis dabei (kein "…"-Abschneiden), table-layout:auto
   verbreitert die Spalte stattdessen automatisch so weit, wie der Header-Text braucht. */
.widetable th{white-space:nowrap}
.widetable .hbadge,.widetable .rolechip,.widetable .pseudochip{white-space:nowrap}
/* Spalten-Prioritaet: breite Inhalts-Spalten bekommen einen groesseren Mindestwert, damit sie
   nicht auf das Minimum kollabieren, sobald andere Spalten Platz beanspruchen - min-width statt
   fester width, die Spalte darf bei Bedarf trotzdem weiter wachsen (siehe Abnahme-Kriterien
   FIX_personen_layout.md). Reihenfolge der Spalten siehe render_tenants() in index.php:
   1 Person, 2 Interne Nr., 3 E-Mail, 4 Telefon, 5 Abteilung, 6 Kennzeichen, 7 Notiz,
   8 Transponder-Nr., 9 Zeitsteuerung, 10 Bereich/Zone, 11 Zugaenge, 12 Status, 13 Aktionen. */
.widetable th:nth-child(1)  {min-width:200px} /* Person - breit */
.widetable th:nth-child(2)  {min-width:90px}  /* Interne Nr. - schmal */
.widetable th:nth-child(3)  {min-width:130px} /* E-Mail - mittel */
.widetable th:nth-child(4)  {min-width:110px} /* Telefon - mittel */
.widetable th:nth-child(5)  {min-width:80px}  /* Abteilung - schmal */
.widetable th:nth-child(6)  {min-width:80px}  /* Kennzeichen - schmal */
.widetable th:nth-child(7)  {min-width:90px}  /* Notiz - schmal */
.widetable th:nth-child(8)  {min-width:120px} /* Transponder-Nr. - mittel */
.widetable th:nth-child(9)  {min-width:145px} /* Zeitsteuerung - mittel, Zellinhalt (Link) braucht etwas mehr als der reine Header-Text */
/* Body-Zelle brauchte trotz breiterem Header noch minimal mehr Raum (der Link ".linkbtn" mit
   eigenem Padding ist etwas breiter als der reine Wort-Text) - nowrap zusaetzlich zum min-width
   verhindert, dass "Zeitsteuerung" dort trotzdem knapp umbricht. */
.widetable td:nth-child(9){white-space:nowrap}
.widetable th:nth-child(10) {min-width:250px} /* Bereich/Zone - breit, Name+Badge nie umbrechend */
.widetable th:nth-child(11) {min-width:190px} /* Zugaenge - breit */
.widetable th:nth-child(12) {min-width:100px} /* Status - mittel */
.widetable th:nth-child(13) {min-width:210px} /* Aktionen */
/* Person/Bereich-Zone kombinieren Name+Badge(s) in einer Zeile - .cellrow haelt sie in einer
   Reihe, .celltext (der Name) darf umbrechen, Badges/Chips bleiben als flex:0 0 auto immer
   vollstaendig und unverkleinert sichtbar. */
.widetable .cellrow{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap;min-width:0}
.widetable .cellrow .celltext{flex:1 1 auto;min-width:0}
.widetable .cellrow .rolechip,.widetable .cellrow .pseudochip,.widetable .cellrow .hbadge{flex:0 0 auto}
/* Bereich/Zone (siehe .nth-child(10) oben): Name + Badge sollen NIE umbrechen, uneinheitlich
   je nach Zeile mal ein-, mal zweizeilig sah unruhig aus (FIX_personen_layout_2.md, Problem 3).
   Die Spalte ist bewusst breit genug (min-width oben) fuer den laengsten realistischen Eintrag -
   anders als beim Personennamen (.cellrow ohne -nowrap), der bei extrem langen Namen lieber
   umbricht als die Spalte unbegrenzt in die Breite zu ziehen. */
.widetable .cellrow-nowrap{flex-wrap:nowrap}
.widetable .cellrow-nowrap .celltext{white-space:nowrap}
/* "verwalten" + "sperren"/"entsperren" nebeneinander in der Aktions-Spalte der Personenliste. */
.widetable .actioncell{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap}
/* Etwas schmaleres Padding als das normale .btn.small, damit "verwalten" + "sperren"/"entsperren"
   nebeneinander in die Spalte passen, ohne dass die Spalte unnoetig breit werden muss. */
.widetable .actioncell .btn.small{padding:.4rem .65rem}
.widetable .actioncell form{margin:0}
.tablewrap{overflow-x:auto}
/* Bei so vielen Spalten wird es auf sehr schmalen Bildschirmen (Handy quer/Tablet) trotzdem eng
   - dort lieber im .tablewrap horizontal scrollen (wie bei anderen breiten Tabellen im Tool)
   statt Inhalte zu quetschen. Ab ~700px reicht die volle Breite normalerweise wieder aus. */
@media(max-width:700px){
  .widetable{min-width:900px}
}

/* 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}
/* Schloss-Chip als kleine Karte statt reinem Text-Pill: Icon + Name + eigener runder ×-Button,
   dezenter Rahmen/Schatten mit Hover-Anhebung wie bei .lockcard/.stat - macht Schloesser auf
   der Access-Seite auf den ersten Blick als eigene, klickbare Einheiten erkennbar. */
.hlock{
  display:inline-flex;align-items:center;gap:.4rem;background:var(--surface);
  border:1px solid var(--line);border-radius:999px;padding:.28rem .3rem .28rem .65rem;
  box-shadow:var(--shadow-xs);transition:border-color var(--dur) var(--ease),box-shadow var(--dur) var(--ease),transform var(--dur) var(--ease);
}
.hlock:hover{border-color:var(--local);box-shadow:var(--shadow-sm);transform:translateY(-1px)}
.hlock .lockicon{flex:0 0 auto;color:var(--local-ink)}
.hlock .lockchip{background:transparent;border:0;padding:0;font-size:.83rem;font-weight:600;color:var(--ink);white-space:nowrap}
/* Geteiltes Schloss (haengt an mehreren Knoten) - Akzent in derselben Farbe wie das
   Unterbereich-Badge, damit "geteilt" auch ohne Hover/Tooltip auf einen Blick sichtbar ist. */
.hlock-shared{border-color:var(--cloud)}
.hlock-shared .lockicon{color:var(--cloud-ink)}
.hlock-form{display:inline-flex}
/* Weiterhin genutzt fuer "Knoten loeschen" und "Person 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;width:20px;height:20px;display:inline-flex;align-items:center;justify-content:center;font-size:.95rem;line-height:1;border-radius:999px;flex:0 0 auto;transition:background var(--dur) var(--ease),color var(--dur) var(--ease)}
.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/Personen/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)}

/* Optionales Bild je Knoten (siehe access_render_nodes()) - bewusst NUR ein Icon-Button
   ("Bild anzeigen", .actionchip wie die anderen Knoten-Aktionen), OHNE eingebettete Vorschau:
   eine winzige Miniatur des Fotos brachte optisch nichts, sichtbar ist das Bild ausschliesslich
   im per Klick geoeffneten Vollbild (.imgfull). */
.hnode-image{margin-bottom:.7rem}
/* Vollbild-Ansicht (Klick auf die Vorschau) - natives <dialog>, kein eigenes JS-Framework
   noetig. ::backdrop verdunkelt den Rest der Seite, Klick irgendwo im Dialog schliesst ihn
   wieder (siehe onclick in access_render_nodes()). */
.imgfull{padding:0;border:0;border-radius:var(--radius-md);background:transparent;max-width:95vw;max-height:95vh}
.imgfull::backdrop{background:rgba(10,13,18,.88)}
.imgfull img{display:block;max-width:95vw;max-height:95vh;border-radius:var(--radius-md);cursor:zoom-out}

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

.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. Kein
   eigenes padding:0 mehr - das schlug wegen hoeherer Selektor-Spezifitaet (Klasse+Element) das
   .actionchip-Padding tot und quetschte Icon+Label ohne Luft an den Rand ("Schloss zuordnen",
   "Neuen Bereich anlegen", "Knoten anlegen" betroffen). */
.hactionmenu summary{width:auto;height:auto}
.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}}

/* ---------- Personen-Detailseite-Redesign ---------- */
/* Alle Sektionen (Kopf/Gültigkeit/eKey/Transponder) als gleich abgesetzte Cards statt frei
   im .content schwebend - gleiche Optik wie .panel ueberall sonst, nur mehr Abstand
   dazwischen als das globale .panel margin-bottom (1.3rem), da diese Sektionen inhaltlich
   schwerer sind als ein normales Formular-Panel. */
.person-card{margin-bottom:1.8rem}
.person-card:last-of-type{margin-bottom:1.3rem}
.person-head{align-items:flex-start}
.person-heading{display:flex;flex-direction:column;gap:.35rem;min-width:0}
.person-name{font-size:1.25rem;font-weight:800;letter-spacing:-.01em;color:var(--ink)}
.person-sub{font-size:.88rem}
/* Bereich/Zone-Zeile: Icon + Text in einer Reihe statt reinem Fliesstext. */
.person-node{display:flex;align-items:center;gap:.4rem;margin-top:1rem}
.person-node svg{flex:0 0 auto;color:var(--muted-2)}

/* Segmented Control (Permanent/Zeitfenster/Zyklisch) - native Radios bleiben (name="mode"
   unveraendert), nur die Labels werden zu einer zusammenhaengenden Button-Reihe gestylt.
   Sichtbarkeit der abhaengigen .sub-window/.sub-cyclic-Bloecke rein per :has() - kein JS. */
.periodtype{margin-bottom:.9rem}
.segctl{display:inline-flex;border:1px solid var(--line);border-radius:var(--radius-sm);overflow:hidden;background:var(--surface-2)}
.segopt{position:relative;cursor:pointer;margin:0}
.segopt input{position:absolute;opacity:0;width:0;height:0}
.segopt span{display:inline-flex;align-items:center;padding:.55rem 1.1rem;font-size:.86rem;font-weight:600;color:var(--muted);transition:background var(--dur) var(--ease),color var(--dur) var(--ease)}
.segopt+.segopt span{border-left:1px solid var(--line)}
.segopt:has(input:checked) span{background:var(--ink);color:var(--surface)}
.segopt:has(input:focus-visible) span{box-shadow:var(--ring);position:relative;z-index:1}
.periodtype .sub-window,.periodtype .sub-cyclic{display:none;margin-top:.7rem}
.periodtype:has(#mode-window:checked) .sub-window{display:flex}
.periodtype:has(#mode-cyclic:checked) .sub-cyclic{display:flex}

/* "Erweitert: pro Schloss einzeln" (Personen-Detailseite) - eine .perlockrow pro Schloss, jede
   mit eigenem Modus/Zeitraum statt EINEM gemeinsamen fuer alle (siehe .periodtype oben). Gleiches
   :has()-Prinzip, aber ueber den radio-VALUE statt eine feste ID gescoped (name="mode[LID]" ist
   pro Zeile unterschiedlich, id waere es nicht ohne PHP-seitig eindeutige IDs zu erzeugen). */
.perlockrow{border:1px solid var(--line);border-radius:var(--radius-sm);padding:.8rem .9rem;margin-bottom:.7rem;background:var(--surface-2)}
.perlockrow .segctl{margin-top:.5rem}
.perlockrow .sub-window,.perlockrow .sub-cyclic{display:none;margin-top:.7rem}
.perlockrow:has(input[value="window"]:checked) .sub-window{display:flex}
.perlockrow:has(input[value="cyclic"]:checked) .sub-cyclic{display:flex}

/* Rollen-Auswahl bei "Verwalter-Login registrieren" (Einstellungen) - gleiches .segctl wie
   oben, nur je nach gewaehlter Rolle blendet sich das passende Objekt-/Bereich-/Unterbereich-
   Auswahlfeld ein statt alle drei gleichzeitig zu zeigen (Admin braucht gar keins). */
.rolepicker{margin-bottom:.9rem}
.rolepicker .scope-objekt,.rolepicker .scope-bereich,.rolepicker .scope-unterbereich{display:none;margin-top:.7rem}
.rolepicker:has(#role-objektverwalter:checked) .scope-objekt{display:block}
.rolepicker:has(#role-personal:checked) .scope-objekt{display:block}
.rolepicker:has(#role-bereichsverwalter:checked) .scope-bereich{display:block}
.rolepicker:has(#role-unterbereichsverwalter:checked) .scope-unterbereich{display:block}

/* "Gilt für"-Schlossauswahl als Toggle-Chips statt Checkbox-Liste - gleiches An/Aus-Feedback
   wie bei .segopt oben, nur als Mehrfachauswahl (Checkbox statt Radio) und Pill-Form. */
.chiptoggles{display:flex;flex-wrap:wrap;gap:.5rem;margin-bottom:1rem}
.chiptoggle{position:relative;cursor:pointer;margin:0}
.chiptoggle input{position:absolute;opacity:0;width:0;height:0}
.chiptoggle span{
  display:inline-flex;align-items:center;padding:.4rem .9rem;border:1px solid var(--line);
  border-radius:999px;font-size:.85rem;font-weight:600;color:var(--muted);background:var(--surface);
  transition:background var(--dur) var(--ease),border-color var(--dur) var(--ease),color var(--dur) var(--ease);
}
.chiptoggle:has(input:checked) span{background:var(--local);border-color:var(--local);color:#fff}
.chiptoggle:has(input:focus-visible) span{box-shadow:var(--ring)}

/* Wochentag-Toggle (Mo-So) fuer "Zyklisch" - eigene Klasse statt .wd (das bleibt fuer die
   Transponder-Uebersicht/renderCardRow() unveraendert, dort andere Formstruktur). */
.wdchips{display:flex;flex-wrap:wrap;gap:.4rem}
.wdchip{position:relative;cursor:pointer;margin:0}
.wdchip input{position:absolute;opacity:0;width:0;height:0}
.wdchip span{
  display:inline-flex;align-items:center;justify-content:center;width:2.3rem;height:2.3rem;
  border-radius:999px;border:1px solid var(--line);background:var(--surface);font-size:.78rem;
  font-weight:700;color:var(--ink-soft);transition:background var(--dur) var(--ease),border-color var(--dur) var(--ease),color var(--dur) var(--ease);
}
.wdchip:has(input:checked) span{background:var(--local);border-color:var(--local);color:#fff}
.wdchip:has(input:focus-visible) span{box-shadow:var(--ring)}

/* Kalender-/Uhr-Icon in Datum-/Zeitfeldern - gleiches Muster wie .personfilter input (Such-Icon). */
.periodtype input[type="date"]{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' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect x='3' y='4' width='18' height='18' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E") no-repeat .55rem center;padding-left:2rem}
.periodtype input[type="time"]{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' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E") no-repeat .55rem center;padding-left:2rem}

/* Info-Box (TTLock-Einschraenkungshinweis) statt loser Fliesstext-Absatz. */
.infobox{
  display:flex;gap:.6rem;align-items:flex-start;background:var(--surface-2);border:1px solid var(--line);
  border-radius:var(--radius-sm);padding:.7rem .9rem;font-size:.83rem;color:var(--muted);margin-top:.9rem;
}
.infobox svg{flex:0 0 auto;margin-top:.1rem;color:var(--muted-2)}

.formfooter{display:flex;justify-content:flex-end;margin-top:1rem}

/* eKey-Konto-Zeile als Definitions-Grid (Label oben klein, Wert darunter) statt Tabellenzeile -
   pro Konto ein Block, mehrere Konten (selten) stapeln sich einfach. */
.ekeyaccount{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:1rem;padding:1rem 0;border-bottom:1px solid var(--line-soft)}
.ekeyaccount:last-child{border-bottom:0;padding-bottom:0}
.ekeyaccount:first-child{padding-top:0}
.ekeyaccount .eklabel{display:block;text-transform:uppercase;letter-spacing:.04em;font-size:.68rem;color:var(--muted-2);margin-bottom:.35rem;font-weight:700}
.ekeyaccount .ekval{display:flex;align-items:center;flex-wrap:wrap;gap:.2rem}

.badge.temp{background:var(--cloud-bg);color:var(--cloud-ink)}

/* "Von"/"bis" vor den Datum-/Zeitfeldern (Gültigkeit ändern, Zeitfenster) - deutlich hervorgehoben
   statt im umgebenden .sub-Fliesstext (muted, klein) unterzugehen, damit auf einen Blick klar ist,
   welches Feldpaar Start und welches Ende ist. */
.fromto-label{color:var(--ink-soft);font-weight:700;font-size:.82rem}

/* Details/Summary mit echtem Icon (statt des Standard-Zahnrads per ::before) - gleiche Loesung
   wie .internalnumedit, nur als generische Klasse fuer mehrere Stellen (App-Zugang/Transponder). */
.periodedit-iconsummary summary{display:inline-flex;align-items:center;gap:.4rem}
.periodedit-iconsummary summary::before{content:none}
.periodedit-iconsummary summary svg{color:var(--local-ink)}
