/* ------------------------------------------------------- Axiom design tokens
   Values taken from the Optimizely Axiom design system (--ax-* variables), so
   this tool looks like the rest of Optimizely's tooling rather than like a
   one-off admin page.

   Two deliberate deviations:
   - The brand faces (VC Nudge, Die Grotesk B) are licensed and would need a
     font CDN, which the Content-Security-Policy blocks. The stacks are kept
     verbatim so they resolve wherever the fonts are installed and fall back to
     system-ui everywhere else.
   - Axiom's accent is a bright lime. It carries DARK text, never white — as a
     button background with white text it would be unreadable. */
:root {
  /* colours */
  --ax-bg-default: #FFFFFF;
  --ax-bg-secondary: #EFF5EB;
  --ax-bg-tertiary-hovered: #D2DEC2;
  --ax-bg-accent: #ABFF44;
  --ax-bg-accent-hovered: #99F141;
  --ax-bg-accent-pressed: #7DDD3D;
  --ax-bg-accent-subtle: #EEFFD9;
  --ax-bg-warning-subtle: #FEF1C6;
  --ax-bg-error-subtle: #FFDFE8;
  --ax-bg-success-subtle: #EEFFD9;
  --ax-bg-information-subtle: #E2F5F5;

  --ax-fg-default: #202320;
  --ax-fg-secondary: #484E46;
  --ax-fg-tertiary: #616755;
  --ax-fg-disabled: #A1AC8D;
  --ax-fg-error-strong: #5D2E41;
  --ax-fg-success-strong: #226B1E;
  --ax-fg-warning-strong: #B54707;
  --ax-fg-information: #197A94;
  --ax-fg-inverse: #FFFFFF;

  --ax-border-default: #D8E4CB;
  --ax-border-secondary: #E4F0DA;
  --ax-border-control: #A1AC8D;
  --ax-border-focus: #197A94;
  --ax-border-error: #A95A77;
  --ax-border-warning: #F79008;
  --ax-border-success: #5F9B85;

  /* radii, shadows, type */
  --ax-radius-xs: 0.125rem;
  --ax-radius-sm: 0.375rem;
  --ax-radius-md: 0.5rem;
  --ax-radius-lg: 0.75rem;
  --ax-shadow-sm: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);
  --ax-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);
  --ax-font-sans: "Die Grotesk B", "DI Grotesk B", "Roboto Variable", system-ui, sans-serif;
  --ax-font-mono: "Roboto Mono Variable", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --ax-text-xs: 0.625rem;  --ax-leading-xs: 0.875rem;
  --ax-text-sm: 0.75rem;   --ax-leading-sm: 1rem;
  --ax-text-md: 0.875rem;  --ax-leading-md: 1.25rem;
  --ax-text-lg: 1rem;      --ax-leading-lg: 1.5rem;

  /* the names the rest of this stylesheet already uses, now fed by Axiom */
  --bg: var(--ax-bg-secondary);
  --panel: var(--ax-bg-default);
  --surface-2: var(--ax-bg-secondary);
  --ink: var(--ax-fg-default);
  --muted: var(--ax-fg-tertiary);
  --line: var(--ax-border-default);
  --accent: var(--ax-fg-information);
  --err: var(--ax-fg-error-strong);
}
* { box-sizing: border-box; }
/* display: grid/flex below would otherwise beat the UA rule for [hidden],
   and the editor would show through before anyone has authenticated. */
[hidden] { display: none !important; }
body {
  margin: 0;
  font-family: var(--ax-font-sans);
  font-size: var(--ax-text-md);
  line-height: var(--ax-leading-md);
  color: var(--ink);
  background: var(--bg);
}
/* --- Grundgeruest: Seitenleiste links, Inhalt rechts ----------------------
   Aufbau nach dem Axiom-Sidebar-Muster (NavHeader / NavBody / NavFooter), wie
   im RCS-Editor. Das Benutzerkonto sitzt unten, wo NavAccountItem es vorsieht. */
.app-shell { display: flex; min-height: 100vh; }

.sidebar {
  width: 232px; flex: none;
  display: flex; flex-direction: column;
  background: var(--panel);
  border-right: 1px solid var(--line);
  position: sticky; top: 0; height: 100vh;
  overflow: hidden;
  transition: width .14s ease;
}
.sidebar.collapsed { width: 64px; }
.sidebar.collapsed .nav-label,
.sidebar.collapsed .nav-header-text,
.sidebar.collapsed .nav-group-trigger,
.sidebar.collapsed .konto-text { display: none; }
.sidebar.collapsed .nav-item, .sidebar.collapsed .nav-account-item { justify-content: center; }
.sidebar.collapsed .nav-header { justify-content: center; }
.sidebar.collapsed .sidebar-toggle { margin-left: 0; }

.nav-header {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 12px; border-bottom: 1px solid var(--line);
}
.logo {
  background: var(--ax-bg-accent); color: var(--ax-fg-default);
  font-weight: 800; padding: 6px 10px;
  border-radius: var(--ax-radius-md); letter-spacing: 1px; flex: none;
}
.nav-header-text { display: flex; flex-direction: column; min-width: 0; }
.nav-header-text strong { font-size: 14px; }
.nav-header-text small {
  font-size: 11px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sidebar-toggle {
  margin-left: auto; width: 22px; height: 22px; flex: none;
  border: 1px solid var(--line); border-radius: var(--ax-radius-sm);
  background: var(--surface-2); cursor: pointer; position: relative; padding: 0;
}
.sidebar-toggle::before {
  content: ""; position: absolute; inset: 4px auto 4px 6px;
  width: 2px; background: var(--muted);
}

.nav-body { flex: 1; overflow-y: auto; padding: 10px 8px; }
.nav-group-trigger {
  font-size: 11px; text-transform: uppercase; letter-spacing: .5px;
  color: var(--muted); padding: 8px 10px 4px;
}
.nav-list { display: flex; flex-direction: column; gap: 2px; }
.nav-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 8px 10px; border: none; border-radius: var(--ax-radius-md);
  background: transparent; color: var(--ink);
  font: inherit; font-size: 13px; text-align: left; cursor: pointer;
}
.nav-item:hover { background: var(--surface-2); }
.nav-item.active { background: var(--ax-bg-accent-subtle); font-weight: 600; }
/* Das Icon traegt die Markierung mit, damit der aktive Eintrag auch bei
   eingeklappter Leiste erkennbar bleibt. */
.nav-icon {
  display: flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; flex: none; color: var(--muted);
}
.nav-item.active .nav-icon { color: var(--ax-fg-default); }
.nav-item:hover .nav-icon { color: var(--ink); }
.nav-separator { border: none; border-top: 1px solid var(--line); margin: 10px 4px; }

.nav-footer { border-top: 1px solid var(--line); padding: 8px; position: relative; }
.nav-account-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 8px; border: none; border-radius: var(--ax-radius-md);
  background: transparent; cursor: pointer; font: inherit; text-align: left;
  color: var(--ink);
}
.nav-account-item:hover { background: var(--surface-2); }
.avatar {
  width: 28px; height: 28px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%; background: var(--ax-bg-accent);
  color: var(--ax-fg-default); font-weight: 700; font-size: 12px;
}
.konto-text { display: flex; flex-direction: column; min-width: 0; }
.konto-text strong { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.konto-text small { font-size: 11px; color: var(--muted); }
.konto-menu {
  position: absolute; bottom: 100%; left: 8px; right: 8px; margin-bottom: 4px;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--ax-radius-md); box-shadow: var(--ax-shadow-lg); padding: 4px;
}
.konto-menu-item {
  display: block; width: 100%; padding: 8px 10px; border: none;
  border-radius: var(--ax-radius-sm); background: transparent;
  font: inherit; font-size: 13px; text-align: left; cursor: pointer; color: var(--ink);
}
.konto-menu-item:hover { background: var(--surface-2); }

.app-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding: 14px 22px;
  border-bottom: 1px solid var(--line); background: var(--panel);
  position: sticky; top: 0; z-index: 10;
}
.topbar h1 { font-size: 17px; margin: 0; font-weight: 600; }

/* --- Hilfe zum Bereich ---------------------------------------------------
   Neben dem Inhalt statt darueber: wer ein Formular ausfuellt, soll es
   waehrend des Lesens weiter sehen. Fest positioniert, weil app-main eine
   Spalte ist -- im Fluss wuerde die Schublade die Ansicht nach unten
   schieben statt neben ihr zu stehen. */
.hilfe-knopf {
  flex: none; width: 30px; height: 30px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--panel); color: var(--muted);
  font-size: 15px; line-height: 1; cursor: pointer;
}
.hilfe-knopf:hover { color: var(--ink); border-color: var(--ax-fg-tertiary); }
.hilfe-knopf[aria-expanded="true"] { background: var(--ax-bg-accent-subtle); color: var(--ink); }
.hilfe-panel {
  position: fixed; right: 0; z-index: 20;
  top: var(--topbar-hoehe, 57px); bottom: 0; width: min(400px, 92vw);
  display: flex; flex-direction: column;
  background: var(--panel); border-left: 1px solid var(--line);
  box-shadow: var(--ax-shadow-lg);
}
.hilfe-kopf {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 14px 18px; border-bottom: 1px solid var(--line);
}
.hilfe-kopf h2 { margin: 0; font-size: 15px; }
.hilfe-body { flex: 1; overflow-y: auto; padding: 16px 18px; font-size: 13.5px; line-height: 1.55; }
.hilfe-body p { margin: 0 0 12px; }
.hilfe-lead { color: var(--ink); font-weight: 500; }
.hilfe-body ul { margin: 0 0 12px; padding-left: 18px; }
.hilfe-body li { margin-bottom: 6px; }
/* Was man nicht sieht, bis es zu spaet ist: einmalige Schluessel, Loeschen,
   das nur nach Zurueckziehen geht. Deshalb abgesetzt statt im Fliesstext. */
.hilfe-merke {
  border-left: 3px solid var(--ax-bg-accent); background: var(--ax-bg-secondary);
  border-radius: 0 var(--ax-radius-sm) var(--ax-radius-sm) 0;
  padding: 10px 12px; margin: 0 0 12px;
}
.hilfe-fuss { border-top: 1px solid var(--line); padding: 12px 18px; }
/* Der Inhalt macht Platz, statt sich verdecken zu lassen: im Vorlagen-Editor
   stehen rechts die Telefone, und eine Hilfe, die genau die Voransicht
   zudeckt, waere an der unpassendsten Stelle im Weg. Auf schmalen Fenstern
   bleibt es beim Ueberdecken -- dort ist fuer beides kein Platz. */
@media (min-width: 1101px) {
  body.hilfe-auf main { padding-right: 420px; }
}

/* Dieselbe Hilfe auf den Seiten vor der Anmeldung. Dort gibt es keine
   Kopfzeile und keinen Platz daneben, also klappt sie unter dem Formular auf
   -- zugeklappt, damit sie niemandem im Weg steht, der sein Passwort weiss. */
.hilfe-aufklapp { margin-top: 16px; border-top: 1px solid var(--line); padding-top: 12px; }
.hilfe-mehr { font-size: 12.5px; padding: 4px 8px; }
.hilfe-inline { margin-top: 10px; font-size: 13px; line-height: 1.55; color: var(--muted); }
.hilfe-inline p { margin: 0 0 10px; }
.hilfe-inline ul { margin: 0 0 10px; padding-left: 18px; }
.hilfe-inline li { margin-bottom: 5px; }
.hilfe-inline .hilfe-lead { color: var(--ink); }
.topbar .sub { margin: 0; font-size: 12px; color: var(--muted); }
.topbar-actions { display: flex; align-items: center; gap: 12px; }

/* Eine Ansicht auf einmal. Jede Sektion sagt selbst, wozu sie gehoert --
   bei sechs Ansichten waere "alles ausser dieser" nicht mehr zu ueberblicken. */
#app > [data-view] { display: none; }
#app.view-overview > [data-view~="overview"],
#app.view-templates > [data-view~="templates"],
#app.view-newtemplate > [data-view~="newtemplate"],
#app.view-newpass > [data-view~="newpass"],
#app.view-passes > [data-view~="passes"],
#app.view-keys > [data-view~="keys"],
#app.view-campaign > [data-view~="campaign"],
#app.view-users > [data-view~="users"],
#app.view-tenants > [data-view~="tenants"],
#app.view-help > [data-view~="help"] { display: block; }
/* Die Vorschauen gehoeren zum Editor, nicht zur Vorlagenliste. */
#app.tpl-edit > .previews { display: flex; }
#app:not(.tpl-edit) > .previews { display: none; }
#app:not(.tpl-edit) { grid-template-columns: 1fr; }
.keys-panel h2 { font-size: 15px; margin: 0 0 6px; }
.keys-panel h2.section-gap { margin-top: 28px; padding-top: 18px; border-top: 1px solid var(--line); }
.platforms { display: grid; gap: 8px; margin: 12px 0 16px; }
.platform { border: 1px solid var(--line); border-radius: var(--ax-radius-md); padding: 10px 12px; font-size: 13px; display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.platform dl { margin: 6px 0 0; display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; font-size: 12px; color: var(--muted); }
.platform dt { font-weight: 600; }
.platform dd { margin: 0; }
.warn { color: var(--ax-fg-warning-strong); font-weight: 600; }
details.upload { border: 1px solid var(--line); border-radius: var(--ax-radius-md); padding: 10px 12px; margin-bottom: 10px; }
details.upload summary { cursor: pointer; font-size: 13px; font-weight: 600; }
details.upload form { display: grid; gap: 10px; margin-top: 12px; }
details.upload label { display: flex; align-items: center; gap: 8px; margin: 0; }
.keyform { display: grid; gap: 10px; margin: 14px 0; }
.keyform label { display: flex; align-items: center; gap: 8px; margin: 0; }
.keyform input[type=text] { max-width: 260px; }
.keyform input[type=number] { width: 90px; }
.scopes { display: flex; flex-wrap: wrap; gap: 14px; }
.scopes label { font-size: 13px; }
.newkey { border: 1px solid var(--ax-border-focus); border-radius: var(--ax-radius-md); padding: 12px; margin-bottom: 14px; background: var(--ax-bg-information-subtle); }
.newkey p { margin: 0 0 8px; font-size: 13px; }
.newkey code { display: block; word-break: break-all; background: #fff; border: 1px solid var(--line); border-radius: var(--ax-radius-sm); padding: 8px; font-size: 13px; margin-bottom: 8px; }
#keyTable td { font-size: 13px; vertical-align: middle; }
.state-revoked, .state-expired { color: var(--muted); }
.state-active { color: var(--ax-fg-success-strong); font-weight: 600; }

/* --- Anmeldung und Zugang ------------------------------------------------
   Aufgebaut wie bei rcs.hikel.de: eine Karte, oben Kurzzeichen mit Titel und
   Untertitel, die mit dem Zustand wechseln; ein breiter Knopf; darunter
   Textverweise statt weiterer Knoepfe. Anmeldung und Zugangsseite teilen sich
   diese Klassen -- wer aus einer Mail kommt, soll nicht merken, dass es eine
   andere Seite ist.
   Die Karte ist bewusst kein <main>: die Regel fuer main weiter unten macht
   daraus ein zweispaltiges Raster. */
.auth-body {
  min-height: 100vh; box-sizing: border-box;
  display: flex; align-items: center; justify-content: center;
  padding: 24px; background: var(--bg);
}
.auth-karte {
  width: 100%; max-width: 380px; box-sizing: border-box;
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--ax-radius-lg); box-shadow: var(--ax-shadow-lg);
  padding: 24px;
}
.auth-marke { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; }
.auth-marke h1 { font-size: 18px; margin: 0; line-height: 1.25; }
.auth-marke .sub { margin: 2px 0 0; font-size: 12.5px; color: var(--muted); }
.auth-karte label { display: block; margin: 0 0 12px; font-size: 13px; color: var(--ink); }
.auth-karte label > input,
.auth-karte label > .pw-feld { margin-top: 5px; }
.auth-hinweis { margin: -4px 0 12px; font-size: 12.5px; color: var(--muted); }
.auth-knopf { width: 100%; margin-top: 6px; }
.auth-fehler { margin: 0 0 10px; font-size: 13px; color: var(--err); }
.auth-erfolg {
  margin: 0 0 10px; padding: 10px 12px;
  border: 1px solid var(--ax-bg-accent); border-radius: var(--ax-radius-md);
  background: var(--ax-bg-accent-subtle); color: var(--ink);
  font-size: 13px; line-height: 1.4;
}
.auth-fuss { display: flex; justify-content: space-between; gap: 12px; margin-top: 14px; }
.auth-link {
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; font-size: 12px; cursor: pointer;
  color: var(--ax-fg-success-strong); text-decoration: underline;
}
.auth-link:hover { color: var(--ink); background: none; }
.auth-karte .hilfe-aufklapp { margin-top: 16px; }

main { display: grid; grid-template-columns: minmax(340px, 1fr) auto; gap: 20px; padding: 20px; align-items: start; }
@media (max-width: 1100px) { main { grid-template-columns: 1fr; } }

.panel { background: var(--panel); border: 1px solid var(--line); border-radius: var(--ax-radius-lg); padding: 20px; box-shadow: var(--ax-shadow-sm); }
fieldset { border: 1px solid var(--line); border-radius: var(--ax-radius-md); margin: 0 0 16px; padding: 12px 14px; }
legend { font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); padding: 0 4px; }
label { display: block; margin-bottom: 10px; font-size: 13px; color: var(--muted); }
input, select, button { font: inherit; }
input[type=text], input[type=password], input[type=email], input[type=number],
input[type=url], input[type=datetime-local], input:not([type]), select {
  width: 100%; padding: 7px 9px; border: 1px solid var(--line); border-radius: var(--ax-radius-sm); background: #fff; color: var(--ink);
}
/* Passwortfelder tragen rechts einen Knopf zum Ein- und Ausblenden. Die
   Huelle traegt den Abstand, den sonst das Feld selbst truege -- sonst sitzt
   der Knopf um genau diesen Abstand zu hoch. */
.pw-feld { position: relative; display: block; }
.pw-feld > input { padding-right: 38px; }
.pw-auge {
  position: absolute; top: 0; right: 0; height: 100%; width: 34px;
  display: grid; place-items: center; cursor: pointer;
  background: none; border: 0; padding: 0; color: var(--muted);
}
.pw-auge:hover { color: var(--ink); }
/* Eine Marge verschiebt auch ein absolut gesetztes Element -- top: 0 allein
   genuegt nicht. Frueher gab die Zugangsseite jedem Knopf margin-top: 18px,
   und das Auge sass um genau das zu tief. Die Rueckstellung bleibt, damit die
   naechste Knopfregel nicht dasselbe anrichtet; zwei Klassen, damit sie gegen
   ein "bereich button" gewinnt. */
.pw-feld > .pw-auge { margin: 0; }
.zugangsform label .pw-feld { margin-top: 5px; }
.zugangsform label .pw-feld > input { margin-top: 0; }

input[type=color] { width: 52px; height: 32px; padding: 2px; border: 1px solid var(--line); border-radius: var(--ax-radius-sm); background: #fff; }
.row { display: flex; gap: 10px; align-items: center; margin-bottom: 14px; }
.row label { margin: 0; white-space: nowrap; }

/* Axiom's accent is a bright lime: it carries dark text. White on it fails
   contrast badly, which is exactly the mistake the token names invite. */
button {
  padding: 7px 14px;
  border-radius: var(--ax-radius-sm);
  border: 1px solid var(--ax-bg-accent);
  background: var(--ax-bg-accent);
  color: var(--ax-fg-default);
  font-weight: 600;
  cursor: pointer;
}
button:hover { background: var(--ax-bg-accent-hovered); border-color: var(--ax-bg-accent-hovered); }
button:active { background: var(--ax-bg-accent-pressed); border-color: var(--ax-bg-accent-pressed); }
button.ghost, .filebtn {
  background: var(--ax-bg-default);
  color: var(--ax-fg-default);
  border-color: var(--ax-border-control);
  font-weight: 500;
}
button.ghost:hover { background: var(--ax-bg-secondary); border-color: var(--ax-border-control); }
:is(button, input, select, textarea, .dropzone, a):focus-visible {
  outline: 2px solid var(--ax-border-focus);
  outline-offset: 1px;
}
button:disabled { opacity: .5; cursor: default; }
.filebtn { display: inline-block; padding: 8px 14px; border: 1px solid var(--accent); border-radius: var(--ax-radius-sm); cursor: pointer; font-size: 15px; }
.actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.status { font-size: 13px; color: var(--muted); }
.status.ok { color: var(--ax-fg-success-strong); }
.status.err, .err { color: var(--err); }
.hint { font-size: 12px; color: var(--muted); margin: 8px 0 0; }

/* Fields carry a dozen attributes now; a table row cannot hold them legibly. */
.fieldlist { display: grid; gap: 10px; margin-bottom: 12px; }
.field { border: 1px solid var(--ax-border-secondary); border-radius: var(--ax-radius-md); padding: 10px; background: var(--ax-bg-secondary); }
/* Jedes Bedienelement traegt seine Beschriftung.
   Vorher hingen fuenf Auswahlfelder ohne jedes Wort nebeneinander und die
   Texteingaben hatten nur einen Platzhalter -- der verschwindet, sobald etwas
   drinsteht. Wer eine bestehende Vorlage oeffnet, sah Werte, ohne zu wissen,
   wofuer sie stehen. */
.feld-kopf { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.feld-marke {
  font-size: var(--ax-text-xs); text-transform: uppercase; letter-spacing: .06em;
  font-weight: 700; color: var(--muted);
}
/* Automatische Spalten: die Felder ordnen sich nach dem verfuegbaren Platz,
   statt in einem festen Raster zu klemmen, das je nach Fensterbreite mal zu
   eng und mal zu weit ist. */
.feld-raster {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 8px 10px;
  align-items: end;
}
.feld-raster > label {
  display: flex; flex-direction: column; gap: 6px; min-width: 0;
  font-size: var(--ax-text-xs); color: var(--muted); font-weight: 600;
}
/* Was Platz braucht, bekommt die ganze Zeile. */
.feld-raster > .z-weit { grid-column: 1 / -1; }
/* Ein Kaestchen steht neben seinem Text, nicht darunter. */
.feld-raster > .z-kasten {
  flex-direction: row; align-items: center; gap: 6px;
  color: var(--ink); font-weight: 500;
}
.feld-raster > .z-kasten input { width: auto; }
.loc-raster { grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
.field input, .field select { padding: 6px 8px; font-size: 13px; }
.field .f-del, .field .l-del { padding: 2px 9px; font-size: 15px; line-height: 1.2; }

table { width: 100%; border-collapse: collapse; font-size: 13px; }
th { text-align: left; font-weight: 600; color: var(--muted); padding: 4px 6px 6px; font-size: 12px; }
td { padding: 3px 4px; }
td.center { text-align: center; }
td input[type=text] { padding: 5px 7px; }
.assets { list-style: none; padding: 0; margin: 10px 0 0; font-size: 13px; }
.assets li { padding: 4px 0; border-bottom: 1px solid var(--line); color: var(--muted); }

/* Side by side wherever there is room: the point of the two previews is
   seeing the platform differences at a glance, and stacked they never
   share a screen. They wrap on narrow windows. */
/* Breite und Abstand der Telefone an einer Stelle: die Live-Voransicht
   darunter rechnet damit, statt eine eigene Zahl zu fuehren. */
:root { --telefon-breite: 300px; --telefon-abstand: 22px; }
.previews { display: flex; flex-direction: column; align-items: center; gap: 14px; }
.telefon-reihe { display: flex; flex-wrap: wrap; gap: var(--telefon-abstand); justify-content: center; align-items: start; }
.previews h3 { font-size: 13px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin: 0 0 8px; }
.previews h3 small { text-transform: none; letter-spacing: 0; font-weight: 400; }

/* The three preview colours arrive through custom properties that the editor
   rewrites in a constructed stylesheet. Setting element.style directly would
   be an inline style, which the Content-Security-Policy blocks. */
:root { --pv-bg: rgb(18,52,86); --pv-fg: #fff; --pv-label: rgb(160,190,225); }

/* Everything below renders the PASS and the phone around it, not the tool.
   Its colours come from the template being designed, so Axiom tokens have no
   business here — the preview has to look like a phone, not like the editor. */

/* ---------------------------------------------------------------- devices
   Phone frames drawn in CSS rather than shipped as images: the page runs
   under img-src 'self', and a bitmap mockup would also age badly. They are a
   frame of reference for judging contrast and text length, not a rendering
   of the real Wallet apps. */
.preview-block { display: grid; justify-items: center; align-content: start; width: var(--telefon-breite); }
.preview-block .hint { text-align: center; }
.device { width: var(--telefon-breite); border-radius: 42px; padding: 11px; background: linear-gradient(160deg, #3a3d42, #17181b 40%, #2b2e33); box-shadow: 0 10px 28px rgba(0,0,0,.28); }
.device-screen { position: relative; border-radius: 32px; overflow: hidden; height: 580px; display: flex; flex-direction: column; }
.device-ios .device-screen { background: #0b0b0d; }
.device-android .device-screen { background: var(--pv-bg); }

.statusbar { display: flex; justify-content: space-between; align-items: center; padding: 11px 22px 4px; font-size: 11px; font-weight: 600; color: #fff; }
.statusbar-icons { width: 44px; height: 9px; border-radius: 2px;
  background: linear-gradient(90deg, #fff 0 12px, transparent 12px 15px, #fff 15px 26px, transparent 26px 29px, #fff 29px 44px); opacity: .85; }

/* Dynamic Island. */
.device-ios .device-screen::before { content: ""; position: absolute; top: 9px; left: 50%; transform: translateX(-50%); width: 82px; height: 23px; border-radius: 12px; background: #000; z-index: 3; }
.ios-title { color: #fff; font-size: 26px; font-weight: 700; padding: 6px 18px 10px; }

/* Lock-screen notification: the one place the icon is ever seen. */
.notif { display: flex; align-items: center; gap: 9px; margin: 0 12px 10px; padding: 8px 10px;
  border-radius: 12px; background: rgba(255,255,255,.14); backdrop-filter: blur(2px); }
.notif-icon { width: 26px; height: 26px; border-radius: 6px; object-fit: cover; flex: none;
  background: rgba(255,255,255,.25); }
.notif-text { min-width: 0; }
.notif-org { color: #fff; font-size: 11px; font-weight: 600; }
.notif-msg { color: rgba(255,255,255,.75); font-size: 11px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.home-indicator { margin: auto auto 8px; width: 108px; height: 4px; border-radius: 2px; background: rgba(255,255,255,.55); }

/* Punch-hole camera. */
.punchhole { position: absolute; top: 10px; left: 50%; transform: translateX(-50%); width: 11px; height: 11px; border-radius: 50%; background: #000; z-index: 3; }
.nav-pill { margin: auto auto 8px; width: 96px; height: 4px; border-radius: 2px; background: rgba(255,255,255,.7); }

/* Apple: one contained card, fields stacked, barcode at the bottom. */
.pk { margin: 0 12px; border-radius: 14px; padding: 14px; display: flex; flex-direction: column; gap: 12px; box-shadow: 0 2px 10px rgba(0,0,0,.35); background: var(--pv-bg); color: var(--pv-fg); }
.pk-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.pk { position: relative; }
/* Event tickets put artwork behind the whole card; the fields sit on top. */
.pk-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  border-radius: var(--ax-radius-lg); z-index: 0; }
.pk > *:not(.pk-bg) { position: relative; z-index: 1; }
.pk-logo { max-height: 30px; max-width: 118px; object-fit: contain; }
/* The strip sits full-bleed behind the primary row on store cards and coupons. */
.pk-strip { display: block; width: calc(100% + 28px); margin: -4px -14px 0; height: 62px; object-fit: cover; }
.pk-primary { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.pk-primary-text { min-width: 0; }
.pk-thumb { width: 46px; height: 46px; border-radius: 4px; object-fit: cover; flex: none; }
.pk-org { font-size: 12px; font-weight: 600; }
.pk-header-fields { display: flex; gap: 12px; text-align: right; }
.pk-label { display: block; font-size: 9px; text-transform: uppercase; letter-spacing: .06em; color: var(--pv-label); }
.pk-value { display: block; font-size: 22px; font-weight: 600; }
.pk-secondary, .pk-auxiliary { display: flex; gap: 18px; flex-wrap: wrap; }
.pk-secondary-value { display: block; font-size: 14px; }
.pk-aux-value { display: block; font-size: 12px; }
.pk-barcode { background: #fff; border-radius: var(--ax-radius-md); padding: 8px; display: grid; place-items: center; gap: 5px; }
.pk-barcode span { font-size: 10px; color: #333; font-family: ui-monospace, monospace; }

/* Google 2026: edge-to-edge colour, full-width hero, content in a light sheet. */
.gw { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.gw-hero { height: 96px; background: var(--pv-bg); filter: brightness(.85); overflow: hidden; }
.gw-hero img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gw-head { display: flex; align-items: center; gap: 10px; }
.gw-logo { width: 34px; height: 34px; border-radius: 50%; object-fit: cover; flex: none;
  border: 1px solid rgba(0,0,0,.08); background: #fff; }
.gw-sub { font-size: 12px; color: #66717f; }
.gw-sheet { background: #fff; border-radius: 20px 20px 0 0; margin-top: -14px; padding: 16px; display: flex; flex-direction: column; gap: 12px; flex: 1; color: #1c2430; }
.gw-org { font-size: 19px; font-weight: 600; line-height: 1.2; }
.gw-rows { display: grid; gap: 9px; }
.gw-row { display: flex; justify-content: space-between; gap: 12px; }
.gw-row-item { display: grid; gap: 1px; }
.gw-row-item.center { text-align: center; }
.gw-row-item.end { text-align: right; }
.gw-row-label { font-size: 10px; color: #66717f; text-transform: uppercase; letter-spacing: .05em; }
.gw-row-value { font-size: 14px; }
.gw-barcode { margin-top: auto; display: grid; place-items: center; gap: 5px; }
.gw-barcode span { font-size: 10px; color: #555; font-family: ui-monospace, monospace; }

/* The barcode is drawn per format, because the shapes differ enough to change
   the layout: a PDF417 is a wide band, a QR is a square. Not scannable — the
   preview is about proportion and placement, not payload. */
.code { border-radius: 2px; }
.code[data-format="QR"] {
  width: 68px; height: 68px; border: 3px solid #111;
  background: repeating-conic-gradient(#111 0% 25%, #fff 0% 50%) 0 0 / 11px 11px;
}
.code[data-format="AZTEC"] {
  width: 68px; height: 68px; border: 3px solid #111;
  background:
    radial-gradient(#111 0 22%, #fff 22% 34%, #111 34% 46%, #fff 46% 58%, transparent 58%),
    repeating-conic-gradient(#111 0% 25%, #fff 0% 50%) 0 0 / 9px 9px;
}
.code[data-format="PDF417"] {
  width: 132px; height: 44px; border: 2px solid #111;
  background:
    repeating-linear-gradient(90deg, #111 0 2px, #fff 2px 4px, #111 4px 5px, #fff 5px 9px,
      #111 9px 12px, #fff 12px 13px);
}
.code[data-format="CODE128"] {
  width: 132px; height: 40px;
  background:
    repeating-linear-gradient(90deg, #111 0 3px, #fff 3px 5px, #111 5px 6px, #fff 6px 10px,
      #111 10px 12px, #fff 12px 15px);
}

/* ------------------------------------------------------------- dropzones
   Click and keyboard stay available: a drop-only control is unusable with a
   keyboard, and browsers still differ on what a drag actually delivers. */
.dropzone {
  border: 2px dashed var(--ax-border-control);
  border-radius: var(--ax-radius-md);
  padding: 18px 14px;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
  cursor: pointer;
  background: var(--ax-bg-default);
  transition: border-color .12s, background .12s;
  display: grid;
  gap: 10px;
  justify-items: center;
}
.dropzone:hover, .dropzone:focus-visible { border-color: var(--accent); color: var(--ink); }
.dropzone:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Set while a file hovers over the zone, so the target is unmistakable. */
.dropzone.over { border-color: var(--ax-border-focus); background: var(--ax-bg-information-subtle); color: var(--ink); }
.dropzone.filled { border-style: solid; border-color: var(--ax-border-success); background: var(--ax-bg-accent-subtle); }
.dropzone small { font-weight: 400; opacity: .8; }
.dropzone-inline { padding: 8px 14px; }
.dz-preview { max-width: 160px; max-height: 90px; border-radius: 4px; border: 1px solid var(--line); background: #fff; }

/* Unsaved work is easy to lose behind a template switch; say so plainly. */
.dirty { font-size: var(--ax-text-sm); font-weight: 600; color: var(--ax-fg-warning-strong); background: var(--ax-bg-warning-subtle);
  border: 1px solid var(--ax-border-warning); border-radius: 999px; padding: 2px 10px; white-space: nowrap; }
.archived-note { font-size: var(--ax-text-sm); color: var(--ax-fg-warning-strong); margin: 0 0 12px; }

/* -------------------------------------------------------------- overview
   Counts, not charts: a handful of headline numbers is a KPI row, and a
   one-bar bar chart would say less than the number itself. */
.hero { margin-bottom: 26px; }
.hero-label { font-size: 13px; color: var(--muted); margin: 0 0 2px; }
/* Proportional figures: tabular would space a display-size number loosely. */
.hero-value { font-size: 54px; line-height: 1; font-weight: 650; margin: 0; letter-spacing: -.02em; }
.hero-note { font-size: 13px; color: var(--muted); margin: 6px 0 0; }

.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); gap: 12px; }
.kpi { border: 1px solid var(--ax-border-secondary); border-radius: var(--ax-radius-lg); padding: 14px 16px; background: var(--ax-bg-default); }
.kpi-label { font-size: 12px; color: var(--muted); margin: 0 0 4px; }
.kpi-value { font-size: 26px; font-weight: 650; margin: 0; line-height: 1.1; }
.kpi-note { font-size: 12px; color: var(--muted); margin: 4px 0 0; }

.overview-head { font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); margin: 28px 0 10px; font-weight: 600; }

.statuslist { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.statuslist li { display: flex; align-items: baseline; gap: 10px; font-size: 14px;
  border: 1px solid var(--line); border-radius: var(--ax-radius-md); padding: 10px 14px; }
.statuslist .st-detail { color: var(--muted); font-size: 13px; margin-left: auto; text-align: right; }

/* Status colours never carry meaning alone: each pill has its own wording. */
.pill { font-size: 12px; font-weight: 650; border-radius: 999px; padding: 2px 10px;
  white-space: nowrap; border: 1px solid transparent; }
.pill-good     { color: var(--ax-fg-success-strong); background: var(--ax-bg-success-subtle); border-color: var(--ax-border-success); }
.pill-warning  { color: var(--ax-fg-warning-strong); background: var(--ax-bg-warning-subtle); border-color: var(--ax-border-warning); }
.pill-critical { color: var(--ax-fg-error-strong); background: var(--ax-bg-error-subtle); border-color: var(--ax-border-error); }
.pill-idle     { color: var(--ax-fg-tertiary); background: var(--ax-bg-secondary); border-color: var(--line); }

/* ------------------------------------------------------------------ help */
.help-body { max-width: 74ch; }
.help-body h2 { font-size: 21px; margin: 30px 0 10px; font-weight: 650; }
.help-body h2:first-child { margin-top: 0; }
.help-body h3 { font-size: 15px; margin: 22px 0 8px; font-weight: 650; }
.help-body p, .help-body li { font-size: 14.5px; line-height: 1.6; }
.help-body pre { background: var(--ax-bg-secondary); border: 1px solid var(--line); border-radius: var(--ax-radius-md);
  padding: 12px 14px; overflow-x: auto; font-size: 13px; line-height: 1.5; }
.help-body code { font-family: var(--ax-font-mono);
  font-size: .88em; background: var(--ax-bg-secondary); border-radius: 4px; padding: 1px 5px; }
.help-body pre code { background: none; padding: 0; }
.help-body table { width: 100%; border-collapse: collapse; font-size: 14px; margin-bottom: 16px; }
.help-body th { text-align: left; font-size: 11.5px; text-transform: uppercase;
  letter-spacing: .07em; color: var(--muted); padding-bottom: 8px; border-bottom: 1px solid var(--line); }
.help-body td { padding: 9px 12px 9px 0; border-bottom: 1px solid var(--line); vertical-align: top; }
.help-body .warnbox { border: 1px solid var(--ax-border-warning); background: var(--ax-bg-warning-subtle); border-radius: var(--ax-radius-md);
  padding: 12px 14px; margin: 0 0 16px; font-size: 14px; }
.help-body .table-wrap { overflow-x: auto; }

/* ---------------------------------------------------------------- artwork
   One tab per role, because a role is what decides where the image lands —
   a flat list of files hides exactly the thing that matters. */
.art-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.art-tab {
  background: var(--ax-bg-default); color: var(--ax-fg-secondary);
  border: 1px solid var(--ax-border-control); border-radius: var(--ax-radius-sm);
  padding: 5px 11px; font-size: var(--ax-text-sm); font-weight: 500; cursor: pointer;
  display: flex; align-items: center; gap: 6px;
}
.art-tab[aria-selected="true"] {
  background: var(--ax-bg-accent); border-color: var(--ax-bg-accent); color: var(--ax-fg-default);
  font-weight: 650;
}
/* A filled role is marked, so the tabs double as an overview. */

.art-where { font-size: var(--ax-text-sm); color: var(--ax-fg-tertiary); margin: 0 0 12px; }
.art-slots { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
.art-slot { border: 1px solid var(--ax-border-secondary); border-radius: var(--ax-radius-md);
  padding: 10px; display: grid; gap: 8px; justify-items: center; text-align: center; }
.art-slot h4 { margin: 0; font-size: var(--ax-text-sm); font-weight: 650; }
.art-slot .dims { font-size: var(--ax-text-xs); color: var(--ax-fg-tertiary); }
.art-slot img { max-width: 100%; max-height: 64px; object-fit: contain;
  background: repeating-conic-gradient(#e9eee6 0% 25%, #fff 0% 50%) 0 0 / 10px 10px;
  border: 1px solid var(--line); border-radius: var(--ax-radius-xs); }
.art-slot .dropzone { padding: 12px 8px; font-size: var(--ax-text-xs); width: 100%; }
.art-slot button { padding: 4px 10px; font-size: var(--ax-text-xs); }

/* --- Verwaltungslisten: Benutzer und Mandanten -------------------------- */
.admin-head { display: flex; align-items: start; justify-content: space-between; gap: 20px; margin-bottom: 16px; }
.admin-head h2 { margin: 0 0 4px; font-size: 15px; }
.admin-head .hint { margin: 0; max-width: 62ch; }

/* Das Einladungsformular klappt ueber der Liste auf, statt auf eine eigene
   Seite zu fuehren: wer einlaedt, will danach die Liste sehen. */
.einladung {
  border: 1px solid var(--ax-border-secondary);
  border-radius: var(--ax-radius-md);
  background: var(--surface-2);
  padding: 14px; margin-bottom: 16px;
}
.einladung .row { gap: 12px; align-items: end; flex-wrap: wrap; }
.einladung label { display: flex; flex-direction: column; gap: 4px; font-size: var(--ax-text-sm); font-weight: 600; }

.liste { width: 100%; border-collapse: collapse; font-size: var(--ax-text-sm); }
.liste th {
  text-align: left; font-size: var(--ax-text-xs); text-transform: uppercase;
  letter-spacing: .05em; color: var(--muted); font-weight: 600;
  padding: 6px 10px; border-bottom: 1px solid var(--line);
}
.liste td { padding: 9px 10px; border-bottom: 1px solid var(--ax-border-secondary); vertical-align: middle; }
.liste tr:last-child td { border-bottom: none; }
.liste .zeilen-aktionen { display: flex; gap: 6px; justify-content: end; flex-wrap: wrap; }
.liste .zeilen-aktionen button { padding: 4px 10px; font-size: var(--ax-text-xs); }
.liste td select { padding: 4px 6px; font-size: var(--ax-text-xs); width: auto; }
/* Die eigene Zeile: was hier nicht geht, soll man sehen statt es zu versuchen. */
.liste tr.ich td { background: var(--ax-bg-accent-subtle); }
.liste tr.ich .selbst { font-size: var(--ax-text-xs); color: var(--muted); }

/* Zustand als Wort mit Farbe, nicht als Farbe allein. */
.zustand { font-weight: 600; font-size: var(--ax-text-xs); }
.zustand-active { color: var(--ax-fg-success-strong); }
.zustand-invited { color: var(--ax-fg-information); }
.zustand-disabled { color: var(--ax-fg-error-strong); }

/* --- Wallets: anlegen und Uebersicht ------------------------------------ */
.tpl-titel { font-weight: 600; }
#newPassForm .row { gap: 14px; align-items: end; flex-wrap: wrap; }
#newPassForm > .row > label { display: flex; flex-direction: column; gap: 4px; font-size: var(--ax-text-sm); font-weight: 600; }
#newPassForm fieldset .row > label { display: flex; flex-direction: column; gap: 4px; font-size: var(--ax-text-sm); font-weight: 600; }
#newPassForm legend small { font-weight: 400; color: var(--muted); text-transform: none; letter-spacing: 0; }

/* Der Link ist das Ergebnis; er soll sich auf einen Blick greifen lassen. */
.fertig-karte {
  border: 1px solid var(--ax-border-success);
  border-radius: var(--ax-radius-md);
  background: var(--ax-bg-success-subtle);
  padding: 16px;
}
.fertig-karte h3 { margin: 0 0 6px; font-size: 15px; }
.fertig-karte .row { gap: 8px; margin-top: 12px; }
.fertig-karte input { font-family: var(--ax-font-mono, ui-monospace, monospace); font-size: var(--ax-text-xs); }

/* Werte eines Passes: Beschriftung links, Eingabe rechts, damit lange
   Feldnamen die Spalte nicht auseinanderziehen. */
.wertfeld { display: grid; grid-template-columns: minmax(120px, 220px) 1fr; gap: 10px; align-items: center; margin-bottom: 8px; }
.wertfeld label { font-size: var(--ax-text-sm); font-weight: 600; }
.wertfeld .pflicht { color: var(--ax-fg-error-strong); }
/* Ein Knopf, der wie ein Link aussieht: die Zeile ist der Weg in den Editor. */
.linkish-inline {
  background: none; border: none; padding: 0;
  color: var(--ax-fg-information); font: inherit; font-weight: 600;
  text-align: left; cursor: pointer; text-decoration: underline;
}

/* --- Vorlagen als Karten ------------------------------------------------
   Card-Muster des Design Systems: eine Flaeche mit Rand und Radius, oben das
   Bild, darunter Text, unten die Aktionen. Die Vorschau steht oben, weil eine
   Vorlage vor allem daran erkannt wird, wie sie aussieht -- nicht am Namen. */
.kopf-knoepfe { display: flex; gap: 8px; flex-wrap: wrap; }
.karten {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 16px;
}

.karte {
  display: flex; flex-direction: column;
  border: 1px solid var(--ax-border-secondary);
  border-radius: var(--ax-radius-lg);
  background: var(--panel);
  box-shadow: var(--ax-shadow-sm);
  transition: box-shadow .12s ease, border-color .12s ease;
}
.karte:hover { box-shadow: var(--ax-shadow-lg); border-color: var(--ax-border-default); }
/* Archiviert: sichtbar zurueckgenommen, aber lesbar -- ausgegraut allein
   waere eine Farbaussage, die niemand mit Sehschwaeche mitbekommt. */
.karte.archiviert { opacity: .72; }

/* Die Miniatur des Passes. Farben kommen je Karte aus einem gebauten
   Stylesheet, weil style-Attribute unter der CSP nicht erlaubt sind. */
.karte-vorschau {
  padding: 14px; min-height: 132px;
  border-radius: calc(var(--ax-radius-lg) - 1px) calc(var(--ax-radius-lg) - 1px) 0 0;
  display: flex; flex-direction: column; gap: 8px;
  background: var(--pv-bg, #1b2a4a);
  color: var(--pv-fg, #fff);
}
.kv-kopf { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.kv-org { font-size: 11px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kv-typ { font-size: 9px; text-transform: uppercase; letter-spacing: .06em; color: var(--pv-label, #b4c8e6); flex: none; }
.kv-label { font-size: 9px; text-transform: uppercase; letter-spacing: .06em; color: var(--pv-label, #b4c8e6); }
.kv-wert { font-size: 17px; font-weight: 700; line-height: 1.1; }
.kv-code {
  margin-top: auto; height: 26px; border-radius: 4px; background: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 8px; letter-spacing: .1em; color: #333;
}

.karte-text { padding: 12px 14px 0; flex: 1; }
.karte-text h3 { margin: 0 0 2px; font-size: 14px; }
.karte-text p { margin: 0; font-size: var(--ax-text-sm); color: var(--muted); }
.karte-meta { display: flex; gap: 8px; flex-wrap: wrap; padding: 8px 14px 0; font-size: var(--ax-text-xs); color: var(--muted); }
.karte-aktionen { display: flex; gap: 6px; padding: 12px 14px; flex-wrap: wrap; }
.karte-aktionen button { padding: 5px 12px; font-size: var(--ax-text-xs); }

/* --- Einklappbare Bereiche im Editor ------------------------------------
   <details>/<summary> statt eigener Auf-und-Zu-Logik: das Aufklappen macht
   der Browser, mit Tastatur und Vorlesehilfe inklusive. */
#templateEditor fieldset { padding: 0; border: 1px solid var(--ax-border-secondary); }
#templateEditor fieldset > legend { display: none; }
.klapp > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px;
  font-size: var(--ax-text-xs); text-transform: uppercase; letter-spacing: .06em;
  font-weight: 700; color: var(--muted);
}
.klapp > summary::-webkit-details-marker { display: none; }
/* Der Pfeil dreht sich beim Aufklappen -- die einzige Stelle, an der man den
   Zustand sieht, wenn der Inhalt weg ist. */
.klapp > summary::after {
  content: ""; width: 0; height: 0; flex: none;
  margin-left: auto;
  border-left: 5px solid currentColor;
  border-top: 4px solid transparent; border-bottom: 4px solid transparent;
  transition: transform .12s ease;
}
.klapp[open] > summary::after { transform: rotate(90deg); }
.klapp > summary:hover { color: var(--ink); background: var(--surface-2); }
.klapp-inhalt { padding: 0 12px 12px; }

/* Farben nebeneinander statt untereinander: drei Waehler brauchen keine
   dreifache Hoehe. */
.farbreihe { display: flex; gap: 18px; flex-wrap: wrap; }
.farbreihe label { display: flex; flex-direction: column; gap: 6px; font-size: var(--ax-text-sm); }

/* --- Plattform-Bereiche: Apple und Google je eigene Karte ---------------- */
.plattformen { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px; margin-bottom: 24px; }
.plattform-karte {
  border: 1px solid var(--ax-border-secondary);
  border-radius: var(--ax-radius-lg);
  background: var(--surface-2);
  padding: 16px;
}
.plattform-kopf h3 { margin: 0 0 8px; font-size: 15px; }
.plattform-status dl { display: grid; grid-template-columns: auto 1fr; gap: 3px 12px; margin: 0 0 14px; font-size: var(--ax-text-xs); }
.plattform-status dt { color: var(--muted); }
.plattform-status dd { margin: 0; word-break: break-all; }
.plattform-status .warn { color: var(--ax-fg-error-strong); font-weight: 600; }
.plattform-leer { margin-bottom: 14px; font-size: var(--ax-text-sm); color: var(--muted); }
.plattform-karte .dropzone { margin-bottom: 10px; }
.plattform-karte label { display: flex; flex-direction: column; gap: 4px; font-size: var(--ax-text-sm); font-weight: 600; margin-bottom: 10px; }

/* --- Drei-Punkte-Menue --------------------------------------------------- */
.menue { position: relative; margin-left: auto; }
.menue-knopf {
  width: 30px; height: 28px; padding: 0;
  border: 1px solid var(--line); border-radius: var(--ax-radius-md);
  background: transparent; color: var(--muted);
  font-size: 16px; line-height: 1; cursor: pointer;
}
.menue-knopf:hover { background: var(--surface-2); color: var(--ink); }
.menue-liste {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 20;
  min-width: 168px; padding: 4px;
  border: 1px solid var(--line); border-radius: var(--ax-radius-md);
  background: var(--panel); box-shadow: var(--ax-shadow-lg);
}
.menue-eintrag {
  display: block; width: 100%; padding: 7px 10px;
  border: none; border-radius: var(--ax-radius-sm); background: transparent;
  font: inherit; font-size: var(--ax-text-sm); text-align: left;
  color: var(--ink); cursor: pointer;
}
.menue-eintrag:hover { background: var(--surface-2); }

/* --- Abholung: Code und Link nebeneinander ------------------------------- */
.abholung { display: flex; gap: 18px; align-items: start; flex-wrap: wrap; margin-top: 12px; }
.abhol-qr { border: 1px solid var(--ax-border-secondary); border-radius: var(--ax-radius-md); background: #fff; flex: none; }
.abhol-text { flex: 1; min-width: 240px; }
.abhol-text .hint { margin: 0 0 8px; }

/* Suche und Filter nebeneinander; sie gehoeren zusammen und passen in eine
   Zeile, solange Platz ist. */
.filterzeile { display: flex; gap: 16px; align-items: end; flex-wrap: wrap; margin-bottom: 16px; }
.filterzeile label { display: flex; flex-direction: column; gap: 4px; font-size: var(--ax-text-sm); font-weight: 600; }
.filterzeile input { min-width: 240px; }
.filterzeile select { width: auto; }

/* Name plus Speichern in einer Zelle. */
.name-zeile { display: flex; gap: 6px; align-items: center; }
.name-zeile input { min-width: 150px; }

/* --- Tabellen nach dem Muster des Design Systems ------------------------- */
/* Kopfzeile abgesetzt, Zeilen mit Innenabstand und ruhigem Wechsel beim
   Ueberfahren -- eine Liste, die man mit dem Finger verfolgen kann. */
.liste { border: 1px solid var(--ax-border-secondary); border-radius: var(--ax-radius-lg); overflow: hidden; }
.liste thead { background: var(--surface-2); }
.liste th { padding: 10px 14px; border-bottom: 1px solid var(--ax-border-secondary); }
.liste td { padding: 11px 14px; }
.liste tbody tr:hover td { background: var(--surface-2); }
.liste tbody tr.ich:hover td { background: var(--ax-bg-accent-subtle); }

/* Ohne Code sitzt der Wert direkt ueber dem unteren Rand der Vorschau. */
.karte-vorschau:not(:has(.kv-code)) .kv-wert { margin-bottom: auto; }

/* --- Kopfzeile des Editors ---------------------------------------------- */
/* Zurueck links, Titel daneben, die Aktionen zur Vorlage rechts -- alles in
   einer Zeile, damit der Editor darunter ungeteilt beginnt. */
.editor-kopf { display: flex; align-items: center; gap: 10px; flex-wrap: nowrap; margin-bottom: 16px; }
.editor-kopf-aktionen { display: flex; align-items: center; gap: 6px; margin-left: auto; flex: none; }
#templateBack { flex: none; }
.editor-kopf-aktionen select { width: auto; max-width: 150px; }
/* Kompakter als die Knoepfe im Formular: hier stehen drei nebeneinander in
   einer Spalte, die sich die Breite mit der Vorschau teilt. */
.editor-kopf-aktionen button { padding: 5px 10px; font-size: var(--ax-text-xs); }
/* Der Titel gibt nach, nicht die Knoepfe -- er ist der einzige Teil, der sich
   kuerzen laesst, ohne dass etwas unbedienbar wird. */
.tpl-titel {
  min-width: 0; flex: 0 1 auto;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* --- Zuschneiden ---------------------------------------------------------
   Der Ausschnitt wird auf die Leinwand gezeichnet, nicht als verschobenes
   Element gebaut: unter style-src 'self' laesst sich kein Element bei jeder
   Mausbewegung neu positionieren, und gezeichnet ist es ohnehin ruhiger. */
.modal {
  position: fixed; inset: 0; z-index: 100;
  display: flex; align-items: center; justify-content: center;
  padding: 20px; background: rgb(0 0 0 / .45);
}
.modal-karte {
  background: var(--panel); border-radius: var(--ax-radius-lg);
  box-shadow: var(--ax-shadow-lg); padding: 22px;
  max-width: 580px; width: 100%; max-height: 90vh; overflow-y: auto;
}
.modal-karte h2 { margin: 0 0 6px; font-size: 16px; }
.modal-aktionen { display: flex; gap: 8px; margin-top: 16px; flex-wrap: wrap; }
/* Eine curl-Zeile ist laenger als ein Formular breit ist. */
.modal-breit { max-width: 760px; }
.api-block { border-top: 1px solid var(--line); padding-top: 14px; margin-top: 14px; }
.api-block:first-child { border-top: 0; padding-top: 0; margin-top: 10px; }
.api-kopf { display: flex; align-items: baseline; gap: 8px; margin-bottom: 4px; }
.api-kopf h3 { margin: 0; font-size: 14px; }
.api-methode { font-family: var(--ax-font-mono); font-size: 11px; letter-spacing: .04em;
  background: var(--ax-bg-accent-subtle); border-radius: var(--ax-radius-sm); padding: 1px 6px; }
.api-block pre { background: var(--ax-bg-secondary); border: 1px solid var(--line);
  border-radius: var(--ax-radius-md); padding: 12px 14px; overflow-x: auto;
  font-size: 12.5px; line-height: 1.5; margin: 8px 0 0; }
.api-block pre code { font-family: var(--ax-font-mono); background: none; padding: 0; }
.api-block .hint { margin: 6px 0 0; }
.api-kopieren { margin-top: 8px; }

.crop-buehne {
  margin: 14px 0 10px;
  border: 1px solid var(--ax-border-secondary); border-radius: var(--ax-radius-md);
  background: var(--surface-2);
  display: flex; justify-content: center;
}
#cropCanvas { max-width: 100%; height: auto; touch-action: none; cursor: move; }
.crop-zoom { display: flex; align-items: center; gap: 10px; font-size: var(--ax-text-sm); font-weight: 600; }
.crop-zoom input { flex: 1; }
.crop-mit { display: flex; align-items: center; gap: 8px; margin-top: 12px; font-size: var(--ax-text-sm); }
.crop-mit input { width: auto; }

/* --- Vorschau laeuft mit ------------------------------------------------
   Beim Bearbeiten scrollt man durch ein langes Formular und will dabei sehen,
   was die Aenderung bewirkt. Ohne dies waeren die Telefone nach dem ersten
   Abschnitt aus dem Bild.

   Der Abstand nach oben haelt sie unter der Kopfzeile, die selbst klebt.
   max-height plus eigenes Scrollen fuer den Fall, dass das Fenster niedriger
   ist als die Telefone hoch sind -- sonst waere ihr unteres Ende abgeschnitten
   und nicht mehr erreichbar. */
#app.tpl-edit > .previews {
  position: sticky;
  top: calc(var(--topbar-hoehe, 57px) + 20px);
  max-height: calc(100vh - var(--topbar-hoehe, 57px) - 40px);
  overflow-y: auto;
  /* Ein Streifen Luft, damit der Schatten der Telefone nicht am Rand klebt. */
  padding: 2px;
}

/* --- Artwork entfernen --------------------------------------------------- */
.art-kopf { display: flex; align-items: start; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
.art-kopf .art-where { margin: 0; }
.art-kopf button { flex: none; padding: 4px 10px; font-size: var(--ax-text-xs); }

/* Entfernen ist die einzige Aktion am Platz und soll als solche erkennbar
   sein -- als graues Wort unter einer Miniatur ging sie unter. Rot umrandet
   statt rot gefuellt: es ist ein Ausweg, keine Hauptaktion. */
.loeschen {
  padding: 4px 10px; font-size: var(--ax-text-xs);
  border: 1px solid var(--ax-fg-error-strong);
  border-radius: var(--ax-radius-md);
  background: transparent; color: var(--ax-fg-error-strong);
  font-weight: 600; cursor: pointer;
}
.loeschen:hover { background: var(--ax-fg-error-strong); color: #fff; }

/* --- Vollstaendigkeit einer Bildrolle ------------------------------------
   Drei Zustaende mit je eigenem Zeichen, nicht nur eigener Farbe: Rot und
   Gruen sind fuer einen Teil der Leute dasselbe. */
.stand {
  width: 14px; height: 14px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%; font-size: 9px; font-weight: 800; line-height: 1;
  color: #fff;
}
.stand-voll { background: var(--ax-fg-success-strong); }
.stand-teil { background: #b8860b; }
.stand-leer { background: var(--ax-fg-error-strong); }

/* --- Herkunft eines Feldes ---------------------------------------------- */
.field-quelle { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--ax-border-secondary); }
.field-quelle label { display: flex; align-items: center; gap: 6px; font-size: var(--ax-text-xs); color: var(--muted); }
.field-quelle select { width: auto; max-width: 220px; }

/* --- Formular fuer einen API-Zugang -------------------------------------
   Felder untereinander ueber die volle Breite: es sind wenige, sie werden
   einmal ausgefuellt, und nebeneinander waeren sie so schmal, dass eine
   Client-ID oder eine Adresse nicht mehr hineinpasst. */
.zugangsform {
  border: 1px solid var(--ax-border-secondary);
  border-radius: var(--ax-radius-md);
  background: var(--surface-2);
  padding: 18px;
  max-width: 640px;
}
.zugangsform label {
  display: block;
  margin-bottom: 14px;
  font-size: var(--ax-text-sm);
  font-weight: 600;
}
.zugangsform label input { margin-top: 5px; }
.zugangsform .hint { margin: 0 0 16px; }
.zugangs-aktionen { display: flex; gap: 8px; flex-wrap: wrap; }

/* --- Live-Voransicht ----------------------------------------------------
   Aufbau wie im RCS-Editor: der Wechsel ist ein breiter, ruhiger Knopf, das
   Blaettern eine mittige Zeile aus Pfeil, Stand, Pfeil. */
.livevorschau {
  /* Genau die beiden Telefonspalten plus ihr Abstand. */
  width: calc(var(--telefon-breite) * 2 + var(--telefon-abstand));
  max-width: 100%;
  margin-top: 4px; padding: 14px;
  border: 1px solid var(--ax-border-secondary);
  border-radius: var(--ax-radius-md);
  background: var(--panel);
}
/* Ueber die ganze Breite, zurueckhaltend: es ist ein Umschalter, keine
   Hauptaktion neben "Speichern". */
.live-start {
  display: block; width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--ax-border-secondary);
  border-radius: var(--ax-radius-md);
  background: var(--surface-2); color: var(--ink);
  font: inherit; font-size: var(--ax-text-sm); font-weight: 600;
  cursor: pointer;
}
.live-start:hover { border-color: var(--line); background: var(--ax-bg-accent-subtle); }

.live-blaettern { display: flex; align-items: center; justify-content: center; gap: 14px; margin-bottom: 12px; }
.live-blaettern span { font-size: var(--ax-text-sm); font-weight: 600; min-width: 8ch; text-align: center; }
.live-pfeil {
  width: 30px; height: 26px; padding: 0;
  border: 1px solid var(--ax-border-secondary); border-radius: var(--ax-radius-sm);
  background: var(--surface-2); color: var(--muted);
  font-size: 11px; line-height: 1; cursor: pointer;
}
.live-pfeil:hover { color: var(--ink); border-color: var(--line); }
.live-suche { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; font-size: var(--ax-text-sm); font-weight: 600; }
.live-hinweis { margin: 10px 0 0; font-size: var(--ax-text-xs); color: var(--ax-fg-success-strong); }
/* Solange echte Daten gezeigt werden, soll man das sehen -- sonst haelt man
   fremde Werte fuer die eigenen Beispielwerte. */
.previews.live .device { outline: 2px solid var(--ax-fg-information); outline-offset: 6px; border-radius: 46px; }

/* --- Formular fuer einen API-Zugang -------------------------------------
   Felder untereinander ueber die volle Breite: es sind wenige, sie werden
   einmal ausgefuellt, und nebeneinander waeren sie so schmal, dass eine
   Client-ID oder eine Adresse nicht mehr hineinpasst. */
.zugangsform {
  border: 1px solid var(--ax-border-secondary);
  border-radius: var(--ax-radius-md);
  background: var(--surface-2);
  padding: 18px;
  max-width: 640px;
}
.zugangsform label {
  display: block;
  margin-bottom: 14px;
  font-size: var(--ax-text-sm);
  font-weight: 600;
}
.zugangsform label input { margin-top: 5px; }
.zugangsform .hint { margin: 0 0 16px; }
.zugangs-aktionen { display: flex; gap: 8px; flex-wrap: wrap; }

/* --- Live-Voransicht ---------------------------------------------------- */
.livevorschau {
  /* Genau die beiden Telefonspalten plus ihr Abstand. */
  width: calc(var(--telefon-breite) * 2 + var(--telefon-abstand));
  max-width: 100%;
  margin-top: 4px; padding: 14px;
  border: 1px solid var(--ax-border-secondary);
  border-radius: var(--ax-radius-md);
  background: var(--panel);
}
.live-kopf { display: flex; gap: 8px; flex-wrap: wrap; }
.live-suche { display: flex; flex-direction: column; gap: 4px; margin-top: 12px; font-size: var(--ax-text-sm); font-weight: 600; }
.live-blaettern { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.live-blaettern button { padding: 4px 12px; }
.live-blaettern span { font-size: var(--ax-text-sm); color: var(--muted); }
/* Solange echte Daten gezeigt werden, soll man das sehen -- sonst haelt man
   fremde Werte fuer die eigenen Beispielwerte. */
.previews.live .device { outline: 2px solid var(--ax-fg-information); outline-offset: 6px; border-radius: 46px; }

/* Der Vergleichswert steht zwischen Kennzeichen und Werten -- er entscheidet,
   womit die Werte gefuellt werden. */
#newPassMatchRow { margin-bottom: 14px; }
#newPassMatchRow label { display: flex; flex-direction: column; gap: 6px; font-size: var(--ax-text-sm); font-weight: 600; max-width: 420px; }
#newPassMatchRow .hint { margin: 6px 0 0; }
