/* ═══════════════════════════════════════════════
   Gate4All Portal — site.css v4
   Neutral grey base · Green accent only
   Dark + Light mode via [data-theme]
   ═══════════════════════════════════════════════ */

[data-theme="light"] {
  --sb-bg:        #1e2328;
  --sb-border:    #2d3540;
  --sb-text:      #8a9ab0;
  --sb-text-act:  #f0f4f8;
  --sb-hover:     rgba(255,255,255,.05);
  --sb-active:    rgba(34,197,94,.14);
  --sb-accent:    #22c55e;

  --bg:           #f0f2f5;
  --surface:      #ffffff;
  --surface-2:    #f5f7fa;
  --border:       #e2e8f0;
  --border-s:     #c8d4e0;
  --text:         #1a202c;
  --text-sub:     #4a5568;
  --text-muted:   #8a9ab0;
  --accent:       #16a34a;
  --accent-dim:   #15803d;
  --accent-glow:  rgba(22,163,74,.1);
  --danger:       #dc2626;
  --warn:         #d97706;
  --info:         #2563eb;
  --card-bg:      #ffffff;
  --input-bg:     #ffffff;
  --shadow:       0 1px 3px rgba(0,0,0,.08),0 4px 16px rgba(0,0,0,.04);
  --shadow-md:    0 4px 24px rgba(0,0,0,.1);
}

[data-theme="dark"] {
  --sb-bg:        #141820;
  --sb-border:    #222a36;
  --sb-text:      #7a8fa8;
  --sb-text-act:  #e8edf4;
  --sb-hover:     rgba(255,255,255,.04);
  --sb-active:    rgba(34,197,94,.12);
  --sb-accent:    #22c55e;

  --bg:           #0f1218;
  --surface:      #181e28;
  --surface-2:    #1e2634;
  --border:       #252e3e;
  --border-s:     #2e3a4e;
  --text:         #e2e8f4;
  --text-sub:     #94a3b8;
  --text-muted:   #5a6a80;
  --accent:       #22c55e;
  --accent-dim:   #16a34a;
  --accent-glow:  rgba(34,197,94,.1);
  --danger:       #f87171;
  --warn:         #fbbf24;
  --info:         #93c5fd;
  --card-bg:      #181e28;
  --input-bg:     #0f1218;
  --shadow:       0 1px 3px rgba(0,0,0,.3),0 4px 16px rgba(0,0,0,.2);
  --shadow-md:    0 8px 32px rgba(0,0,0,.4);
}

*,*::before,*::after { box-sizing:border-box; margin:0; padding:0; }

:root {
  --sb-w:   220px;
  --sb-col: 56px;
  --tr:     200ms cubic-bezier(.4,0,.2,1);
  --r:      6px;
  --r-lg:   10px;
  --hh:     72px;
}

html,body {
  height:100%;
  background:var(--bg);
  color:var(--text);
  font-family:Inter,system-ui,-apple-system,sans-serif;
  font-size:15px; line-height:1.55;
  transition:background .22s,color .22s;
}

a { color:var(--accent); text-decoration:none; }
a:hover { opacity:.8; }

::-webkit-scrollbar { width:5px; }
::-webkit-scrollbar-track { background:transparent; }
::-webkit-scrollbar-thumb { background:var(--border); border-radius:3px; }

/* ── Sidebar ── */
.sidebar {
  position:fixed; top:0; left:0; bottom:0;
  width:var(--sb-w);
  background:var(--sb-bg); border-right:1px solid var(--sb-border);
  display:flex; flex-direction:column;
  transition:width var(--tr); z-index:200; overflow:hidden;
}
.sidebar.sb-col { width:var(--sb-col); }

.sb-brand {
  height:var(--hh);
  display:flex; align-items:center; justify-content:flex-start;
  padding:0 .6rem; gap:.65rem;
  border-bottom:1px solid var(--sb-border);
  flex-shrink:0; overflow:hidden; white-space:nowrap; text-decoration:none;
}
/* Wide logo (symbol + wordmark, no tagline): fills the bar width. */
.sb-brand img.sb-logo-full { width:100%; max-width:196px; height:auto; max-height:52px; object-fit:contain; flex-shrink:0; }
/* Symbol-only mark, shown when the sidebar is collapsed. */
.sb-brand img.sb-logo-mark { height:30px; width:30px; object-fit:contain; flex-shrink:0; display:none; }
.sb-brand-name {
  font-size:.7rem; font-weight:700; letter-spacing:.14em; text-transform:uppercase;
  color:var(--sb-accent); transition:opacity var(--tr);
}
.sidebar.sb-col .sb-brand-name { opacity:0; }
/* Collapsed: swap full logo for the compact symbol, center it. */
.sidebar.sb-col .sb-brand { justify-content:center; padding:0; }
.sidebar.sb-col .sb-brand img.sb-logo-full { display:none; }
.sidebar.sb-col .sb-brand img.sb-logo-mark { display:block; }

.sb-toggle {
  position:absolute; top:14px; right:-12px;
  width:24px; height:24px;
  background:var(--sb-bg); border:1px solid var(--sb-border);
  border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  cursor:pointer; color:var(--sb-text); font-size:10px; z-index:10;
  transition:color var(--tr);
}
.sb-toggle:hover { color:var(--sb-accent); }

.sb-nav { flex:1; overflow-y:auto; overflow-x:hidden; padding:.5rem 0; }

.sb-grp {
  padding:.75rem 1rem .25rem;
  font-size:.58rem; font-weight:700; letter-spacing:.13em; text-transform:uppercase;
  color:var(--sb-border); white-space:nowrap; overflow:hidden;
  transition:opacity var(--tr),height var(--tr),padding var(--tr);
}
.sidebar.sb-col .sb-grp { opacity:0; height:0; padding:0; }

.sb-link {
  display:flex; align-items:center;
  padding:.48rem 1rem; gap:.7rem;
  color:var(--sb-text); font-size:.82rem; font-weight:500;
  white-space:nowrap; overflow:hidden;
  transition:color var(--tr),background var(--tr);
  position:relative; cursor:pointer; text-decoration:none;
}
.sb-link:hover { color:var(--sb-text-act); background:var(--sb-hover); text-decoration:none; }
.sb-link.sb-on { color:var(--sb-accent); background:var(--sb-active); }
.sb-link.sb-on::before {
  content:''; position:absolute; left:0; top:20%; bottom:20%;
  width:3px; background:var(--sb-accent); border-radius:0 3px 3px 0;
}
.sb-link i { font-size:15px; flex-shrink:0; width:20px; text-align:center; }
.sb-lbl { flex:1; transition:opacity var(--tr); }
.sidebar.sb-col .sb-lbl { opacity:0; }

.sb-chip {
  font-size:.52rem; font-weight:700; letter-spacing:.05em; text-transform:uppercase;
  padding:1px 5px; border-radius:3px;
  background:rgba(34,197,94,.12); color:var(--sb-accent);
  border:1px solid rgba(34,197,94,.2); flex-shrink:0;
  transition:opacity var(--tr);
}
.sidebar.sb-col .sb-chip { opacity:0; }

.sb-hr { height:1px; background:var(--sb-border); margin:.45rem 1rem; transition:margin var(--tr); }
.sidebar.sb-col .sb-hr { margin:.45rem .65rem; }

.sidebar.sb-col .sb-link::after {
  content:attr(data-tip); display:none;
  position:absolute; left:calc(var(--sb-col) - 2px); top:50%;
  transform:translateY(-50%);
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r); padding:.28rem .65rem;
  font-size:.78rem; color:var(--text); white-space:nowrap;
  box-shadow:var(--shadow-md); z-index:999;
}
.sidebar.sb-col .sb-link:hover::after { display:block; }

.sb-user {
  border-top:1px solid var(--sb-border);
  padding:.7rem 1rem .85rem;
  display:flex; flex-direction:column; gap:.55rem;
  overflow:hidden; flex-shrink:0;
}
.sb-user-row {
  display:flex; align-items:center; gap:.65rem;
  overflow:hidden;
}
.sb-av {
  width:30px; height:30px; border-radius:50%;
  background:var(--accent); color:#fff;
  border:1px solid var(--accent-dim);
  display:flex; align-items:center; justify-content:center;
  font-size:12px; font-weight:700; flex-shrink:0;
  text-decoration:none; cursor:pointer;
  transition:transform var(--tr),background var(--tr);
}
.sb-av:hover { transform:scale(1.08); background:var(--accent-dim); }
.sb-uinfo { flex:1; overflow:hidden; transition:opacity var(--tr); }
.sidebar.sb-col .sb-uinfo { opacity:0; }
.sb-uname { font-size:.76rem; font-weight:600; color:var(--sb-text-act); white-space:nowrap; }
.sb-urole { font-size:.63rem; color:var(--sb-text); }
.sb-out {
  color:var(--sb-text); font-size:13px; cursor:pointer; flex-shrink:0;
  display:inline-flex; align-items:center; justify-content:center; gap:.4rem;
  background:none; border:1px solid var(--sb-border); border-radius:7px;
  padding:.4rem .6rem; width:100%;
  transition:color var(--tr),opacity var(--tr),background var(--tr),border-color var(--tr);
}
.sb-out-lbl { font-size:12px; font-weight:600; }
.sidebar.sb-col .sb-out { opacity:0; pointer-events:none; height:0; padding:0; border:0; }
.sidebar.sb-col .sb-out-lbl { display:none; }
.sb-out:hover {
  color:#fff; background:var(--danger); border-color:var(--danger);
}

/* ── Main ── */
.g4-main {
  margin-left:var(--sb-w);
  transition:margin-left var(--tr);
  min-height:100vh; display:flex; flex-direction:column;
}
.g4-main.sb-col { margin-left:var(--sb-col); }

/* ── Page header ── */
.g4-ph {
  height:var(--hh);
  background:var(--surface); border-bottom:1px solid var(--border);
  display:flex; align-items:center; justify-content:space-between;
  padding:0 1.5rem; gap:1rem;
  position:sticky; top:0; z-index:100;
  box-shadow:var(--shadow);
}
.g4-ph-left { display:flex; align-items:baseline; gap:.5rem; }
.g4-ph-title {
  font-size:.88rem; font-weight:700; color:var(--text);
  display:flex; align-items:center; gap:.45rem;
}
.g4-ph-title i { color:var(--text-muted); font-size:15px; }
.g4-ph-sub { font-size:.75rem; color:var(--text-muted); }
.g4-ph-right { display:flex; align-items:center; gap:.6rem; }

/* ── Live pill ── */
.g4-live {
  display:inline-flex; align-items:center; gap:.32rem;
  padding:.2rem .6rem; border-radius:20px;
  background:var(--accent-glow); border:1px solid rgba(22,163,74,.2);
  font-size:.64rem; font-weight:700; letter-spacing:.07em; text-transform:uppercase;
  color:var(--accent);
}
[data-theme="dark"] .g4-live { border-color:rgba(34,197,94,.2); }
.g4-live-dot { width:6px;height:6px;border-radius:50%;background:var(--accent);animation:blink 2s infinite; }
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:.25} }

/* "Last active" relative timestamp + online dot (see localize-time.js /
   TimeHtmlHelper.RelativeTime). The dot is an inline marker shown only when the
   user was active within the online window; it pulses like the other live dots
   in the app. When online, the whole label leans on the accent colour so the
   row reads as "active now" at a glance. */
.g4-reltime { white-space:nowrap; }
.g4-reltime.g4-is-online { color:var(--accent); font-weight:600; }
.g4-online-dot {
  display:inline-block; width:7px; height:7px; border-radius:50%;
  background:var(--accent); margin-right:.4rem; vertical-align:baseline;
  animation:blink 2s infinite;
}
.g4-live.disconnected .g4-live-dot { background:var(--danger); animation:none; }

/* ── Client switcher ── */
.g4-csw { position:relative; }
.g4-csw-btn {
  display:flex; align-items:center; gap:.45rem;
  padding:.28rem .75rem;
  background:var(--surface-2); border:1px solid var(--border);
  border-radius:var(--r); color:var(--text-sub);
  font-size:.77rem; font-weight:500; cursor:pointer; white-space:nowrap;
  transition:border-color var(--tr);
}
.g4-csw-btn:hover { border-color:var(--border-s); color:var(--text); }
.g4-csw-dd {
  display:none; position:absolute; right:0; top:100%;
  /* Bridge the visual gap with a transparent top padding instead of a real
     margin/offset. A literal 5px gap (top: calc(100% + 5px)) left a dead zone
     between the button and the menu, so moving the cursor across it dropped the
     :hover and the menu snapped shut. The padding keeps the whole path
     hoverable; background-clip stops the padding from being painted. */
  padding-top:6px; background-clip:padding-box;
  min-width:200px; background:var(--surface);
  border:1px solid var(--border); border-radius:var(--r);
  overflow:hidden; box-shadow:var(--shadow-md); z-index:999;
}
/* Keep the dropdown open while the cursor is over EITHER the button or the
   menu (and during the move between them). */
.g4-csw:hover .g4-csw-dd,
.g4-csw-dd:hover { display:block; }
.g4-csw-dd a {
  display:flex; align-items:center; gap:.5rem;
  padding:.48rem .9rem; color:var(--text-sub); font-size:.78rem;
  transition:background var(--tr),color var(--tr);
}
.g4-csw-dd a:hover { background:var(--surface-2); color:var(--text); text-decoration:none; }

/* ── Icon button ── */
.g4-icon-btn {
  width:30px; height:30px;
  background:var(--surface-2); border:1px solid var(--border);
  border-radius:var(--r);
  display:flex; align-items:center; justify-content:center;
  cursor:pointer; color:var(--text-muted); font-size:14px;
  transition:color var(--tr),border-color var(--tr);
}
.g4-icon-btn:hover { color:var(--text); border-color:var(--border-s); }

/* ── Content ── */
.g4-content { padding:1.5rem; flex:1; }

/* ── Stat cards ── */
.g4-stats { display:grid; grid-template-columns:repeat(auto-fit,minmax(148px,1fr)); gap:.9rem; margin-bottom:1.25rem; }
.g4-sc {
  background:var(--card-bg); border:1px solid var(--border);
  border-radius:var(--r-lg); padding:1rem 1.1rem;
  display:flex; flex-direction:column; gap:.3rem;
  transition:box-shadow var(--tr),border-color var(--tr);
}
.g4-sc:hover { box-shadow:var(--shadow); border-color:var(--border-s); }
.g4-sc.hi { border-color:rgba(22,163,74,.3); }
[data-theme="dark"] .g4-sc.hi { border-color:rgba(34,197,94,.25); }
.g4-sc-row { display:flex; align-items:center; justify-content:space-between; }
.g4-sc-lbl { font-size:.63rem; font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--text-muted); }
.g4-sc-ico { font-size:1rem; color:var(--text-muted); }
.g4-sc.hi .g4-sc-ico { color:var(--accent); }
.g4-sc-val { font-size:2rem; font-weight:800; color:var(--text); line-height:1; letter-spacing:-.03em; }
.g4-sc.hi .g4-sc-val { color:var(--accent); }

/* ── Card ── */
.g4-card {
  background:var(--card-bg); border:1px solid var(--border);
  border-radius:var(--r-lg); overflow:hidden; box-shadow:var(--shadow);
  margin-bottom:1.25rem;
}
.g4-card-hd {
  padding:.7rem 1rem; border-bottom:1px solid var(--border);
  display:flex; align-items:center; justify-content:space-between;
  background:var(--surface-2);
}
.g4-card-title {
  font-size:.7rem; font-weight:700; letter-spacing:.09em; text-transform:uppercase;
  color:var(--text-muted); display:flex; align-items:center; gap:.4rem;
}
.g4-card-meta { font-size:.74rem; color:var(--text-muted); }

/* ── Table ── */
.g4-table { width:100%; border-collapse:collapse; }

/* A card whose rows carry hover tooltips (.g4-tip) must not clip them at the
   top/bottom edge. The card normally has overflow:hidden for its rounded
   corners; this opts a specific card out so a tooltip on the first/last row is
   fully visible. Rows are rectangular and sit inside the corner radius, so the
   visual rounding is unaffected in practice. */
.g4-card-tips { overflow:visible; }

/* Table scroll host used together with .g4-card-tips. On the desktop the table
   fits, so keep overflow visible — otherwise overflow-x:auto would also clip
   tooltips vertically. On narrow screens (handled in the mobile block) it turns
   back into a horizontal scroller. */
.g4-table-scroll { overflow:visible; }
.g4-table thead th {
  padding:.52rem .9rem;
  font-size:.64rem; font-weight:700; letter-spacing:.09em; text-transform:uppercase;
  color:var(--text-muted); border-bottom:1px solid var(--border); white-space:nowrap; text-align:left;
}
.g4-table tbody td {
  padding:.62rem .9rem; border-bottom:1px solid var(--border);
  color:var(--text); vertical-align:middle; font-size:.82rem;
}
.g4-table tbody tr:last-child td { border-bottom:none; }
.g4-table tbody tr { transition:background var(--tr); }
.g4-table tbody tr:hover { background:var(--surface-2); }

/* ── Badges ── */
.g4-badge {
  display:inline-flex; align-items:center; gap:.25rem;
  padding:.18rem .52rem; border-radius:20px;
  font-size:.63rem; font-weight:700; letter-spacing:.05em; text-transform:uppercase;
}
.g4-badge-on  { background:rgba(22,163,74,.1);  color:#15803d; border:1px solid rgba(22,163,74,.25); }
[data-theme="dark"] .g4-badge-on { background:rgba(34,197,94,.1); color:#4ade80; border-color:rgba(34,197,94,.2); }
.g4-badge-off { background:rgba(107,114,128,.1); color:#6b7280; border:1px solid rgba(107,114,128,.2); }
[data-theme="dark"] .g4-badge-off { color:#94a3b8; border-color:rgba(148,163,184,.2); }
.g4-badge-info { background:rgba(37,99,235,.08); color:var(--info); border:1px solid rgba(37,99,235,.2); }

/* Zwei gleich breite Karten nebeneinander, auf schmalen Schirmen untereinander.
   Eingeführt für die Freigabe-Seite (importieren neben „mit uns geteilt"). */
.g4-grid-2 { display:grid; grid-template-columns:1fr 1fr; gap:1.25rem; align-items:start; }
@media (max-width: 900px) { .g4-grid-2 { grid-template-columns:1fr; } }
.g4-badge-warn { background:rgba(217,119,6,.08); color:var(--warn); border:1px solid rgba(217,119,6,.2); }
/* Fehlerstufe im Server-Log. Bewusst eine eigene Klasse: g4-badge-off ist grau
   und bedeutet "inaktiv", nicht "Fehler". */
.g4-badge-err { background:rgba(220,38,38,.1); color:#dc2626; border:1px solid rgba(220,38,38,.25); }
[data-theme="dark"] .g4-badge-err { background:rgba(248,113,113,.1); color:#f87171; border-color:rgba(248,113,113,.22); }
.g4-bd-dot { width:5px;height:5px;border-radius:50%;background:currentColor; }
.g4-badge-on .g4-bd-dot { animation:blink 2s infinite; }

/* ── Buttons ──
   One consistent control height across the app. The base .g4-btn and the
   (heavily used) .g4-btn-sm intentionally share the same vertical size, so a
   primary button and a ghost button sitting side by side line up — buttons vary
   by COLOUR and weight, not by height. .g4-btn-sm only trims horizontal padding
   for dense toolbars/rows; it is not visibly "smaller". Emphasis comes from
   .g4-btn-primary, not from size. */
.g4-btn {
  display:inline-flex; align-items:center; justify-content:center; gap:.4rem;
  padding:.42rem .9rem; border-radius:var(--r);
  font-size:.8rem; font-weight:500; cursor:pointer; line-height:1.2;
  border:1px solid transparent; transition:all var(--tr); white-space:nowrap;
  text-decoration:none;
}
.g4-btn:hover { text-decoration:none; }
.g4-btn:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
.g4-btn-primary {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent-dim);
  font-weight: 600;
  box-shadow: 0 1px 3px rgba(0,0,0,.15);
}
.g4-btn-primary:hover { background: var(--accent-dim); border-color: var(--accent-dim); color: #fff; opacity:1; }
[data-theme="light"] .g4-btn-primary { background: #15803d; border-color: #166534; }
[data-theme="light"] .g4-btn-primary:hover { background: #166534; }
.g4-btn-ghost { background:transparent; color:var(--text-sub); border-color:var(--border); }
.g4-btn-ghost:hover { border-color:var(--border-s); color:var(--text); }
.g4-btn-danger { background:transparent; color:var(--danger); border-color:rgba(220,38,38,.3); }
.g4-btn-danger:hover { background:rgba(220,38,38,.08); }
/* Secondary = a filled neutral button, between primary and ghost in weight. */
.g4-btn-secondary { background:var(--surface-2); color:var(--text); border-color:var(--border); }
.g4-btn-secondary:hover { border-color:var(--border-s); background:var(--surface); }
/* Same height as the base button — only less horizontal padding, for rows and
   toolbars where several controls sit together. */
.g4-btn-sm { padding:.42rem .7rem; font-size:.78rem; }

/* Icons inside buttons render one step larger than the label text, so the
   Bootstrap glyphs stay legible. In icon-only buttons they go a little larger
   still, since there's no text to carry the meaning. */
.g4-btn i { font-size:1.1em; line-height:1; }
.g4-btn-icon i { font-size:1.2rem; }

/* Icon-only button: a square-ish hit area so a lone icon is easy to tap on
   touch screens and clearly a control, not just a glyph. min-height matches the
   text buttons' computed height (padding + line-height + border) so an icon
   button and a text button in the same row line up flush; min-width keeps it
   square. Use with .g4-btn (+ optional -sm). */
.g4-btn-icon {
  padding:.42rem; min-width:2rem; min-height:2rem; justify-content:center;
}

/* Row action cluster: gives the little icon buttons breathing room instead of
   letting them collide. Wraps on narrow screens. */
.g4-actions { display:inline-flex; align-items:center; gap:.4rem; flex-wrap:wrap; }

/* ── Generic hover tooltip ─────────────────────────────────────────────────
   Add class="g4-tip" plus data-tip="Label" to ANY element to get a small
   label on hover/focus. Built for the icon-only action buttons so a user can
   tell what each does without a manual, but works on anything. CSS-only, no JS.
   The host needs position:relative; .g4-btn already qualifies via its own
   rules, so set it here defensively. */
.g4-tip { position:relative; }
.g4-tip::after {
  content:attr(data-tip);
  position:absolute; top:calc(100% + 7px); left:50%; transform:translateX(-50%);
  background:var(--text); color:var(--bg);
  font-size:.72rem; font-weight:600; letter-spacing:.01em; line-height:1;
  padding:.35rem .5rem; border-radius:6px; white-space:nowrap;
  box-shadow:var(--shadow-md); pointer-events:none;
  opacity:0; visibility:hidden; transition:opacity .12s ease, visibility .12s ease;
  z-index:1000;
}
/* Little arrow above the bubble, pointing up at the control. */
.g4-tip::before {
  content:""; position:absolute; top:calc(100% + 2px); left:50%;
  transform:translateX(-50%);
  border:5px solid transparent; border-bottom-color:var(--text);
  opacity:0; visibility:hidden; transition:opacity .12s ease, visibility .12s ease;
  z-index:1000; pointer-events:none;
}
.g4-tip:hover::after, .g4-tip:focus-visible::after,
.g4-tip:hover::before, .g4-tip:focus-visible::before {
  opacity:1; visibility:visible;
}

/* Touch devices have no reliable hover, so a hover-only tooltip would leave the
   icon buttons unlabelled — the exact problem tooltips were meant to solve. On a
   narrow, touch, stacked-table screen (phones, portrait tablets) an icon button
   in an action cell shows its data-tip as a persistent inline label beside the
   icon instead of a hover bubble. Wide touch tablets keep the tap-to-reveal
   bubble so the table columns don't widen. */
@media(hover:none) and (max-width:992px){
  .g4-actions .g4-btn-icon.g4-tip,
  td .g4-btn-icon.g4-tip {
    min-width:0; width:auto; gap:.4rem; padding-left:.6rem; padding-right:.7rem;
  }
  .g4-actions .g4-btn-icon.g4-tip::after,
  td .g4-btn-icon.g4-tip::after {
    content:attr(data-tip);
    position:static; transform:none; opacity:1; visibility:visible;
    background:none; color:inherit; box-shadow:none; padding:0;
    font-size:.78rem; font-weight:500; white-space:nowrap;
  }
  .g4-actions .g4-btn-icon.g4-tip::before,
  td .g4-btn-icon.g4-tip::before { display:none; }   /* no bubble arrow */
}

/* ── Forms ── */
.g4-form-group { margin-bottom:1rem; }
.g4-label { display:block; margin-bottom:.3rem; font-size:.75rem; font-weight:500; color:var(--text-muted); }
.g4-input {
  width:100%; padding:.48rem .75rem;
  background:var(--input-bg); border:1px solid var(--border);
  border-radius:var(--r); color:var(--text); font-size:.82rem;
  transition:border-color var(--tr),box-shadow var(--tr); outline:none;
}
.g4-input:focus { border-color:var(--accent-dim); box-shadow:0 0 0 3px var(--accent-glow); }
.g4-input::placeholder { color:var(--text-muted); opacity:.6; }

/* ── Alerts ── */
.g4-alert {
  padding:.6rem 1rem; border-radius:var(--r);
  font-size:.8rem; border:1px solid transparent; margin-bottom:.75rem;
}
.g4-alert-success { background:rgba(22,163,74,.08); border-color:rgba(22,163,74,.2); color:var(--accent); }
.g4-alert-danger  { background:rgba(220,38,38,.07); border-color:rgba(220,38,38,.2); color:var(--danger); }
.g4-alert-warn    { background:rgba(217,119,6,.07);  border-color:rgba(217,119,6,.2);  color:var(--warn); }

/* ── Utilities ── */
.g4-mono   { font-family:'JetBrains Mono','Fira Code',monospace; font-size:.76rem; }
.g4-muted  { color:var(--text-muted); }
.g4-sub    { color:var(--text-sub); }
.g4-accent-text { color:var(--accent); font-weight:600; }

/* ── Responsive ── */
/* ── Mobile menu button (hidden on desktop, shown on mobile) ── */
.g4-mob-menu {
  display:none;
  background:none; border:none; cursor:pointer;
  color:var(--text); font-size:1.4rem; padding:.2rem .5rem .2rem 0;
  line-height:1;
}

/* ── Layout utilities ───────────────────────────────────────────────────
   The views were written against Bootstrap's grid and spacing helpers, but
   Bootstrap is never loaded — the layout only pulls in site.css. So `.row`,
   `.col-lg-6`, `.d-flex`, `.gap-2`, `.me-1` and friends were inert class
   names: cards stacked full width, action bars ignored justify-content-end,
   and every icon sat flush against its label.

   Rather than pulling in the whole framework (which would fight the g4-*
   design and, per the TODO, leak user IPs via a CDN), this is the exact
   subset the views actually use. Breakpoint lg = 992px, matching Bootstrap.
   A mobile override further down already assumed these existed. */
.row {
  display:flex; flex-wrap:wrap;
  margin-left:-.5rem; margin-right:-.5rem;
}
.row > [class^="col"], .row > [class*=" col"] {
  padding-left:.5rem; padding-right:.5rem;
  width:100%;
}
.row > .col { flex:1 0 0%; width:auto; }
.g-2 { row-gap:.5rem; }
.g-4 { row-gap:1.5rem; }

/* Unprefixed columns apply at every width (as in Bootstrap). The mobile
   override further down still collapses them to full width below 768px. */
.row > .col-4 { width:33.3333%; }
.row > .col-6 { width:50%; }
.row > .col-8 { width:66.6667%; }

/* Tablets (portrait) keep the fixed sidebar but leave less room for content, so
   a wide table can overrun. Let the scroll containers scroll horizontally from
   here down — the phone block below (≤768px) refines this further with the
   stacked card view for log tables. This only affects overflow, not the tooltip
   escape hatch, which matters on the desktop where tables fit. */
@media(max-width:992px){
  .g4-table-wrap,
  .g4-table-scroll,
  .g4-card [style*="overflow-x"] {
    overflow-x:auto; -webkit-overflow-scrolling:touch; max-width:100%;
  }
}

/* lg breakpoint = 992px, matching Bootstrap. */
@media(min-width:992px){
  .row > .col-lg-5 { width:41.6667%; }
  .row > .col-lg-6 { width:50%; }
  .row > .col-lg-7 { width:58.3333%; }
}

.d-flex  { display:flex; }
.d-none  { display:none; }
.gap-2   { gap:.5rem; }
.justify-content-end { justify-content:flex-end; }
.me-1 { margin-right:.25rem; }
.me-2 { margin-right:.5rem; }
.ms-1 { margin-left:.25rem; }
.mt-3 { margin-top:1rem; }
.w-100 { width:100%; }

/* ── Key/value rows (client details, etc.) ──────────────────────────────
   A two-cell g4-table splits 50/50 by default, which pushed values into the
   middle of a very wide card with nothing to their right. */
.g4-kv { width:100%; border-collapse:collapse; }
.g4-kv td { padding:.6rem .9rem; border-bottom:1px solid var(--border); font-size:.82rem; }
.g4-kv tr:last-child td { border-bottom:none; }
.g4-kv td:first-child { width:170px; color:var(--text-muted); white-space:nowrap; }
@media(max-width:768px){
  .g4-kv td:first-child { width:120px; }
}

/* ── Structure tree (read-only hierarchy view) ──────────────────────────
   A nested, indented tree. Each group carries a --d (depth) custom property;
   the group header is indented by depth, and the group's body (its Devices
   and Users) sits one guide-line further in, so items clearly read as sitting
   UNDER their group. The indent unit is a variable so mobile can shrink it. */
.g4-tree {
  /* All sizes are variables so the tree can scale up on large displays and
     down on phones without touching the markup. */
  --tree-indent:1.4rem;
  --tree-fs-grp:.92rem;    /* group name          */
  --tree-fs:.84rem;        /* device / user label */
  --tree-fs-sub:.68rem;    /* "Devices" / "Users" caption */
  --tree-fs-meta:.75rem;   /* serial / email      */
  --tree-ico:1rem;         /* leaf icons          */
  --tree-ico-grp:1.1rem;   /* folder icon         */
  --tree-badge:.66rem;     /* count badges        */
  padding:.35rem 0;
}

.g4-tree-grp { padding:.1rem 1rem; }

.g4-tree-head {
  display:flex; align-items:center; gap:.5rem;
  padding:.3rem 0;
  padding-left:calc(var(--tree-indent) * var(--d, 0));
}
.g4-tree-head .g4-tree-name { flex:1; font-size:var(--tree-fs-grp); font-weight:600; }
.g4-tree-head .bi-folder2   { font-size:var(--tree-ico-grp); flex-shrink:0; color:var(--text-muted); }

/* Count badges next to a group name — sized from the tree scale. */
.g4-tree-count { font-size:var(--tree-badge); }

/* The indented body with a vertical guide line — this is what makes the
   devices/users visually hang beneath the group. */
.g4-tree-body {
  margin-left:calc(var(--tree-indent) * var(--d, 0) + .5rem);
  padding-left:.85rem;
  border-left:1px solid var(--border);
}

.g4-tree-sub {
  font-size:var(--tree-fs-sub); text-transform:uppercase; letter-spacing:.05em;
  color:var(--text-muted); margin:.35rem 0 .12rem;
}
.g4-tree-sub:first-child { margin-top:.1rem; }

.g4-tree-item {
  display:flex; align-items:center; gap:.5rem;
  padding:.16rem 0 .16rem .2rem; font-size:var(--tree-fs);
}
.g4-tree-item .bi { font-size:var(--tree-ico); flex-shrink:0; }
.g4-tree-item .g4-tree-label { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.g4-tree-item .g4-tree-meta  { color:var(--text-muted); font-size:var(--tree-fs-meta); flex-shrink:0; }
.g4-tree-empty { color:var(--text-muted); font-size:var(--tree-fs-meta); padding:.1rem 0 .1rem .2rem; }

/* ── Large displays: scale the tree up so icons and captions stay legible.
   On a 1440p/4K monitor the compact defaults become hard to read. ── */
@media(min-width:1600px){
  .g4-tree {
    --tree-indent:1.7rem;
    --tree-fs-grp:1rem;
    --tree-fs:.92rem;
    --tree-fs-sub:.74rem;
    --tree-fs-meta:.82rem;
    --tree-ico:1.15rem;
    --tree-ico-grp:1.25rem;
    --tree-badge:.72rem;
  }
  .g4-tree-item { padding-top:.22rem; padding-bottom:.22rem; }
}
@media(min-width:2000px){
  .g4-tree {
    --tree-indent:2rem;
    --tree-fs-grp:1.1rem;
    --tree-fs:1rem;
    --tree-fs-sub:.8rem;
    --tree-fs-meta:.9rem;
    --tree-ico:1.3rem;
    --tree-ico-grp:1.4rem;
    --tree-badge:.78rem;
  }
  .g4-tree-item { padding-top:.28rem; padding-bottom:.28rem; }
}

/* Collapsible member sections inside a group (details/summary). Hide the
   native marker; the caption row acts as the toggle. */
.g4-tree-body details > summary { list-style:none; }
.g4-tree-body details > summary::-webkit-details-marker { display:none; }
.g4-tree-body details > summary::before {
  content:"\25B8";                       /* ▸ */
  display:inline-block; width:.8em;
  transition:transform var(--tr);
}
.g4-tree-body details[open] > summary::before { transform:rotate(90deg); }

/* ── Pick lists: multi-select assignment of ungrouped devices / users ──
   A client can hold hundreds of devices, so the list scrolls and filters
   rather than rendering one form (and one dropdown) per row. */
.g4-picklist {
  max-height:320px; overflow-y:auto;
  border:1px solid var(--border); border-radius:var(--r);
  padding:.2rem;
}
.g4-pick {
  display:flex; align-items:center; gap:.5rem;
  padding:.25rem .35rem; border-radius:var(--r);
  font-size:.78rem; cursor:pointer;
}
.g4-pick:hover { background:var(--hover-bg, rgba(127,127,127,.08)); }
/* Angehakte Zeile sichtbar machen — das Kästchen allein ist in einer langen
   Liste leicht zu übersehen, und genau daran scheiterte die Zuordnung. */
.g4-pick.selected { background:rgba(34,197,94,.10); border-left:2px solid var(--accent); }

/* ── Zuweisungslisten: Einzel- vs. Mehrfachmodus ───────────────────────────
   Standard ist die EINZELZUWEISUNG: jede Zeile trägt ihr eigenes Dropdown und
   einen Pfeilknopf, es gibt keinen Auswahlzustand, den man übersehen kann.
   Die Mehrfachauswahl wird über .pick-mode-bulk am umgebenden Kasten
   eingeblendet — dann verschwinden die Zeilen-Formulare und Checkboxen plus
   Sammelleiste erscheinen. */
.g4-pick-head { display:flex; gap:.4rem; margin-bottom:.5rem; }
.g4-pick-head .g4-input { flex:1; }

.g4-pick { flex-wrap:wrap; }
.g4-pick-main { flex:1; min-width:0; display:flex; flex-direction:column; gap:1px; }
.g4-pick-name { font-size:.8rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.g4-pick-meta { font-size:.68rem; color:var(--text-muted);
                overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* Eigene Zeile: in der schmalen Spalte passt neben Name und E-Mail kein
   weiteres Bedienelement. */
.g4-pick-act { flex:0 0 100%; display:flex; gap:.35rem; margin-top:.35rem; }
.g4-pick-act .g4-input { flex:1; font-size:.72rem; padding:.25rem .4rem; }

.g4-pick-box  { display:none; }
.g4-pick-bulk { display:none; }

.pick-mode-bulk .g4-pick-act { display:none; }
.pick-mode-bulk .g4-pick-box { display:inline-block; }
.pick-mode-bulk .g4-pick-bulk { display:block; }
/* Größer und in der Akzentfarbe: das Kästchen trägt die eigentliche Aussage
   des Formulars und war vorher das kontrastärmste Element im Kasten. */
.g4-pick input[type=checkbox] {
    flex-shrink:0; cursor:pointer;
    width:16px; height:16px;
    accent-color:var(--accent);
}
/* Warum der Assign-Knopf gesperrt ist. */
.g4-pick-hint { font-size:.72rem; color:var(--text-muted); margin-top:.35rem; }
.g4-pick-name { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.g4-pick-meta { color:var(--text-muted); font-size:.7rem; flex-shrink:0; }

/* ── Mobile sidebar backdrop ── */
.g4-mob-backdrop {
  display:none;
  position:fixed; inset:0; z-index:40;
  background:rgba(0,0,0,.5);
  opacity:0; transition:opacity var(--tr);
}
.g4-mob-backdrop.show { opacity:1; }

@media(max-width:768px){
  /* Sidebar becomes an off-canvas drawer, opened via the header hamburger. */
  .sidebar {
    transform:translateX(-100%);
    transition:transform var(--tr);
    width:var(--sb-w) !important; z-index:50;
  }
  .sidebar.sb-col { width:var(--sb-w) !important; }      /* ignore desktop collapse on mobile */
  .sidebar.sb-col .sb-lbl,
  .sidebar.sb-col .sb-grp,
  .sidebar.sb-col .sb-brand-name,
  .sidebar.sb-col .sb-chip { opacity:1; height:auto; }   /* always show labels in the drawer */
  .sidebar.sb-mob-open { transform:translateX(0); }
  .sb-toggle { display:none; }                            /* desktop collapse arrow hidden on mobile */

  .g4-mob-backdrop.show { display:block; }
  .g4-mob-menu { display:inline-flex; align-items:center; }

  /* Main takes the full width. */
  .g4-main, .g4-main.sb-col { margin-left:0 !important; }
  .g4-content { padding:.85rem; }

  /* Page header: tighter, allow wrapping, smaller title. */
  .g4-ph {
    height:auto; min-height:var(--hh);
    padding:.6rem .85rem; flex-wrap:wrap; gap:.5rem;
  }
  .g4-ph-title { font-size:.95rem; }
  .g4-ph-sub { display:none; }                            /* client name subtitle hidden to save room */

  /* Tables scroll horizontally instead of overflowing the viewport.
     The card normally has overflow:hidden (for rounded corners), which would
     CLIP an over-wide table instead of letting it scroll — so on mobile we let
     the card show its overflow and make the inner scroll container do the work.
     Covers both the .g4-table-wrap class and the inline overflow-x:auto divs. */
  .g4-card { overflow:visible; margin-bottom:.85rem; }
  .g4-table-wrap,
  .g4-table-scroll,
  .g4-card [style*="overflow-x"] {
    overflow-x:auto; -webkit-overflow-scrolling:touch;
    max-width:100%;
  }
  .g4-table { min-width:560px; }                          /* keep columns readable; wrap scrolls */

  /* Log tables (.g4-log-table) switch to a stacked card view on mobile: each
     row becomes its own card and each cell shows its column name (from
     data-label) next to the value, so nothing scrolls off-screen. This
     overrides the horizontal-scroll behaviour above for these tables only. */
  .g4-log-table { min-width:0; }
  .g4-log-table thead { display:none; }                   /* column headers not needed in card view */
  .g4-log-table, .g4-log-table tbody, .g4-log-table tr, .g4-log-table td { display:block; width:100%; }
  .g4-log-table tr {
    border:1px solid var(--border); border-radius:var(--r-lg);
    margin-bottom:.6rem; padding:.3rem .1rem; background:var(--card-bg);
  }
  .g4-log-table td {
    display:flex; justify-content:space-between; align-items:flex-start; gap:1rem;
    padding:.4rem .8rem; border:none; text-align:right;
    max-width:none !important; white-space:normal !important;
    overflow:visible !important; text-overflow:clip !important;
  }
  .g4-log-table td::before {
    content:attr(data-label);
    font-size:.62rem; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
    color:var(--text-muted); text-align:left; flex:none; padding-top:.15rem;
  }
  /* The "no entries" full-width cell shouldn't get a label or flex layout. */
  .g4-log-table td[colspan]::before { content:none; }
  .g4-log-table td[colspan] { justify-content:center; text-align:center; }

  /* Action clusters in a stacked row: let the labelled icon buttons (see the
     hover:none rule) sit in a left-aligned wrapping column so each reads
     clearly, rather than being squeezed to the right edge. */
  .g4-log-table td .g4-actions {
    justify-content:flex-end; gap:.5rem; row-gap:.5rem;
  }
  .g4-log-table td .g4-actions .g4-btn { flex:0 0 auto; }

  /* Cards: less inner padding, full-width feel. */
  .g4-card-hd { padding:.6rem .8rem; flex-wrap:wrap; gap:.3rem; }

  /* Stat cards: 2 per row instead of shrinking too far. */
  .g4-stats { grid-template-columns:repeat(auto-fit,minmax(130px,1fr)); gap:.6rem; }
  .g4-sc-val { font-size:1.6rem; }

  /* Bootstrap-style columns stack full width on mobile. */
  .row > [class^="col-"], .row > [class*=" col-"] { flex:0 0 100%; max-width:100%; }

  /* Device detail panel: full-width slide-over on mobile. Keep the existing
     translateX slide mechanic (defined locally in the Devices view); only make
     it span the full width and drop the rounded corner. */
  .g4-panel {
    width:100vw !important; max-width:100vw !important;
    border-left:none !important; border-radius:0 !important;
  }

  /* Client switcher: don't let it eat the whole header row. */
  .g4-csw { max-width:150px; }

  /* Structure tree: shrink the indent unit so deeply-nested groups don't run
     off-screen, and allow horizontal scroll as a last-resort safety net for
     very long names at deep nesting (nothing gets clipped). */
  .g4-tree { --tree-indent:.7rem; overflow-x:auto; -webkit-overflow-scrolling:touch; }
  .g4-tree-grp { padding-left:.5rem; padding-right:.5rem; }
  .g4-tree-item .g4-tree-label { white-space:normal; }   /* let names wrap rather than clip on the phone */
}

/* ── Informational cookie/privacy notice ── */
.g4-cookie-notice {
  position:fixed; left:1rem; right:1rem; bottom:1rem; z-index:80;
  max-width:640px; margin:0 auto;
  display:flex; align-items:center; gap:1rem;
  background:var(--surface); border:1px solid var(--border);
  border-radius:12px; padding:.85rem 1.1rem;
  box-shadow:0 8px 30px rgba(0,0,0,.35);
}
.g4-cookie-text { flex:1; font-size:.82rem; color:var(--text-muted); line-height:1.5; }
.g4-cookie-text a { color:var(--accent); text-decoration:none; }
.g4-cookie-text a:hover { text-decoration:underline; }
@media(max-width:768px){
  .g4-cookie-notice { flex-direction:column; align-items:stretch; text-align:center; gap:.6rem; }
}

/* ── 2FA nudge toast ──────────────────────────────────────────────────────
   Slides in from the top-right after login for an admin without 2FA. Not a
   centre-screen modal — deliberately non-blocking, easy to dismiss. Snooze is
   remembered in a cookie (see _Layout script).
   Sits BELOW the sticky page header (var(--hh)=72px, z-index:100) and ABOVE it
   in stacking, so it's never hidden behind the LIVE/client bar. */
.g4-2fa-toast {
  position:fixed; top:calc(var(--hh) + 0.9rem); right:1.25rem; z-index:120;
  width:min(420px, calc(100vw - 2.5rem));
  background:var(--surface); border:1px solid var(--border);
  border-radius:14px; padding:1.25rem 1.35rem;
  box-shadow:0 14px 48px rgba(0,0,0,.4);
  /* Start off-screen to the right; animate in. */
  transform:translateX(calc(100% + 2rem)); opacity:0;
  transition:transform .35s cubic-bezier(.2,.8,.2,1), opacity .35s ease;
}
.g4-2fa-toast.show { transform:translateX(0); opacity:1; }
.g4-2fa-toast-hd {
  display:flex; align-items:center; gap:.55rem; margin-bottom:.6rem;
  font-weight:700; font-size:1rem; color:var(--text);
}
.g4-2fa-toast-hd .bi { color:var(--warn); font-size:1.3rem; }
.g4-2fa-toast-body { font-size:.86rem; color:var(--text-sub); line-height:1.6; margin-bottom:.9rem; }
.g4-2fa-toast-snooze {
  display:flex; align-items:center; gap:.5rem; cursor:pointer;
  font-size:.8rem; color:var(--text-muted); margin-bottom:1rem;
}
.g4-2fa-toast-snooze input { accent-color:var(--accent); width:16px; height:16px; }
.g4-2fa-toast-actions { display:flex; gap:.55rem; }
.g4-2fa-toast-close {
  position:absolute; top:.7rem; right:.75rem; background:none; border:none;
  color:var(--text-muted); cursor:pointer; font-size:1.05rem; line-height:1; padding:.2rem;
}
.g4-2fa-toast-close:hover { color:var(--text); }
@media(max-width:768px){
  /* On a phone, come in from the top full-width, still clear of the header. */
  .g4-2fa-toast {
    top:calc(var(--hh) + 0.6rem); left:.7rem; right:.7rem; width:auto;
    transform:translateY(calc(-100% - var(--hh) - 1.5rem));
  }
  .g4-2fa-toast.show { transform:translateY(0); }
}

/* ── Generic confirmation modal (logout, etc.) ── */
.g4-modal-backdrop {
  position:fixed; inset:0; z-index:200;
  background:rgba(0,0,0,.55);
  display:flex; align-items:center; justify-content:center;
  padding:1.5rem;
}
.g4-modal {
  background:var(--surface); border:1px solid var(--border);
  border-radius:14px; padding:1.75rem; max-width:380px; width:100%;
  text-align:center; box-shadow:0 12px 40px rgba(0,0,0,.45);
}
.g4-modal-icon {
  font-size:2rem; color:var(--accent); margin-bottom:.75rem;
}
.g4-modal-title { font-size:1.1rem; font-weight:700; color:var(--text); margin-bottom:.5rem; }
.g4-modal-text { font-size:.85rem; color:var(--text-muted); line-height:1.55; margin-bottom:1.5rem; }
.g4-modal-actions { display:flex; gap:.6rem; justify-content:center; }

/* ── Sidebar copyright ─────────────────────────────────────────────────────
   Sits at the very bottom of the sidebar. Shows full "© YEAR Name" when the
   sidebar is expanded, collapses to just "© YEAR" when the rail is collapsed. */
.sb-copyright {
    padding: .5rem .9rem 0;
    font-size: .62rem;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-align: center;
    opacity: .7;
}
.sb-copyright-short { display: none; }
.sidebar.sb-col .sb-copyright-full  { display: none; }
.sidebar.sb-col .sb-copyright-short { display: inline; }
.sidebar.sb-col .sb-copyright {
    text-align: center;
    padding-left: 0;
    padding-right: 0;
}

/* Powered by NEXUSGATE — discreet white-label attribution */
.sb-powered {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: .35rem .9rem .7rem;
    text-decoration: none;
    cursor: default;
    opacity: .55;
}
.sb-powered-lbl {
    font-size: .6rem;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--text-muted);
    white-space: nowrap;
}
.sb-powered-logo {
    height: 30px;
    width: auto;
    max-width: 60%;
    object-fit: contain;
}
/* Collapsed sidebar: hide the "Powered by" label, keep a small mark */
.sidebar.sb-col .sb-powered-lbl { display: none; }
.sidebar.sb-col .sb-powered-logo { height: 22px; max-width: 40px; }
.sidebar.sb-col .sb-powered { padding: .4rem 0 .6rem; }
