/* =====================================================================
   Skibums Timing System — Zentrale Styles (Single Source of Truth)
   ---------------------------------------------------------------------
   Alle Marken-/Format-Vorgaben aus dem Style Guide an EINER Stelle.
   Zentrale Änderung: Werte hier in :root anpassen — sie gelten dann
   auf allen Seiten, die diese Datei einbinden.

   Einbinden:  <link rel="stylesheet" href="styleguide.css">
   Aktivieren: <body class="sg"> ...  (Basis-Styles greifen nur im .sg-Scope,
               damit noch nicht migrierte Seiten unverändert bleiben)
   ===================================================================== */

:root {
  /* ---- Marke: Puffin's Bill (Orange) = Aktion/Akzent ---- */
  --orange:        #E4562A;
  --orange-strong: #C2431C;   /* kleiner weißer Text auf Orange */
  --orange-tint:   #FBE2D6;
  --on-orange:     #FFFFFF;

  /* ---- Marke: Electric Blue Lemonade (Blau) = Sekundär/Links ---- */
  --blue:        #0B5FAF;
  --blue-strong: #084A88;
  --blue-tint:   #D8E8F7;
  --blue-pale:   #E8F2FC;      /* sehr helles Blau: Tabellen-Kopfzeilen */
  --on-blue:     #FFFFFF;

  /* ---- Neutrale (kühl, eisgetönt) ---- */
  --snow:      #F4F5F7;        /* hinterster Hintergrund / Seite */
  --surface:   #FFFFFF;        /* Kachel-Oberfläche */
  --surface-2: #EEF2F6;        /* verschachtelt: Vorschau, Insets */
  --ink:       #12161B;        /* Text */
  --ink-soft:  #4A5561;        /* Sekundärtext, Labels */
  --ink-faint: #77828F;        /* Hinweise, deaktiviert */
  --line:      #DCE3EA;        /* Rahmen, Zeilentrenner */

  /* ---- Semantik (Zustand, getrennt vom Akzent) ---- */
  --go:   #2E7D32;
  /* Heller Grundton fuer "aktiv" — analog zu --blue-pale. Gedacht als Flaeche hinter einer
     Zeile, die gerade laeuft (Live-Uebersicht). NICHT fuer leere Platzhalter verwenden: Gruen
     heisst aktiv, und ein leerer Platz ist kein aktiver Zustand. */
  --go-pale: #E8F5E9;
  --stop: #C62828;
  --warn: #B26A00;

  /* ---- Favorit (eigener Ton, bewusst getrennt von --warn) ---- */
  --gold:        #B8860B;
  --gold-strong: #8F6A08;

  /* ---- Manuell/Leitung (Violett) — Rollen-Tag und manuelle Ereignisse im Event Log.
     Bewusst keine der Semantik-Farben: eine Handeingabe ist weder Erfolg noch Fehler. ---- */
  --violet: #6A1B9A;

  /* ---- Form ---- */
  --radius:    10px;           /* Kacheln/Karten */
  --radius-sm: 8px;            /* Tags, Badges, Buttons, Felder */
  --shadow:    0 1px 2px rgba(18,22,27,.06), 0 6px 20px rgba(18,22,27,.06);

  /* Schleier hinter einer Kachel ueber der Seite (.sg-modal). Eigener Token, weil er sich
     NICHT mit dem Theme umdrehen darf: aus color-mix auf --ink gebaut wurde er im dunklen
     Theme hell und legte einen weissen Nebel ueber die dunkle Seite. Abdunkeln muss er in
     beiden Themes, im dunklen sogar etwas kraeftiger -- dort ist der Abstand zwischen Seite
     und Kachel kleiner. */
  --scrim: rgba(18, 22, 27, .68);

  /* ---- Spalten-Board (TopBar + Kachel-Grids mit umschaltbarer Spaltenzahl) ----
     --sg-col-base-w = heutige 1-Spalten-Breite (.container max-width), bleibt bei
     1 Spalte unverändert. --sg-col-shrink-max = wie stark eine Spalte bei Platzmangel
     höchstens schrumpfen darf, bevor auf horizontales Scrollen umgeschaltet wird
     (0.20 = max. 20%, konfigurierbar an dieser einen Stelle). --sg-col-gap = Abstand
     ZWISCHEN den Spalten (.sg-col-board gap) — hier zentral einstellen, nicht pro
     Board/Seite. */
  --sg-col-base-w:    800px;
  --sg-col-shrink-max: 0.20;
  --sg-col-gap:       16px;

  /* ---- Typografie ---- */
  --ui:   system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Code", "Roboto Mono", Consolas, monospace;

  --accent: var(--orange);
}

/* Dark-Theme über System-Einstellung … */
@media (prefers-color-scheme: dark) {
  :root {
    --orange: #F47B4E; --orange-strong: #F9946E; --orange-tint: #3A241B; --on-orange: #1B0F09;
    --blue: #4D9BE0; --blue-strong: #7FB8EC; --blue-tint: #15293A; --blue-pale: #0C1520; --on-blue: #0A1622;
    --snow: #12161B; --surface: #1A2027; --surface-2: #222A33;
    --ink: #EAF0F6; --ink-soft: #A7B3C0; --ink-faint: #78848F; --line: #2B333D;
    --go: #5CC46A; --go-pale: #14251A; --stop: #F26D6D; --warn: #F0A73D;
    --gold: #E0B23D; --gold-strong: #F0C863;
    --violet: #A96BD0;
    --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 26px rgba(0,0,0,.45);
    --scrim: rgba(0, 0, 0, .72);
  }
}
/* … und explizit umschaltbar (gewinnt über die Media-Query) */
:root[data-theme="light"] {
  --orange: #E4562A; --orange-strong: #C2431C; --orange-tint: #FBE2D6; --on-orange: #FFFFFF;
  --blue: #0B5FAF; --blue-strong: #084A88; --blue-tint: #D8E8F7; --blue-pale: #E8F2FC; --on-blue: #FFFFFF;
  --snow: #F4F5F7; --surface: #FFFFFF; --surface-2: #EEF2F6;
  --ink: #12161B; --ink-soft: #4A5561; --ink-faint: #77828F; --line: #DCE3EA;
  --go: #2E7D32; --go-pale: #E8F5E9; --stop: #C62828; --warn: #B26A00;
  --gold: #B8860B; --gold-strong: #8F6A08;
  --violet: #6A1B9A;
  --shadow: 0 1px 2px rgba(18,22,27,.06), 0 6px 20px rgba(18,22,27,.06);
  --scrim: rgba(18, 22, 27, .68);
}
:root[data-theme="dark"] {
  --orange: #F47B4E; --orange-strong: #F9946E; --orange-tint: #3A241B; --on-orange: #1B0F09;
  --blue: #4D9BE0; --blue-strong: #7FB8EC; --blue-tint: #15293A; --blue-pale: #0C1520; --on-blue: #0A1622;
  --snow: #12161B; --surface: #1A2027; --surface-2: #222A33;
  --ink: #EAF0F6; --ink-soft: #A7B3C0; --ink-faint: #78848F; --line: #2B333D;
  --go: #5CC46A; --stop: #F26D6D; --warn: #F0A73D;
  --gold: #E0B23D; --gold-strong: #F0C863;
  --violet: #A96BD0;
  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 26px rgba(0,0,0,.45);
  --scrim: rgba(0, 0, 0, .72);
}

/* =====================================================================
   BASIS — greift nur unter .sg (Opt-in via <body class="sg">)
   ===================================================================== */
.sg {
  background: var(--snow);
  color: var(--ink);
  font-family: var(--ui);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  margin: 0;
}
.sg-container { max-width: 900px; margin: 0 auto; padding: 24px; }

.sg h1, .sg h2, .sg h3, .sg h4 { color: var(--ink); text-wrap: balance; }
.sg h1 { font-size: 2em; font-weight: 800; letter-spacing: -.01em; margin: 0 0 4px; }
/* Headlines nach Style Guide: Ink, fett, keine Markenfarbe, kein Icon.
   Abschnittstitel mit ruhiger Bottom-Linie statt farbigem Balken. */
.sg h2 { font-size: 1.5em; font-weight: 800; color: var(--ink); margin-top: 28px; padding-bottom: .3em; border-bottom: 1px solid var(--line); }
.sg h3 { font-size: 1.15rem; font-weight: 700; color: var(--ink); margin-top: 18px; }
.sg p { margin: .6em 0; }
.sg a { color: var(--blue); text-decoration: none; font-weight: 600; }
.sg a:hover { color: var(--blue-strong); text-decoration: underline; }
.sg code { background: var(--surface-2); color: var(--ink); padding: 2px 6px; border-radius: 4px; font-family: var(--mono); font-size: .9em; }
.sg hr { border: none; border-top: 1px solid var(--line); margin: 24px 0; }
.sg :focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.sg .date-badge { color: var(--ink-soft); font-size: .9em; font-weight: 500; }

/* =====================================================================
   KOMPONENTEN — überall verwendbar (klassenbasiert, kein Scope nötig)
   ===================================================================== */

/* Kopfleiste / Navigation */
.sg-topnav { margin-bottom: 20px; display: flex; flex-wrap: wrap; gap: 15px; }
.sg-topnav a { color: var(--blue); text-decoration: none; font-weight: 600; }
.sg-topnav a:hover { text-decoration: underline; }

/* Karte / Kachel */
.sg-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 18px;
  margin: 18px 0;
}
/* Kachel-Titel nach Style Guide: Ink, fett, 1.15rem, keine Markenfarbe, kein farbiger Balken.
   Gilt auch für die erste Überschrift in einer Kachel, damit bestehendes Markup automatisch passt. */
.sg-card__title,
.sg-card > h2:first-child,
.sg-card > h3:first-child,
.sg-card > h4:first-child {
  font-weight: 700;
  font-size: 1.15rem;
  color: var(--ink);
  margin: 0 0 12px;
  padding: 0;
  border: none;
  text-transform: none;
  letter-spacing: normal;
  text-wrap: balance;
}

/* Karte mit Akzent-Kante (ersetzt frühere rule-box / live-status-card) */
.sg-accent { border-left: 5px solid var(--blue); }
.sg-accent--orange { border-left-color: var(--orange); }
.sg-accent--go { border-left-color: var(--go); }
.sg-accent--stop { border-left-color: var(--stop); }

/* Tabelle: Kopfzeile hellblau mit runden oberen Ecken, Zeilen durch leichte Linie getrennt, Hover */
.sg-table { width: 100%; border-collapse: separate; border-spacing: 0; margin: 16px 0; font-size: .95em; }
.sg-table th {
  text-align: left; background: var(--blue-pale); color: var(--ink-soft);
  font-size: .72rem; text-transform: uppercase; letter-spacing: .06em;
  padding: 10px; border-bottom: 1px solid var(--line);
}
.sg-table thead th:first-child { border-top-left-radius: var(--radius-sm); }
.sg-table thead th:last-child  { border-top-right-radius: var(--radius-sm); }
.sg-table td { padding: 10px; border-bottom: 1px solid var(--line); }
.sg-table tbody tr { transition: background .12s ease; }
.sg-table tbody tr:hover { background: color-mix(in srgb, var(--blue) 7%, var(--surface)); }
.sg-table tbody tr:last-child td { border-bottom: none; }
.sg-table .num { text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* Buttons */
.sg-btn { font: inherit; font-weight: 700; font-size: .9rem; border-radius: var(--radius-sm);
  padding: .6rem 1.1rem; border: 1px solid transparent; cursor: pointer; display: inline-flex;
  align-items: center; gap: .4rem; text-decoration: none; }
.sg-btn--primary { background: var(--orange-strong); color: var(--on-orange); }
.sg-btn--primary:hover { filter: brightness(1.05); }
.sg-btn--secondary { background: var(--blue); color: var(--on-blue); }
.sg-btn--secondary:hover { background: var(--blue-strong); }
.sg-btn--ghost { background: transparent; color: var(--blue); border-color: var(--blue); }
.sg-btn--danger { background: transparent; color: var(--stop); border-color: color-mix(in srgb, var(--stop) 50%, transparent); }
.sg-btn--neutral { background: var(--surface-2); color: var(--ink); border-color: var(--line); }
.sg-btn--neutral:hover { background: var(--line); }
.sg-btn--sm { padding: .3rem .7rem; font-size: .8rem; }

/* Symbol-Buttons (Soft-Tint) — Add/Edit/Delete/Admin für Tabellen & Kacheln.
   Nur die Klasse setzen; das Icon kommt per CSS-Mask, eingefärbt in der Aktionsfarbe.
   Farb-Logik: Add = Orange (primär), Edit/Admin = Blau (interaktiv), Delete = Rot (destruktiv).
   Zustände: Standard 14% Tint -> Hover 24% -> Aktiv/Gedrückt 34% + kräftigerer Text (--act-strong).
   Inaktiv: neutrale Fläche/Text, kein Hover/Klick (per :disabled oder [aria-disabled="true"]). */
.sg-iconbtn {
  --act: var(--blue);
  --act-strong: var(--blue-strong);
  -webkit-appearance: none; appearance: none; cursor: pointer; padding: 0; border: none;
  display: inline-flex; align-items: center; justify-content: center;
  /* Innerer Abstand Icon<->Rand = 2/3 des ursprünglichen Werts (8.5px -> ~5.5px),
     dadurch kompakteres Feld und niedrigere Zeilenhöhe in Tabellen. */
  width: 30px; height: 30px; border-radius: var(--radius-sm);
  color: var(--act);
  background: color-mix(in srgb, var(--act) 14%, transparent);
  transition: background .13s ease, color .13s ease;
}
.sg-iconbtn:hover  { background: color-mix(in srgb, var(--act) 24%, transparent); }
.sg-iconbtn:active { background: color-mix(in srgb, var(--act) 34%, transparent); color: var(--act-strong); }
.sg-iconbtn:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.sg-iconbtn:disabled,
.sg-iconbtn[aria-disabled="true"] {
  color: var(--ink-faint);
  background: var(--surface-2);
  cursor: not-allowed;
  pointer-events: none;
}
.sg-iconbtn::before {
  content: ""; width: 19px; height: 19px; background: currentColor;
  -webkit-mask: var(--sg-icon) center / contain no-repeat;
          mask: var(--sg-icon) center / contain no-repeat;
}
.sg-iconbtn + .sg-iconbtn { margin-left: 4px; }
/* Innerer Abstand = 2/3 des ursprünglichen Werts (7px -> ~4.5px) */
.sg-iconbtn--sm { width: 25px; height: 25px; }
.sg-iconbtn--sm::before { width: 16px; height: 16px; }

.sg-iconbtn--add   { --act: var(--orange); --act-strong: var(--orange-strong);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 5v14M5 12h14'/%3E%3C/svg%3E"); }
.sg-iconbtn--edit  { --act: var(--blue); --act-strong: var(--blue-strong);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h4L19 9l-4-4L4 16v4z'/%3E%3Cpath d='M14 6l4 4'/%3E%3C/svg%3E"); }
.sg-iconbtn--del   { --act: var(--stop); --act-strong: var(--stop);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 7h16'/%3E%3Cpath d='M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2'/%3E%3Cpath d='M6 7l1.2 13a1 1 0 0 0 1 .9h7.6a1 1 0 0 0 1-.9L18 7'/%3E%3Cpath d='M10 11v6M14 11v6'/%3E%3C/svg%3E"); }
.sg-iconbtn--admin { --act: var(--blue); --act-strong: var(--blue-strong);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3l7 3v5c0 4.5-3 7.5-7 9-4-1.5-7-4.5-7-9V6z'/%3E%3Cpath d='M9.5 12l1.8 1.8L15 10'/%3E%3C/svg%3E"); }
/* Logout: neutral (Ink-soft), keine Marken-/Statusfarbe — Verlassen der Sitzung ist weder
   Aktion noch Fehler. Aktiv/Gedrückt geht dezent Richtung Ink, nicht Rot (keine "Gefahr"). */
.sg-iconbtn--logout { --act: var(--ink-soft); --act-strong: var(--ink);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4'/%3E%3Cpath d='M16 17l5-5-5-5'/%3E%3Cpath d='M21 12H9'/%3E%3C/svg%3E"); }

/* Details/Home: reine Navigation, keine Statusänderung -> Blau, wie Edit/Admin. */
.sg-iconbtn--details { --act: var(--blue); --act-strong: var(--blue-strong);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cline x1='12' y1='11' x2='12' y2='16'/%3E%3Ccircle cx='12' cy='7.5' r='0.9' fill='%23000' stroke='none'/%3E%3C/svg%3E"); }
.sg-iconbtn--home { --act: var(--blue); --act-strong: var(--blue-strong);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 10.5L12 3l9 7.5'/%3E%3Cpath d='M5 9.5V21h14V9.5'/%3E%3Cpath d='M9 21v-7h6v7'/%3E%3C/svg%3E"); }
/* Bug/Feedback-Board: BLAU, nicht Rot. Das Symbol zeigt einen Käfer, die Aktion ist aber der
   Sprung auf eine Übersichtsseite — also Navigation. Rot ist hier reserviert für Destruktives
   (Löschen); ein Fehlerbericht ist kein Schaden, sondern ein Hinweis. Käfer aus Grundformen:
   Körper als Ellipse, Trennlinie, zwei Fühler, drei Beinpaare. */
.sg-iconbtn--bug { --act: var(--blue); --act-strong: var(--blue-strong);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cellipse cx='12' cy='13' rx='5' ry='6.5'/%3E%3Cpath d='M12 8.5v10'/%3E%3Cpath d='M9.6 7.2L8 4.5'/%3E%3Cpath d='M14.4 7.2L16 4.5'/%3E%3Cpath d='M7 10L3.5 8.5'/%3E%3Cpath d='M7 13.5H3.5'/%3E%3Cpath d='M7.4 17L4 18.8'/%3E%3Cpath d='M17 10l3.5-1.5'/%3E%3Cpath d='M17 13.5h3.5'/%3E%3Cpath d='M16.6 17l3.4 1.8'/%3E%3C/svg%3E"); }

/* Vollbild: Anzeigetafel-Ansicht einer Kachel. BLAU wie die uebrige Navigation — Vergroessern
   ist weder die primaere Aktion einer Ansicht (Orange) noch destruktiv (Rot), sondern ein
   Wechsel der Darstellung. Umschalter: .is-active zeigt das Symbol zum Verlassen (Pfeile nach
   innen). Die Klasse per classList.toggle() setzen, NIE className/textContent ueberschreiben —
   das reisst die sg-*-Klassen heraus. */
.sg-iconbtn--expand { --act: var(--blue); --act-strong: var(--blue-strong);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 4H4v5'/%3E%3Cpath d='M15 4h5v5'/%3E%3Cpath d='M20 15v5h-5'/%3E%3Cpath d='M4 15v5h5'/%3E%3C/svg%3E"); }
.sg-iconbtn--expand.is-active {
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 9h5V4'/%3E%3Cpath d='M20 9h-5V4'/%3E%3Cpath d='M15 20v-5h5'/%3E%3Cpath d='M9 20v-5H4'/%3E%3C/svg%3E"); }

/* Subscribe/Favorite: Umschalter, nicht nur Aktion. .is-active schaltet Farbe UND Icon
   (Outline -> gefüllt) um; Klasse per JS auf Klick togglen, z.B.:
   btn.classList.toggle('is-active'); btn.setAttribute('aria-pressed', btn.classList.contains('is-active')); */
.sg-iconbtn--subscribe { --act: var(--ink-soft); --act-strong: var(--ink);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9a6 6 0 0 1 12 0c0 5 2 6 2 6H4s2-1 2-6z'/%3E%3Cpath d='M10 20a2 2 0 0 0 4 0'/%3E%3C/svg%3E"); }
.sg-iconbtn--subscribe.is-active { --act: var(--go); --act-strong: var(--go);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9a6 6 0 0 1 12 0c0 5 2 6 2 6H4s2-1 2-6z' fill='%23000' stroke='none'/%3E%3Cpath d='M10 20a2 2 0 0 0 4 0'/%3E%3C/svg%3E"); }

.sg-iconbtn--favorite { --act: var(--ink-soft); --act-strong: var(--ink);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.5l2.5 5.5 6 .7-4.4 4 1.2 6-5.3-3-5.3 3 1.2-6-4.4-4 6-.7z'/%3E%3C/svg%3E"); }
.sg-iconbtn--favorite.is-active { --act: var(--gold); --act-strong: var(--gold-strong);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.5l2.5 5.5 6 .7-4.4 4 1.2 6-5.3-3-5.3 3 1.2-6-4.4-4 6-.7z'/%3E%3C/svg%3E"); }

/* Ein-/Ausklappen: neutraler Chevron, der sich um 90° dreht (zeigt rechts = zu,
   zeigt runter = offen) statt Text/Icon zu tauschen. Für rein visuelle Chevrons
   (kein eigener Klick-Handler, z.B. als Teil einer klickbaren Kopfzeile) als
   <span class="sg-iconbtn sg-iconbtn--collapse"> statt <button> einsetzen, damit
   kein doppelter Toggle durch Event-Bubbling entsteht. Zustand: JS setzt/entfernt
   die Klasse .is-expanded (z.B. el.classList.toggle('is-expanded', isOpen)). */
.sg-iconbtn--collapse { --act: var(--ink-soft); --act-strong: var(--ink);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 6 15 12 9 18'/%3E%3C/svg%3E"); }
.sg-iconbtn--collapse::before { transition: transform .15s ease; }
.sg-iconbtn--collapse.is-expanded::before { transform: rotate(90deg); }

/* Schließen/Abbrechen: für "Formular schließen"-Umschalter (ersetzt das jeweilige
   Add-Icon, solange das zugehörige Formular offen ist). Rot wie Delete, da es
   eine Eingabe verwirft — Klassen zwischen --add und --close umschalten. */
.sg-iconbtn--close { --act: var(--stop); --act-strong: var(--stop);
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 6l12 12M18 6L6 18'/%3E%3C/svg%3E"); }

/* Ziehen (Griff, 6-Punkte-Raster): reine visuelle Drag-Affordanz auf
   umsortierbaren/verschiebbaren Kacheln (z.B. sg-col-board__tile). Neutral wie
   Collapse — Ziehen ist keine Aktion mit Ergebnis, sondern eine Interaktions-
   einladung. Als <span>, nicht <button>: hat keinen eigenen Klick-Handler —
   columnLayout.js setzt draggable auf der Kachel erst beim mousedown auf diesem
   Griff, der damit der EINZIGE Anfasser der Kachel ist (die Kachel selbst ist
   nicht dauerhaft draggable, sonst startet jedes Markieren/Klicken darin ein
   Drag). Bereits in styleguide.html §11 als
   reine Doku-Grafik gezeigt — hier als echte, wiederverwendbare Komponente. */
.sg-iconbtn--drag { --act: var(--ink-soft); --act-strong: var(--ink); cursor: grab;
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Ccircle cx='9' cy='6' r='1.6'/%3E%3Ccircle cx='15' cy='6' r='1.6'/%3E%3Ccircle cx='9' cy='12' r='1.6'/%3E%3Ccircle cx='15' cy='12' r='1.6'/%3E%3Ccircle cx='9' cy='18' r='1.6'/%3E%3Ccircle cx='15' cy='18' r='1.6'/%3E%3C/svg%3E"); }

/* Avatar mit Initialen — Login-Status auf einen Blick, Klick öffnet das Profil.
   Blau (interaktiv) wenn angemeldet; für "nicht angemeldet" .sg-avatar--anon nutzen. */
.sg-avatar {
  -webkit-appearance: none; appearance: none; cursor: pointer; border: none; padding: 0;
  width: 34px; height: 34px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--blue); color: var(--on-blue);
  font-weight: 700; font-size: .78rem; letter-spacing: .01em;
  transition: background .13s ease;
}
.sg-avatar:hover { background: var(--blue-strong); }
.sg-avatar:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.sg-avatar--anon { background: var(--surface-2); color: var(--ink-faint); }

/* Tags (Rollen etc.) — 8dp Rundung */
.sg-tag { font-size: .72rem; font-weight: 700; letter-spacing: .03em; padding: 3px 9px;
  border-radius: var(--radius-sm); color: #fff; display: inline-block; }
.sg-tag--admin  { background: var(--stop); }
.sg-tag--lead   { background: var(--violet); }
.sg-tag--course { background: var(--blue); }
.sg-tag--start  { background: var(--go); }
/* Neutrales Grau: die Zuschauerrolle und -- als Feststellung, nicht als Bewertung -- die
   Person ohne Benutzerkonto (`sg-tag--guest`, z. B. ein am Hang eingetragener Starter).
   Orange, Rot oder Gruen haetten hier eine Bedeutung, die es nicht gibt. */
.sg-tag--spec,
.sg-tag--guest  { background: #64748B; }

/* Status-Badges — getönte Fläche, kräftige Schrift */
.sg-badge { font-size: .8125rem; font-weight: 700; padding: 3px 10px; border-radius: var(--radius-sm); display: inline-block; }
.sg-badge--neu  { background: var(--blue-tint); color: var(--blue-strong); }
.sg-badge--live { background: color-mix(in srgb, var(--go) 18%, transparent); color: var(--go); }
.sg-badge--done { background: var(--surface-2); color: var(--ink-soft); }
.sg-badge--warn { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); }
.sg-badge--stop { background: color-mix(in srgb, var(--stop) 16%, transparent); color: var(--stop); }

/* Begruendung unter einem Ergebnis-Badge im Ereignisprotokoll ("Ziel: Laeufer #7 in
   34.512 s"). Steht hier und nicht in den beiden Seiten, weil sie sonst auseinanderlaufen:
   log.html und die Event-Log-Kacheln in index.html zeigen dieselbe Zeile. */
.sg-outcome-detail { font-size: .8em; color: var(--ink-soft); margin-top: 3px; }

/* Gate-Typ */
.sg-gate { font-size: .72rem; font-weight: 800; letter-spacing: .05em; padding: 3px 9px; border-radius: var(--radius-sm); color: #fff; }
.sg-gate--start  { background: var(--go); }
.sg-gate--finish { background: var(--stop); }
.sg-gate--split  { background: var(--blue); }

/* Transport-Status (BLE / DATA / LORA / WIFI) — auf welchem Weg ein Gate gerade erreichbar
   ist. Nicht anklickbar, reine Anzeige; die Beschriftung nennt den Transport, die Farbe
   nennt nur den Zustand. Genau drei Zustände, mehr braucht es nicht:

     .is-off    Grau  — dieser Weg trägt gerade nicht. Am Hang ohne Abdeckung der
                        Normalfall und deshalb bewusst neutral, nicht rot: ein Zustand,
                        den niemand beheben kann, darf nicht nach Fehler aussehen.
     .is-on     Grün  — Verbindung steht (aktiver Status, wie Live-Badge und Subscribe-an).
     .is-error  Rot   — Gegenstelle da, hat uns aber abgewiesen (z. B. falsches WLAN-
                        Passwort). Das ist der Fall, den der Bediener sofort beheben kann,
                        und nur der verdient Rot.

   Farbe steht nie allein: der Transportname bleibt immer lesbar.

   ABWEICHUNG (Stand: Android-App): BLE und DATA sind dort blau, LoRa violett (#9C27B0 —
   außerhalb der Palette). Beide meinen „Verbindung steht" und gehören auf .is-on; die
   Migration ist offen. Neue Transporte bitte nicht nach diesem Vorbild bauen. */
.sg-transport { display: inline-flex; gap: 4px; flex-wrap: wrap; }
.sg-transport__btn {
  font-size: .68rem; font-weight: 700; letter-spacing: .04em;
  min-width: 48px; padding: 4px 10px; text-align: center;
  border-radius: var(--radius-sm); color: #fff;
  background: var(--ink-faint);
}
.sg-transport__btn.is-on    { background: var(--go); }
.sg-transport__btn.is-error { background: var(--stop); }

/* Formularfelder — 8dp, Fokus in Blau (nicht Orange, wg. Nähe zu Fehler-Rot) */
.sg-field { display: flex; flex-direction: column; gap: .35rem; margin-bottom: 1rem; }
.sg-label { font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; font-weight: 700; color: var(--ink-soft); }
.sg-input { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: .55rem .7rem; color: var(--ink); font: inherit; font-size: .95rem; }
.sg-input:focus { outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px color-mix(in srgb, var(--blue) 24%, transparent); }
.sg-input:disabled { background: var(--surface-2); color: var(--ink-faint); border-style: dashed; }
.sg-input.is-error { border-color: var(--stop); box-shadow: 0 0 0 3px color-mix(in srgb, var(--stop) 18%, transparent); }

/* Kachel über der Seite (Modal) — für etwas, das den Blick ganz haben muss und danach
   wieder verschwindet: eine Aufnahme ansehen, eine Rückfrage beantworten.

   Vorher hatte jede Seite ihre eigene: feedback.html den Screenshot-Lightbox, index.html das
   Chat-Fenster, beide mit eigenem Schwarzwert. Die Abdunklung kommt deshalb aus --scrim,
   einem Token mit eigenem Wert je Theme (siehe dortige Begründung).

   Zustand ausschließlich über .is-open umschalten (classList.toggle), nie style.display von
   Hand setzen: display gehört zur Komponente, nicht zum Aufrufer. Der Panel-Klick stoppt die
   Blasenbildung, damit ein Klick INS Panel nicht als Klick auf den Hintergrund gilt. */
.sg-modal {
  position: fixed; inset: 0; z-index: 9500;
  display: none; align-items: center; justify-content: center;
  padding: 16px;
  background: var(--scrim);
}
.sg-modal.is-open { display: flex; }
.sg-modal__panel {
  background: var(--surface); color: var(--ink);
  border-radius: var(--radius); box-shadow: var(--shadow);
  width: min(920px, 100%); max-height: 92vh;
  display: flex; flex-direction: column; overflow: hidden;
}
.sg-modal__head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 16px; border-bottom: 1px solid var(--line);
}
.sg-modal__body { padding: 16px; overflow: auto; }
.sg-modal__foot {
  display: flex; align-items: center; justify-content: flex-end; gap: 8px;
  padding: 12px 16px; border-top: 1px solid var(--line);
}

/* =====================================================================
   TOPBAR — seitenübergreifende Kopfleiste (außerhalb der View-Container
   eingehängt, damit sie unabhängig von der aktiven Ansicht sichtbar bleibt).
   Wie eine Kachel über den Spalten: gleiche Breite wie das aktive Spalten-
   Board (--sg-board-width, von columnLayout.js direkt per JS gesetzt, siehe
   dortigen Kommentar zur width-Transition) bzw. die 1-Spalten-Basisbreite,
   wenn kein Board aktiv ist — KEIN voller Seiten-Streifen mehr. Oben flächig
   (sitzt am Viewport-Rand), unten abgerundet wie die Karten darunter, damit
   sie sich als Kachel in den Kachel-Stapel einreiht statt als eigenständiger
   Balken zu wirken. */
.sg-topbar {
  position: sticky; top: 0; z-index: 40;
  box-sizing: border-box;
  width: var(--sg-board-width, var(--sg-col-base-w));
  max-width: 100%;
  margin: 0 auto 15px; /* Abstand zum Kachel-Stapel darunter, wie zwischen den Kacheln selbst */
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 0 0 var(--radius) var(--radius);
  box-shadow: var(--shadow);
}
.sg-topbar__inner {
  padding: 10px 16px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.sg-topbar__left, .sg-topbar__right { display: flex; align-items: center; gap: 10px; min-width: 0; }
.sg-topbar__title {
  font-weight: 700; font-size: 1.05rem; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ---------------------------------------------------------------------
   FUSSZEILEN-KACHEL (.sg-footer, gerendert von footer.js)

   Spiegelbild der TopBar: gleiche Breitenquelle (--sg-board-width, von
   columnLayout.js zusätzlich direkt per JS gesetzt), gleicher Rahmen,
   nur oben statt unten gerundet — sie schließt den Kachel-Stapel ab,
   wie die TopBar ihn eröffnet.

   Bewusst NICHT sticky: Die TopBar klebt oben, weil man Titel, Zurück
   und Spaltenzahl beim Scrollen braucht. Der Fußzeilen-Inhalt ist ein
   Absprung, kein Werkzeug — dauerhaft angeheftet würde er nur
   Bildschirmhöhe kosten und den Chat-Knopf unten rechts überlagern.
   --------------------------------------------------------------------- */
.sg-footer {
  box-sizing: border-box;
  width: var(--sg-board-width, var(--sg-col-base-w));
  max-width: 100%;
  margin: 15px auto 0; /* Abstand zum Kachel-Stapel darüber, wie zwischen den Kacheln selbst */
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: var(--shadow);
}
.sg-footer__inner {
  padding: 10px 16px;
  display: flex; align-items: center; justify-content: flex-end; gap: 10px;
}

/* Spalten-Umschalter: zyklischer Button (1 -> 2 -> 3 -> 4 -> 1), Zustand rein
   über [data-columns] gesteuert (kein Klassen-Umschalten nötig, siehe unten). */
.sg-iconbtn--columns { --act: var(--blue); --act-strong: var(--blue-strong); }
.sg-iconbtn--columns[data-columns="1"] {
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='4' y='4' width='16' height='16' rx='2'/%3E%3C/svg%3E"); }
.sg-iconbtn--columns[data-columns="2"] {
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='3' y='4' width='8' height='16' rx='1.5'/%3E%3Crect x='13' y='4' width='8' height='16' rx='1.5'/%3E%3C/svg%3E"); }
.sg-iconbtn--columns[data-columns="3"] {
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='2' y='4' width='5' height='16' rx='1'/%3E%3Crect x='9.5' y='4' width='5' height='16' rx='1'/%3E%3Crect x='17' y='4' width='5' height='16' rx='1'/%3E%3C/svg%3E"); }
.sg-iconbtn--columns[data-columns="4"] {
  --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='2.8' y='4' width='3.5' height='16' rx='1'/%3E%3Crect x='7.8' y='4' width='3.5' height='16' rx='1'/%3E%3Crect x='12.8' y='4' width='3.5' height='16' rx='1'/%3E%3Crect x='17.8' y='4' width='3.5' height='16' rx='1'/%3E%3C/svg%3E"); }

/* =====================================================================
   SPALTEN-BOARD — Kachel-Grid mit umschaltbarer Spaltenzahl (1-4) und
   Drag & Drop der Kacheln zwischen Spalten. Spaltenzahl (--sg-cols),
   Spaltenbreite (--sg-col-w) und Gesamtbreite (--sg-board-width) werden
   von columnLayout.js berechnet und gesetzt, siehe web-portal/columnLayout.js. */
/* Wrapper AUSSERHALB eines Boards (z.B. die Dashboard-Kopfkachel mit Titel +
   Beschreibung, die über dem Kachel-Grid sitzt), der bei mehr Spalten mit dem
   Board mitwachsen soll — reines CSS statt einer JS-Breitenapproximation,
   damit margin:0 auto (aus .container) korrekt zentriert bleibt. */
.sg-col-board-outer { box-sizing: border-box; max-width: var(--sg-board-width, var(--sg-col-base-w)); }

.sg-col-board-scroll { overflow-x: auto; }
.sg-col-board {
  display: grid;
  grid-template-columns: repeat(var(--sg-cols, 1), var(--sg-col-w, var(--sg-col-base-w)));
  gap: var(--sg-col-gap);
  width: var(--sg-board-width, var(--sg-col-base-w));
  max-width: 100%;
  margin: 0 auto;
}
.sg-col {
  display: flex; flex-direction: column; gap: var(--sg-col-gap);
  min-height: 60px;
  padding: 10px;
  border-radius: var(--radius);
  transition: background .12s ease, outline-color .12s ease;
  outline: 2px dashed transparent; outline-offset: -2px;
}
/* Vorläufige, klar unterscheidbare Spalten-Hintergründe (helle Töne aus
   bestehenden Statusfarben), damit die Spaltengrenzen sichtbar sind, bis
   Spalten regulär genug Inhalt tragen, um sich optisch von selbst abzugrenzen. */
.sg-col:nth-child(1) { background: color-mix(in srgb, var(--blue) 8%, var(--surface-2)); }
.sg-col:nth-child(2) { background: color-mix(in srgb, var(--go) 8%, var(--surface-2)); }
.sg-col:nth-child(3) { background: color-mix(in srgb, var(--warn) 8%, var(--surface-2)); }
.sg-col:nth-child(4) { background: color-mix(in srgb, var(--gold) 8%, var(--surface-2)); }
.sg-col.is-dragover {
  background: color-mix(in srgb, var(--blue) 16%, var(--surface-2));
  outline-color: color-mix(in srgb, var(--blue) 45%, transparent);
}
/* Kein cursor:grab auf der ganzen Kachel: gezogen wird ausschließlich am Griff,
   der den Grab-Cursor selbst mitbringt (siehe .sg-iconbtn--drag). */
.sg-col-board__tile { position: relative; }
.sg-col-board__tile.is-dragging { opacity: .4; }
/* Sichtbarer Griff oben rechts auf jeder Kachel — der einzige Anfasser der
   Kachel (siehe .sg-iconbtn--drag oben und columnLayout.js::attachTileDnD). */
.sg-col-board__grip { position: absolute; top: 8px; right: 8px; }

/* =====================================================================
   ROUTING-DIAGRAMM (Sensor-Anbindung)
   ---------------------------------------------------------------------
   Zeigt je Gate den Weg der Messung: Sensor -> Zustellweg (Handy/Access
   Point/Nachbar-Gate) -> zentraler Web-Server. Der Server-Knoten steht
   EINMAL rechts und spannt über alle Zeilen (grid-row: 1 / -1) — er ist
   für alle Pfade derselbe, doppelt gezeichnet wäre er eine Falschaussage.

   Farbe: bewusst neutral (Ink/Line). Der einzige Farbträger ist das
   Transport-Badge (.sg-badge--live wenn das Gate aktiv meldet, sonst
   --done) — das Diagramm zeigt Topologie, nicht Zustand.
   Unbekannte Angaben (z.B. IP-Adressen, die heute nirgends erfasst
   werden) bekommen .sg-route__node--unknown: gestrichelt und gedämpft,
   damit "wissen wir nicht" nie wie "ist so" aussieht.
   ===================================================================== */
.sg-route { display: grid; grid-template-columns: minmax(150px, 1fr) auto minmax(150px, 1fr) auto minmax(150px, 1fr);
  gap: 10px 8px; align-items: center; min-width: 620px; }
.sg-route__server { grid-column: 5; grid-row: 1 / -1; align-self: center; }

.sg-route__node { display: flex; align-items: center; gap: 9px; min-width: 0;
  padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); }
/* --unknown = die Datenlage gibt den Weg nicht her.
   --stale    = der Weg ist bekannt, trägt aber gerade nicht (kein frischer
                Heartbeat). Gleiche Optik, weil beides dasselbe aussagt:
                „hierauf ist gerade kein Verlass" — getrennte Namen, weil es
                zwei verschiedene Gründe sind. */
.sg-route__node--unknown,
.sg-route__node--stale { border-style: dashed; color: var(--ink-faint); background: var(--surface-2); }

.sg-route__icon { flex: none; width: 22px; height: 22px; background: currentColor;
  -webkit-mask: var(--sg-icon) center / contain no-repeat;
          mask: var(--sg-icon) center / contain no-repeat; }
/* Gate: zwei Torstangen mit Lichtschranke dazwischen */
.sg-route__icon--gate { --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 21V4M18 21V4'/%3E%3Cpath d='M6 4h12'/%3E%3Cpath d='M8 12h8'/%3E%3C/svg%3E"); }
/* Handy: Gerät hochkant mit Home-Strich */
.sg-route__icon--phone { --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='7' y='2' width='10' height='20' rx='2'/%3E%3Cpath d='M11 18.5h2'/%3E%3C/svg%3E"); }
/* Access Point: Kasten mit Funkwellen */
.sg-route__icon--ap { --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='14' width='18' height='6' rx='2'/%3E%3Cpath d='M6.5 17h.01'/%3E%3Cpath d='M10 17h7'/%3E%3Cpath d='M5.5 9.5a9 9 0 0 1 13 0'/%3E%3Cpath d='M8.5 6.5a13 13 0 0 1 7 0'/%3E%3C/svg%3E"); }
/* Server: zwei gestapelte Einschübe mit Status-LED */
.sg-route__icon--server { --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='7' rx='2'/%3E%3Crect x='3' y='13' width='18' height='7' rx='2'/%3E%3Cpath d='M7 7.5h.01M7 16.5h.01'/%3E%3C/svg%3E"); }

/* Unbekannt: Fragezeichen — für Wege, die die Datenlage nicht hergibt */
.sg-route__icon--unknown { --sg-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M9.5 9.5a2.5 2.5 0 1 1 3 2.45V14'/%3E%3Cpath d='M12 17.5h.01'/%3E%3C/svg%3E"); }

/* Umbrechen statt kürzen: In einer schmalen Kachel ist die Spalte schnell bei
   ihrer Mindestbreite, und genau die abgeschnittene Zeile (MAC-Adresse, Name des
   Relay-Gates) ist die, die das Gerät identifiziert. Lieber zwei Zeilen hoch als
   nicht lesbar. */
.sg-route__label { min-width: 0; }
.sg-route__name { display: block; font-weight: 700; font-size: .875rem; line-height: 1.3; overflow-wrap: anywhere; }
.sg-route__meta { display: block; font-size: .72rem; line-height: 1.35; color: var(--ink-faint);
  font-family: var(--mono); overflow-wrap: anywhere; }

/* Kante zwischen zwei Knoten: Transport-Badge über einem Pfeil. */
.sg-route__link { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 0 2px; }
/* Kompaktes Badge auf der Kante — kleiner als das Standard-Badge, weil es
   zwischen zwei Knoten sitzt und nicht mit ihnen um Aufmerksamkeit ringen soll. */
.sg-route__link .sg-badge { font-size: .68rem; padding: 2px 7px; white-space: nowrap; }
.sg-route__arrow { width: 34px; height: 12px; background: var(--ink-faint);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 34 12' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 6h30'/%3E%3Cpath d='M27 2l4 4-4 4'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 34 12' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 6h30'/%3E%3Cpath d='M27 2l4 4-4 4'/%3E%3C/svg%3E") center / contain no-repeat; }
/* Gestrichelte Kante = Weg nur vermutet (kein Heartbeat, Transport unbekannt). */
.sg-route__arrow--unknown { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 34 12' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round' stroke-dasharray='3 3'%3E%3Cpath d='M1 6h30'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 34 12' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round' stroke-dasharray='3 3'%3E%3Cpath d='M1 6h30'/%3E%3C/svg%3E"); }

/* Hilfsklassen */
.sg-mono { font-family: var(--mono); }
.sg-tabular { font-variant-numeric: tabular-nums; }
.sg-muted { color: var(--ink-soft); }
.sg-scroll-x { overflow-x: auto; }
/* Vertikal scrollbarer Container für lange Tabellen (z.B. Event-Log-Kacheln) —
   wächst bis zur konfigurierbaren Maximalhöhe, danach scrollt nur der Inhalt,
   nicht die ganze Seite. Kopfzeile bleibt beim Scrollen sichtbar (sticky). */
.sg-scroll-y { max-height: var(--sg-scroll-y-max, 80vh); overflow-y: auto; }
.sg-scroll-y .sg-table thead th { position: sticky; top: 0; z-index: 1; }

@media (max-width: 600px) {
  .sg-container { padding: 16px; }
}
@media (prefers-reduced-motion: reduce) {
  .sg-table tbody tr { transition: none; }
}
