/**
 * Komponentenbibliothek — der einzige erlaubte Baukasten für alle Module.
 * Jede Komponente stylt sich ausschließlich über Tokens (tokens.css).
 * Designsprache FLX: heller Solid-Primärbutton, indigo-akzentuierte
 * Sekundär-/Ghost-Zustände, Karten mit 10px-Radius, 36px-Bedienhöhe.
 */

/* ========== Button ========== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: var(--control-height);
  padding: 0 var(--space-4);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-surface-raised);
  color: var(--color-text);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  box-shadow: var(--shadow-xs);
  transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.btn svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.btn:hover {
  background: var(--color-accent-soft);
  border-color: var(--color-accent);
  color: var(--color-accent);
  text-decoration: none;
}

.btn:active {
  background: var(--color-accent-soft-strong);
}

.btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-color: var(--color-accent);
}

.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.5;
  pointer-events: none;
  box-shadow: none;
}

/* Primär — heller Solid-Button (FLX) */
.btn-primary {
  background: var(--color-solid);
  border-color: transparent;
  color: var(--color-on-solid);
  font-weight: var(--font-medium);
  box-shadow: var(--shadow-sm);
}

.btn-primary:hover {
  background: var(--color-solid-hover);
  border-color: transparent;
  color: var(--color-on-solid);
}

.btn-primary:active {
  background: var(--color-solid-active);
}

/* Ghost — transparent, indigo bei Interaktion */
.btn-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--color-text-secondary);
  box-shadow: none;
}

.btn-ghost:hover {
  background: var(--color-accent-soft);
  border-color: transparent;
  color: var(--color-text);
}

/* Gefährliche Aktion */
.btn-danger {
  background: var(--color-danger);
  border-color: transparent;
  color: #FFFFFF;
  box-shadow: var(--shadow-sm);
}

.btn-danger:hover {
  background: var(--color-danger-hover);
  border-color: transparent;
  color: #FFFFFF;
}

.btn-danger:focus-visible {
  box-shadow: var(--focus-ring-danger);
  border-color: var(--color-danger);
}

.btn-sm {
  height: var(--control-height-sm);
  padding: 0 var(--space-3);
  font-size: var(--text-xs);
}

.btn-lg {
  height: var(--control-height-lg);
  padding: 0 var(--space-5);
  font-size: var(--text-base);
}

/* Quadratisch, nur Icon */
.btn-icon {
  width: var(--control-height);
  padding: 0;
}

.btn-icon.btn-sm {
  width: var(--control-height-sm);
}

/* ========== Dropdown-Menü (native <details>) ========== */

.menu {
  position: relative;
}

.menu > summary {
  list-style: none;
}

.menu > summary::-webkit-details-marker,
.menu > summary::marker {
  display: none;
  content: "";
}

.menu > summary .chevron {
  width: 14px;
  height: 14px;
  transition: transform var(--transition-fast);
}

.menu[open] > summary .chevron {
  transform: rotate(180deg);
}

.menu-dropdown {
  position: absolute;
  top: calc(100% + var(--space-1));
  right: 0;
  min-width: 190px;
  display: grid;
  gap: 2px;
  padding: var(--space-1);
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  z-index: var(--z-dropdown);
}

/* Kippt nach oben, wenn unten kein Platz mehr ist — in einem scrollenden
   Dialog oder am unteren Bildschirmrand waere das Menue sonst abgeschnitten.
   Gesetzt wird die Klasse beim Aufklappen (assets/js/dialog.js). */
.menu-dropdown.is-above {
  top: auto;
  bottom: calc(100% + var(--space-1));
}

.menu-item {
  display: block;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--color-text-secondary);
  white-space: nowrap;
}

.menu-item:hover {
  background: var(--color-hover);
  color: var(--color-text);
  text-decoration: none;
}

/* Formular-Aktionen im Dropdown sehen aus wie Menü-Einträge. */
button.menu-item {
  width: 100%;
  text-align: left;
  border: none;
  background: none;
  cursor: pointer;
}

.menu-item-danger:hover {
  color: var(--color-danger-text);
}

/* ========== Formulare ========== */

.input,
.select,
.textarea {
  width: 100%;
  height: var(--control-height);
  padding: 0 var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: var(--text-sm);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.textarea {
  height: auto;
  min-height: 88px;
  padding: var(--space-2) var(--space-3);
  line-height: var(--leading-normal);
  resize: vertical;
}

.input::placeholder,
.textarea::placeholder {
  color: var(--color-text-tertiary);
}

.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--color-accent);
  box-shadow: var(--focus-ring);
}

.input:disabled,
.select:disabled,
.textarea:disabled {
  background: var(--color-surface-muted);
  color: var(--color-text-disabled);
  cursor: not-allowed;
}

.select {
  appearance: none;
  padding-right: var(--space-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M4 6l4 4 4-4' stroke='%23A1A1AA' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-3) center;
}

.checkbox,
.radio {
  width: 1rem;
  height: 1rem;
  accent-color: var(--color-accent);
  cursor: pointer;
}

/* Ungültige Eingaben */
.input-invalid,
.input-invalid:focus {
  border-color: var(--color-danger);
  box-shadow: var(--focus-ring-danger);
}

/* Feld-Gruppe: Label + Eingabe + Hinweis/Fehler */
.field {
  display: grid;
  gap: var(--space-2);
}

.field-label {
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  color: var(--color-text);
}

.field-label .required {
  color: var(--color-danger-text);
}

.field-hint {
  font-size: var(--text-xs);
  color: var(--color-text-tertiary);
}

.field-error {
  font-size: var(--text-xs);
  color: var(--color-danger-text);
}

/* ========== Badge ========== */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  height: 22px;
  padding: 0 var(--space-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface-muted);
  color: var(--color-text-secondary);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  line-height: 1;
  white-space: nowrap;
}

.badge-accent {
  background: var(--color-accent-soft);
  border-color: var(--color-accent);
  color: var(--color-accent-text);
}

.badge-success {
  background: var(--color-success-soft);
  border-color: var(--color-success);
  color: var(--color-success-text);
}

.badge-warning {
  background: var(--color-warning-soft);
  border-color: var(--color-warning);
  color: var(--color-warning-text);
}

.badge-danger {
  background: var(--color-danger-soft);
  border-color: var(--color-danger);
  color: var(--color-danger-text);
}

/* ========== Kennzahl-Kacheln (Dashboard-KPIs) ========== */

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-3);
}

.stat-tile {
  display: block;
  padding: var(--space-4) var(--space-5);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  color: inherit;
  text-decoration: none;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}

a.stat-tile:hover {
  border-color: var(--color-border-strong);
  background: var(--color-surface-muted);
  text-decoration: none;
}

.stat-tile-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  color: var(--color-text-tertiary);
}

.stat-tile-label {
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.stat-tile-icon {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  background: var(--color-accent-soft);
  color: var(--color-accent-text);
  display: grid;
  place-items: center;
}

.stat-tile-icon.is-danger {
  background: var(--color-danger-soft);
  color: var(--color-danger-text);
}

.stat-tile-icon svg {
  width: 16px;
  height: 16px;
}

.stat-tile-value {
  font-size: var(--text-2xl);
  font-weight: var(--font-semibold);
  line-height: 1;
  letter-spacing: -0.01em;
}

.stat-tile-value.is-danger { color: var(--color-danger-text); }
.stat-tile-value.is-warning { color: var(--color-warning-text); }

.stat-tile-hint {
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  color: var(--color-text-tertiary);
}

/* ========== Card ========== */

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-border);
}

.card-title {
  font-size: var(--text-md);
  font-weight: var(--font-semibold);
}

/* Beisatz unter dem Kartentitel — erklaert, wofuer die Karte da ist. */
.card-description {
  margin-top: 2px;
  font-size: var(--text-sm);
  color: var(--color-text-secondary);
}

.card-body {
  padding: var(--space-5);
}

.card-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-muted);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

/* ========== Tabelle ========== */

.table-container {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  overflow-x: auto;
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

.table th {
  padding: var(--space-3);
  text-align: left;
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  color: var(--color-text-tertiary);
  background: var(--color-surface-muted);
  border-bottom: 1px solid var(--color-border);
  white-space: nowrap;
}

.table td {
  padding: var(--space-3);
  border-bottom: 1px solid var(--color-border);
  vertical-align: middle;
}

.table tbody tr:last-child td {
  border-bottom: none;
}

.table tbody tr:hover {
  background: var(--color-hover);
}

/* Tabellen auf schmalen Bildschirmen: jede Zeile wird zur Karte.
   Sechs Spalten sind auf einem Telefon entweder unlesbar gequetscht oder nur
   seitwaerts scrollend erreichbar — beim Scrollen verliert man die Zeile, in
   der man gerade war. Als gestapelte Karte bleibt alles an einem Stueck.

   Die Spaltenueberschrift wandert dabei vor den Wert: ohne sie staende dort
   „Aktiv", ohne zu sagen, was aktiv ist. Beschriftet wird nur, was ein
   data-label traegt — Auswahlkaestchen, Aktionsmenues und Leerzustaende
   stapeln sich schlicht.

   Ausnahme .table-plain: zweispaltige Bezeichnung/Wert-Tabellen (die
   Zeit-Auswertung) bleiben Tabellen. Sie passen auch auf ein Telefon, und
   gestapelt verloeren sie genau die Gegenueberstellung, die sie ausmacht. */

@media (max-width: 640px) {
  /* Der Kopf verschwindet fuer das Auge, bleibt aber fuer Screenreader
     stehen: die Zellen behalten so ihre Zuordnung. */
  .table:not(.table-plain) thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .table:not(.table-plain),
  .table:not(.table-plain) tbody,
  .table:not(.table-plain) tbody tr,
  .table:not(.table-plain) tbody td {
    display: block;
    width: 100%;
  }

  .table:not(.table-plain) tbody tr {
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--color-border);
  }

  .table:not(.table-plain) tbody tr:last-child {
    border-bottom: none;
  }

  /* !important, weil die Zellen ihre Ausrichtung teils als style-Attribut
     tragen (rechtsbuendige Aktionsspalte, nowrap bei Zeitstempeln). In der
     Kartendarstellung waere beides falsch, und ein Attribut sticht jede
     Regel ohne !important. */
  .table:not(.table-plain) tbody td {
    padding: var(--space-1) 0;
    border-bottom: none;
    text-align: left !important;
    white-space: normal !important;
  }

  .table:not(.table-plain) tbody td[data-label] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px var(--space-3);
  }

  .table:not(.table-plain) tbody td[data-label]::before {
    content: attr(data-label);
    flex: 0 0 38%;
    font-size: var(--text-xs);
    font-weight: var(--font-semibold);
    color: var(--color-text-tertiary);
  }

  /* Der Leerzustand steht in einer Zelle ueber alle Spalten — dort waere die
     Innenabstands-Wueste des Normalfalls zu viel. */
  .table:not(.table-plain) tbody td .empty-state {
    padding: var(--space-8) var(--space-2);
  }
}

/* ========== Ticket-Detailseite ========== */
/* Vollständig neu gesetzt nach TICKET-DETAIL-SPEC.md. Die früheren Regeln
   dieser Seite sind ersatzlos entfernt, nicht weitergepatcht — sie hatten sich
   über mehrere Durchgaenge selbst widersprochen.
   Farben und Schriftart kommen unveraendert aus tokens.css; alle Maße dieser
   Seite stehen hier als eigene Variablen und werden nur über diese benutzt. */

.ticket-page {
  /* Abstände */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 24px;
  --s-6: 32px;

  /* Schrift */
  --t-title: 20px;
  --t-body: 14px;
  --t-author: 13px;
  --t-meta: 12px;
  --lh-body: 1.55;

  /* Form. --control-height überschreibt hier bewusst den globalen Wert:
     Damit bekommt jeder Knopf, jedes Feld und jede Auswahl auf dieser Seite
     34px, ohne dass es an jeder Stelle einzeln steht. */
  --radius-control: 6px;
  --radius-card: 10px;
  --border: 1px solid var(--color-border);
  --control-height: 34px;
  --avatar-size: 28px;
  --icon-size: 28px;
  --accent-line: 2px;
  --motion: 120ms;

  /* Breiten, damit auch sie nicht als lose Zahl im Stylesheet stehen. */
  --page-max: 1240px;
  --side-width: 340px;
  --label-width: 92px;
  --reply-min: 72px;
  --reply-max: 220px;
  --w-minutes: 72px;
  --w-date: 130px;

  /* Ein 1380px breiter Kasten mit fünf kurzen Nachrichten kann nicht gefüllt
     aussehen. Begrenzt und zentriert liest sich der freie Platz als Seitenrand
     statt als Lücke. */
  max-width: var(--page-max);
  margin: 0 auto;
  padding: var(--s-5) var(--s-6) var(--s-6);
  font-size: var(--t-body);
  line-height: var(--lh-body);
}

/* ----- Bedienelemente: eine Höhe, ein Radius, eine Rahmenfarbe ----- */

.ticket-page .btn,
.ticket-page .input,
.ticket-page .select {
  height: var(--control-height);
  border-radius: var(--radius-control);
  font-size: var(--t-body);
}

.ticket-page .btn {
  /* Ohne das brachte der Knopf eine zweite, hellere Rahmenfarbe und einen
     Schatten mit. Auf dieser Seite gibt es genau eine Rahmenfarbe. */
  border: var(--border);
  box-shadow: none;
}

.ticket-page .btn-primary {
  border-color: transparent;
}

.ticket-page .badge {
  border-radius: var(--radius-control);
}

/* Zustaende — je genau eine Regel (Spec 8). */
.ticket-page .btn,
.ticket-page .input,
.ticket-page .select,
.ticket-page .tp-textarea,
.ticket-page .tp-tab,
.ticket-page .tp-ctab,
.ticket-page .tp-icon-btn,
.ticket-page .tp-file::file-selector-button {
  transition: background-color var(--motion), border-color var(--motion);
}

.ticket-page .btn:focus-visible,
.ticket-page .input:focus,
.ticket-page .input:focus-visible,
.ticket-page .select:focus,
.ticket-page .select:focus-visible,
.ticket-page .tp-textarea:focus,
.ticket-page .tp-textarea:focus-visible,
.ticket-page .tp-icon-btn:focus-visible,
.ticket-page .tp-tab:focus-visible,
.ticket-page .tp-ctab:focus-visible,
.ticket-page input:focus-visible + .tp-tab,
.ticket-page input:focus-visible + .tp-ctab {
  outline: var(--accent-line) solid var(--color-accent);
  outline-offset: var(--accent-line);
  /* Der globale Fokusring ist ein Schatten — hier ersetzt ihn der Umriss. */
  box-shadow: none;
}

/* ----- Wiederkehrende Textrollen ----- */

.tp-meta {
  font-size: var(--t-meta);
  font-weight: 400;
  color: var(--color-text-tertiary);
}

.tp-card-title {
  margin: 0 0 var(--s-4);
  font-size: var(--t-body);
  font-weight: 600;
  color: var(--color-text);
}

/* ----- 4. Kopfzeile ----- */

.tp-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-4);
  padding-bottom: var(--s-4);
  margin-bottom: var(--s-5);
  border-bottom: var(--border);
}

.tp-head-main {
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  min-width: 0;
}

.tp-number {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: var(--t-title);
  font-weight: 400;
  color: var(--color-text-tertiary);
}

.tp-title {
  margin: 0;
  font-size: var(--t-title);
  font-weight: 600;
  color: var(--color-text);
  /* Ein langer Betreff darf die Zeile nicht sprengen. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tp-customer {
  flex: 0 0 auto;
  font-size: var(--t-body);
  white-space: nowrap;
}

.tp-head-side {
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  flex: 0 0 auto;
}

/* ----- 3. Raster ----- */

.tp-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--side-width);
  gap: var(--s-5);
  align-items: start;
}

.tp-main {
  min-width: 0;
}

.tp-side {
  display: grid;
  gap: var(--s-4);
  min-width: 0;
}

/* Derselbe Haltepunkt wie beim Schalenlayout weiter unten: Einspaltig und
   „Fenster scrollt wieder" müssen zusammenfallen, sonst teilten sich zwei
   Rasterzeilen eine feste Höhe. */
@media (max-width: 899px) {
  .tp-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ----- 5. Verlaufseintrag ----- */
/* Kein Rahmen, kein Hintergrund, keine feste Höhe, kein eigener Scrollkasten:
   Die Seite scrollt normal, der Verlauf wächst mit seinem Inhalt. */

.entry {
  display: grid;
  grid-template-columns: var(--avatar-size) minmax(0, 1fr);
  gap: var(--s-3);
  padding: var(--s-3) 0;
  border-bottom: var(--border);
}

.entry:last-child {
  border-bottom: none;
}

.entry-avatar {
  display: grid;
  place-items: center;
  width: var(--avatar-size);
  height: var(--avatar-size);
  border-radius: 50%;
  background: var(--color-accent-soft);
  color: var(--color-accent-text);
  font-size: var(--t-meta);
  font-weight: 600;
  text-transform: uppercase;
}

.entry-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--s-2);
}

.entry-author {
  font-size: var(--t-author);
  font-weight: 600;
  color: var(--color-text);
}

.entry-text {
  margin: var(--s-1) 0 0;
  /* Nur der Textknoten wird begrenzt — nie die getönte Fläche darunter. */
  max-width: 72ch;
  font-size: var(--t-body);
  font-weight: 400;
  line-height: var(--lh-body);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Interne Notiz: der getönte Bereich ist exakt so breit wie der Eintrag und
   endet dort, wo auch die Trennlinie endet. Der negative Rand holt die
   Einrückung wieder herein, die Rahmen und Polsterung erzeugen — das ist der
   einzige negative Rand auf dieser Seite. */
.entry--internal {
  border-left: var(--accent-line) solid var(--color-warning);
  background: rgba(252, 185, 0, 0.05);
  padding-left: var(--s-3);
  margin-left: calc(var(--s-3) * -1 - var(--accent-line));
}

/* ----- 6. Antwortbereich ----- */

/* Steht im Schalenlayout (unten) von selbst unten, als letztes Flex-Element.
   Kein sticky, kein deckender Hintergrund, kein z-index — die brauchte es nur,
   solange das Fenster selbst scrollte. */
.tp-reply {
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: var(--border);
}

/* Etwas Luft unter dem letzten Beitrag. */
.tp-thread {
  padding-bottom: var(--s-2);
}

/* Die Reiter sind Radioknöpfe mit Beschriftung: So schaltet die Auswahl auch
   ohne JavaScript um und wird ganz normal mit abgeschickt. */
.tp-seg {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.tp-tabs {
  display: flex;
  gap: var(--s-2);
  margin-bottom: var(--s-3);
}

.tp-tab {
  padding: var(--s-1) var(--s-3);
  border: none;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--color-text-tertiary);
  font-size: var(--t-body);
  cursor: pointer;
}

.tp-tab:hover {
  background: var(--color-hover);
}

.tp-seg[value="0"]:checked ~ .tp-tabs .tp-tab-public,
.tp-seg[value="1"]:checked ~ .tp-tabs .tp-tab-internal {
  background: var(--color-surface-raised);
  color: var(--color-text);
}

.tp-textarea {
  display: block;
  width: 100%;
  min-height: var(--reply-min);
  max-height: var(--reply-max);
  padding: var(--s-3);
  border: var(--border);
  border-radius: var(--radius-control);
  background: var(--color-surface);
  color: var(--color-text);
  font-family: inherit;
  font-size: var(--t-body);
  line-height: var(--lh-body);
  resize: none;
}

.tp-textarea::placeholder {
  color: var(--color-text-tertiary);
}

.tp-reply-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  margin-top: var(--s-2);
}

/* Der Hinweis wechselt mit dem Reiter — ohne Skript. */
.tp-hint-internal {
  display: none;
}

.tp-seg[value="1"]:checked ~ .tp-reply-foot .tp-hint-public {
  display: none;
}

.tp-seg[value="1"]:checked ~ .tp-reply-foot .tp-hint-internal {
  display: inline;
}

/* ----- 7. Rechte Spalte ----- */

.tp-card {
  padding: var(--s-4);
  border: var(--border);
  border-radius: var(--radius-card);
}

.tp-props {
  display: grid;
  grid-template-columns: var(--label-width) minmax(0, 1fr);
  row-gap: var(--s-3);
  column-gap: var(--s-3);
  align-items: center;
}

.tp-props .select,
.tp-props .input {
  width: 100%;
}

/* Feld und Haken in festen Spuren: Der Haken erscheint und verschwindet,
   ohne dass das Feld dabei seine Breite ändert. */
.tp-field {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--s-3);
  column-gap: var(--s-2);
  align-items: center;
}

.tp-mark {
  font-size: var(--t-meta);
  color: var(--color-success-text);
  text-align: center;
}

.tp-props .tp-note {
  grid-column: 1 / -1;
}

.tp-prop-value {
  min-width: 0;
  font-size: var(--t-body);
  overflow-wrap: anywhere;
}

.tp-save {
  width: 100%;
  margin-top: var(--s-4);
}

.tp-note {
  margin: var(--s-3) 0 0;
  font-size: var(--t-meta);
  line-height: var(--lh-body);
  color: var(--color-text-tertiary);
}

/* Reiterzeile der zweiten Karte */
.tp-ctabs {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-bottom: var(--s-4);
  border-bottom: var(--border);
}

.tp-ctab {
  padding: 0 0 var(--s-3);
  border: none;
  border-bottom: var(--accent-line) solid transparent;
  background: transparent;
  color: var(--color-text-tertiary);
  font-size: var(--t-body);
  cursor: pointer;
}

.tp-ctab:hover {
  color: var(--color-text);
}

.tp-ctabs-side {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin-left: auto;
  padding-bottom: var(--s-3);
}

.tp-icon-btn {
  display: grid;
  place-items: center;
  width: var(--icon-size);
  height: var(--icon-size);
  padding: 0;
  border: var(--border);
  border-radius: var(--radius-control);
  background: var(--color-surface-raised);
  color: var(--color-text);
  cursor: pointer;
}

.tp-icon-btn:hover {
  background: var(--color-hover);
}

.tp-panel {
  display: none;
}

/* ----- Listen in den Reitern ----- */

.tp-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-2) 0;
  border-bottom: var(--border);
}

.tp-row:last-child {
  border-bottom: none;
}

.tp-row-main {
  min-width: 0;
}

.tp-row-title {
  display: block;
  font-size: var(--t-body);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tp-empty {
  padding: var(--s-3) 0;
  font-size: var(--t-meta);
  color: var(--color-text-tertiary);
}

/* Das native Dateifeld bringt einen Knopf mit, der zu nichts hier passt.
   ::file-selector-button formt ihn um — der Dateiname bleibt als Meta-Text
   daneben stehen, ohne dass ein Skript ihn nachtragen müsste. */
.tp-file {
  width: 100%;
  font-size: var(--t-meta);
  color: var(--color-text-tertiary);
}

.tp-file::file-selector-button {
  height: var(--control-height);
  margin-right: var(--s-2);
  padding: 0 var(--s-3);
  border: var(--border);
  border-radius: var(--radius-control);
  background: var(--color-surface-raised);
  color: var(--color-text);
  font-family: inherit;
  font-size: var(--t-body);
  cursor: pointer;
}

.tp-file::file-selector-button:hover {
  background: var(--color-hover);
}

.tp-check {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-3);
  font-size: var(--t-meta);
  color: var(--color-text-secondary);
}

.tp-full {
  width: 100%;
  margin-top: var(--s-3);
}

/* Zeit nachtragen: eine Zeile. */
.tp-timeadd {
  display: flex;
  gap: var(--s-2);
  margin-top: var(--s-3);
}

.tp-timeadd .tp-minutes {
  width: var(--w-minutes);
}

.tp-timeadd .tp-date {
  width: var(--w-date);
}

.tp-timeadd .tp-notefield {
  flex: 1;
  min-width: 0;
}

.tp-event {
  padding: var(--s-2) 0;
  border-bottom: var(--border);
}

.tp-event:last-child {
  border-bottom: none;
}

/* ----- Reiter schalten ----- */

.tp-radio {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.tp-radio[value="files"]:checked ~ .tp-ctabs .tp-ctab-files,
.tp-radio[value="time"]:checked ~ .tp-ctabs .tp-ctab-time,
.tp-radio[value="activity"]:checked ~ .tp-ctabs .tp-ctab-activity {
  color: var(--color-text);
  border-bottom-color: var(--color-accent);
}

.tp-radio[value="files"]:checked ~ .tp-panel-files,
.tp-radio[value="time"]:checked ~ .tp-panel-time,
.tp-radio[value="activity"]:checked ~ .tp-panel-activity {
  display: block;
}


/* ----- Schalenlayout ab 900px ----- */
/* Hier wird Punkt 1 der Spec bewusst aufgehoben: Diese eine Seite bekommt eine
   feste Höhe und einen eigenen Scrollkasten. Der Grund ist derselbe, aus dem
   die Spec sie verboten hat — Ruhe im Bild: Bei fünfzig Nachrichten soll sich
   nur der Verlauf bewegen, während Kopfzeile, Antwortfeld und Eckdaten stehen
   bleiben. Das Fenster selbst bekommt gar keine Scrollleiste mehr.

   Angehängt wird das über `:has(.ticket-page)` statt über eine Klasse am
   <body>: So bleibt das gemeinsame Layout unangetastet. Kennt ein Browser
   `:has()` nicht, greift schlicht nichts davon und die Seite scrollt wie
   bisher — kein Schaden, nur kein Gewinn.

   `min-height: 0` steht in jedem Glied der Kette. Ohne das nimmt ein
   Flex-Element mindestens die Höhe seines Inhalts ein, die Begrenzung wird
   stillschweigend ignoriert und die Seite scrollt doch wieder. */

@media (min-width: 900px) {
  html:has(.ticket-page),
  body:has(.ticket-page) {
    height: 100%;
    overflow: hidden;
  }

  .app-shell:has(.ticket-page) {
    height: 100%;
    min-height: 0;
  }

  .app-main:has(.ticket-page) {
    height: 100dvh;
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
  }

  /* Die obere Leiste bleibt eine feste Zeile (flex-shrink: 0 steht dort
     bereits), der Rest bekommt den Platz. */
  .app-content:has(.ticket-page) {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
  }

  .ticket-page {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
  }

  .tp-grid {
    flex: 1 1 auto;
    min-height: 0;
    /* Beide Spalten sollen die volle Höhe bekommen — start hielte sie kurz. */
    align-items: stretch;
  }

  .tp-head {
    flex-shrink: 0;
  }

  .tp-main {
    display: flex;
    flex-direction: column;
    min-height: 0;
  }

  /* Der einzige Kasten, der sich bewegt. `scrollbar-gutter` hält den Platz
     der Leiste frei, damit das Layout beim ersten Überlaufen nicht springt. */
  .tp-thread {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding-right: var(--s-3);
    scrollbar-gutter: stable;
  }

  .tp-reply {
    flex-shrink: 0;
  }

  /* Viele Aktivitätseinträge verlängern nicht mehr die Seite, sondern rollen
     in der Karte. */
  .tp-side {
    min-height: 0;
    overflow-y: auto;
  }
}

/* ========== Benachrichtigungen ========== */
/* „Benutzer angelegt" stand bisher als Balken oben im Inhalt: Er schob die
   Seite nach unten, blieb liegen, bis man weiterklickte, und im Dialog war er
   die einzige Rückmeldung. Jetzt meldet sich das Ergebnis kurz oben rechts und
   geht von allein wieder.

   Ohne JavaScript bleibt der Balken, wo er war — der Server liefert ihn
   unverändert aus, erst assets/js/ui.js hebt ihn heraus. */

.toast-stack {
  position: fixed;
  top: var(--space-4);
  right: var(--space-4);
  z-index: var(--z-toast);
  display: grid;
  gap: var(--space-2);
  width: min(380px, calc(100vw - 2 * var(--space-4)));
  /* Der Stapel selbst fängt keine Klicks ab, die Meldungen darin schon. */
  pointer-events: none;
}

.toast {
  position: relative;
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-lg);
  background: var(--color-surface-raised);
  color: var(--color-text);
  box-shadow: var(--shadow-overlay);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  overflow: hidden;
  animation: toast-in var(--transition) both;
}

.toast.is-leaving {
  animation: toast-out var(--transition-fast) both;
}

@keyframes toast-in {
  from { opacity: 0; transform: translateX(16px) scale(0.98); }
  to { opacity: 1; transform: none; }
}

@keyframes toast-out {
  from { opacity: 1; }
  to { opacity: 0; transform: translateX(16px); }
}

.toast-mark {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  margin-top: 1px;
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: var(--font-bold);
}

.toast.is-success .toast-mark {
  background: var(--color-success-soft);
  color: var(--color-success-text);
}

.toast.is-danger .toast-mark {
  background: var(--color-danger-soft);
  color: var(--color-danger-text);
}

.toast.is-info .toast-mark {
  background: var(--color-accent-soft);
  color: var(--color-accent-text);
}

.toast-text {
  min-width: 0;
  overflow-wrap: anywhere;
}

.toast-close {
  flex: 0 0 auto;
  margin: -2px -4px 0 auto;
  padding: 2px 4px;
  border: 0;
  border-radius: var(--radius-xs);
  background: none;
  color: var(--color-text-tertiary);
  font-size: var(--text-xs);
  line-height: 1;
  cursor: pointer;
}

.toast-close:hover {
  background: var(--color-hover);
  color: var(--color-text);
}

/* Der Balken am unteren Rand zeigt die verbleibende Zeit — sonst wirkt das
   Verschwinden willkürlich. Die Dauer setzt das Skript. */
.toast-life {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: 100%;
  background: var(--color-border-strong);
  transform-origin: left center;
  animation: toast-life linear both;
}

@keyframes toast-life {
  from { transform: scaleX(1); }
  to { transform: scaleX(0); }
}

/* Wer mit der Maus draufbleibt, will lesen. */
.toast:hover .toast-life,
.toast:focus-within .toast-life {
  animation-play-state: paused;
}

@media (max-width: 640px) {
  .toast-stack {
    top: var(--space-3);
    right: var(--space-3);
    left: var(--space-3);
    width: auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  .toast,
  .toast.is-leaving {
    animation: none;
  }

  .toast-life {
    display: none;
  }
}

/* ----- Rückfrage vor einer folgenreichen Aktion ----- */
/* Statt des grauen Browserkastens: derselbe Dialog wie überall. */

.dialog-confirm {
  width: min(420px, 92vw);
}

.dialog-message {
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--color-text-secondary);
}

.dialog-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  flex: 0 0 auto;
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-muted);
}

/* ========== Dialog ========== */
/* Formulare und Verwaltungsseiten oeffnen sich ueber der Seite, statt sie zu
   verlassen. Der Inhalt ist dieselbe Seite wie ohne JavaScript — sie kommt nur
   als Fragment (siehe layouts/app und assets/js/dialog.js).

   Natives <dialog>: bringt Fokusfalle, Esc und Hintergrund-Abdunklung selbst
   mit. Alles davon nachzubauen waere Arbeit an einer Stelle, an der der Browser
   es besser kann. */

.dialog {
  /* Mitte des Bildschirms, nicht Ecke: Das Browser-Stylesheet setzt für einen
     modalen Dialog zwar selbst inset und margin, aber unterschiedlich je nach
     Browser. Hier steht es ausgeschrieben, damit es überall gleich sitzt. */
  position: fixed;
  inset: 0;
  margin: auto;
  width: min(560px, 92vw);
  max-height: 88vh;
  padding: 0;
  /* Kopfzeile steht, nur der Inhalt scrollt. */
  flex-direction: column;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: var(--shadow-overlay);
  overflow: hidden;
}

/* Verwaltungsseiten bringen ganze Tabellen mit und brauchen mehr Platz. */
.dialog.is-wide {
  width: min(1000px, 94vw);
}

/* Geschlossen bleibt display:none aus dem Browser-Stylesheet — deshalb erst
   im offenen Zustand auf flex umstellen. */
.dialog[open] {
  display: flex;
}

.dialog::backdrop {
  background: rgba(0, 0, 0, 0.55);
}

.dialog-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-border);
}

.dialog-title {
  font-size: var(--text-md);
  font-weight: var(--font-semibold);
  line-height: var(--leading-tight);
}

.dialog-description {
  margin-top: 2px;
  font-size: var(--text-sm);
  color: var(--color-text-secondary);
}

/* Die Aktionsknöpfe des Seitenkopfs, vom Skript hier hereingehoben. */
.dialog-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  flex-shrink: 0;
  margin-left: auto;
}

.dialog-body {
  flex: 1 1 auto;
  min-height: 0;
  padding: var(--space-5);
  overflow-y: auto;
}

/* Im Dialog steht der Titel schon in der Kopfzeile, und „Zurueck"-Knoepfe
   fuehren aus einem Dialog heraus ins Leere — beides raeumt das Skript ab.
   Die Regel hier faengt den Moment davor ab, damit nichts aufblitzt. */
.dialog-body .page-header {
  display: none;
}

/* Karten im Dialog haben schon den Rahmen des Dialogs um sich. */
.dialog-body > .card,
.dialog-body > * > .card {
  max-width: none !important;
}

.dialog-loading {
  display: grid;
  place-items: center;
  padding: var(--space-12);
}

/* ========== Alert ========== */

.alert {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  background: var(--color-surface-muted);
  color: var(--color-text);
}

.alert-title {
  font-weight: var(--font-semibold);
  margin-bottom: var(--space-1);
}

.alert-success { background: var(--color-success-soft); border-color: var(--color-success); }
.alert-warning { background: var(--color-warning-soft); border-color: var(--color-warning); }
.alert-danger { background: var(--color-danger-soft); border-color: var(--color-danger); }

/* ========== Empty State ========== */

.empty-state {
  display: grid;
  justify-items: center;
  gap: var(--space-2);
  padding: var(--space-12) var(--space-6);
  text-align: center;
}

.empty-state-title {
  font-size: var(--text-md);
  font-weight: var(--font-semibold);
}

.empty-state-description {
  font-size: var(--text-sm);
  color: var(--color-text-secondary);
  max-width: 360px;
}

.empty-state .btn {
  margin-top: var(--space-2);
}

/* ========== Kleinteile ========== */

.kbd {
  display: inline-block;
  padding: 0 var(--space-1);
  min-width: 18px;
  border: 1px solid var(--color-border-strong);
  border-bottom-width: 2px;
  border-radius: var(--radius-xs);
  background: var(--color-surface-raised);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-align: center;
  color: var(--color-text-secondary);
}

.divider {
  height: 1px;
  background: var(--color-border);
  border: none;
}

.spinner {
  width: 16px;
  height: 16px;
  border: 2px solid var(--color-border-strong);
  border-top-color: var(--color-accent);
  border-radius: var(--radius-full);
  animation: spinner-rotate 0.7s linear infinite;
}

@keyframes spinner-rotate {
  to { transform: rotate(360deg); }
}

/* ========== Einmal-Code-Eingabe ========== */
/* Kaestchen fuer Zwei-Faktor-Codes. Die Kaestchen selbst legt erst das Skript
   an — ohne JavaScript bleibt das normale Textfeld sichtbar und nutzbar. */

.code-input {
  display: grid;
  gap: var(--space-3);
}

/* Sobald die Kaestchen stehen, verschwindet das Originalfeld — es bleibt aber
   im Formular und traegt weiterhin den Wert. Im Handbetrieb (Wiederherstellungs-
   code) ist es wieder das sichtbare Feld, dann verschwinden die Kaestchen. */
.code-input.is-enhanced:not(.is-manual) .code-input-real {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  border: 0;
  opacity: 0;
  pointer-events: none;
}

.code-input.is-manual .code-segments {
  display: none;
}

.code-segments {
  display: flex;
  gap: var(--space-2);
  justify-content: center;
}

.code-segment {
  width: 100%;
  max-width: 54px;
  height: 60px;
  padding: 0;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--text-2xl);
  font-weight: var(--font-medium);
  color: var(--color-text);
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  transition:
    border-color var(--transition-fast),
    background var(--transition-fast),
    transform var(--transition-fast);
}

.code-segment:focus {
  outline: none;
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px var(--color-accent-soft);
}

.code-segment.is-filled {
  border-color: var(--color-border-strong);
  background: var(--color-surface);
}

/* Kurzer Impuls, wenn eine Ziffer landet. */
.code-segment.is-filled {
  animation: code-pop 160ms ease-out;
}

@keyframes code-pop {
  0% { transform: scale(1); }
  45% { transform: scale(1.06); }
  100% { transform: scale(1); }
}

/* Code vollstaendig: alle Kaestchen leuchten kurz nacheinander auf, dann wird
   abgeschickt. Die Verzoegerung je Kaestchen ergibt die Welle. */
.code-input.is-complete .code-segment {
  border-color: var(--color-accent);
  animation: code-confirm 340ms ease-out both;
}

.code-input.is-complete .code-segment:nth-child(1) { animation-delay: 0ms; }
.code-input.is-complete .code-segment:nth-child(2) { animation-delay: 25ms; }
.code-input.is-complete .code-segment:nth-child(3) { animation-delay: 50ms; }
.code-input.is-complete .code-segment:nth-child(4) { animation-delay: 75ms; }
.code-input.is-complete .code-segment:nth-child(5) { animation-delay: 100ms; }
.code-input.is-complete .code-segment:nth-child(6) { animation-delay: 125ms; }

@keyframes code-confirm {
  0% { transform: translateY(0); box-shadow: 0 0 0 0 var(--color-accent-soft); }
  40% { transform: translateY(-4px); box-shadow: 0 0 0 4px var(--color-accent-soft); }
  100% { transform: translateY(0); box-shadow: 0 0 0 0 transparent; }
}

/* Fehlversuch: einmal kurz wackeln. */
.code-input.is-error .code-segments {
  animation: code-shake 400ms ease-in-out;
}

.code-input.is-error .code-segment {
  border-color: var(--color-danger);
}

@keyframes code-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-6px); }
  40% { transform: translateX(5px); }
  60% { transform: translateX(-3px); }
  80% { transform: translateX(2px); }
}

.code-input-toggle {
  justify-self: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-text-secondary);
  font-size: var(--text-sm);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.code-input-toggle:hover {
  color: var(--color-text);
}

@media (max-width: 400px) {
  .code-segment {
    max-width: 46px;
    height: 52px;
    font-size: var(--text-xl);
  }
}

/* Wer Bewegung reduziert haben moechte, bekommt die Zustaende ohne Animation. */
@media (prefers-reduced-motion: reduce) {
  .code-segment,
  .code-input.is-complete .code-segment,
  .code-input.is-error .code-segments {
    animation: none;
    transition: none;
  }
}

/* Schild-Symbol ueber der Zwei-Faktor-Abfrage. */
.code-shield {
  width: 48px;
  height: 48px;
  margin: 0 auto var(--space-4);
  display: grid;
  place-items: center;
  border-radius: var(--radius-full);
  background: var(--color-accent-soft);
  color: var(--color-accent-text);
}

.code-shield svg {
  width: 24px;
  height: 24px;
}
