/******************* COLOR DEFINITIONS *******************/

:root {
--s-color-strong: #000;
--s-color-light: #888;
--s-color-chart-bg: #eee;
--s-color-tooltip: #626976;
--s-color-waiting: #F22738;
--s-color-editing: #ea992d;
--s-color-customer: #bec0c5;
--s-color-done: #1FA641;
}

[data-bs-theme="dark"] {
	--s-color-strong: #fff;
	--s-color-light: #aaa;
	/* the empty part of the progress rings: as subtle on the dark cards as #eee is on white */
	--s-color-chart-bg: #374151;
	/* Tabler's dark secondary resolves to gray-400 (#9ca3af) and .text-muted to a
	   near-white 75% — both too bright for muted text. Dim them app-wide to a muted grey
	   (covers .text-secondary via var + rgb, .text-muted via -color). Not darker than
	   this: longer muted text such as item descriptions must stay readable on the dark
	   cards (about 5.5:1). */
	--tblr-secondary: #9aa1ac;
	--tblr-secondary-rgb: 154, 161, 172;
	--tblr-secondary-color: rgb(154, 161, 172);
	/* this Tabler version colours .text-muted from --tblr-muted (gray-500 in dark mode),
	   so without this line the muted text stays even darker than the value above */
	--tblr-muted: #9aa1ac;
}

/* Links always use the primary colour. Tabler's anchor rule reads
   --tblr-link-color-rgb, which matches the primary in light mode but is lightened
   in dark mode (106,169,227) and then drifts away from it. Pin it to the primary
   in both themes; this file loads after tabler.min.css, so it wins. */
:root,
[data-bs-theme="dark"] {
	--tblr-link-color-rgb: var(--tblr-primary-rgb);
}

/******************* COLOR CHANGES *******************/

.s-link {
  color: var(--s-color-strong);
}

.s-link:hover, .s-link:focus {
  color: var(--s-color-strong);
}

.s-text-light {
  --tblr-text-opacity: 1;
  color: var(--s-color-light);
}

/* Billed effort rows: grey out the data cells. Icons/buttons keep their own
   colour (text-green / btn-*). Specificity must beat Bootstrap's table cell
   colour rule `.table > :not(caption) > * > *`. */
.table tbody tr.s-billed td {
  color: var(--s-color-light);
}

/* Row-limited table: clamp to data-max-rows body rows and reveal the rest via a
   toggle button below (not a scrollbar, so it's obvious more rows exist).
   initRowLimitedTables() measures the exact pixel height (per row, so wrapped rows
   still yield exactly N) and wires the button. Without JS the full table shows.
   Reusable: .table-responsive.s-clamp-rows[data-max-rows] + a .s-clamp-toggle-wrap
   with a .s-clamp-toggle button right after it. */
.s-clamp-rows.is-clamped {
  overflow: hidden;
}
.s-clamp-toggle-wrap .s-clamp-toggle {
  text-decoration: none;
}

/* Square corners for every modal across the whole app (no rounded corners). */
.modal-content,
.modal-content .modal-status,
.modal-content .modal-header,
.modal-content .modal-footer {
  border-radius: 0;
}

/* GRUNDSATZ: Modals müssen sich in JEDEM Theme klar vom Hintergrund abheben.
   Im Dark-Mode ist Tablers Modal-Fläche fast so dunkel wie die (geblurrte) Seite
   und der Standard-Rand kaum sichtbar — deshalb hier ein deutlich sichtbarer Rand,
   ein kräftigerer Schatten und ein dunklerer Backdrop. Gilt app-weit. */
[data-bs-theme="dark"] .modal-content {
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: 0 1.5rem 3rem rgba(0, 0, 0, 0.65);
}
[data-bs-theme="dark"] .modal-backdrop.show {
  opacity: 0.6;
}

/* Summary table (e.g. open efforts in a modal): the data part (header + rows)
   gets a full border grid, while the total row (tfoot) floats below without any
   borders. Group double-borders are removed. Specificity beats Bootstrap's
   `.table > :not(caption) > * > *` and `.table > :not(:first-child)` rules. */
.s-summary-table {
  border-collapse: collapse;
}
.s-summary-table > * > tr > * {
  vertical-align: top;
}
.s-summary-table > :not(:first-child) {
  border-top-width: 0;
}
.s-summary-table > thead > tr > *,
.s-summary-table > tbody > tr > * {
  border: 1px solid var(--tblr-border-color);
}
.s-summary-table > tfoot > tr > * {
  border-width: 0;
}

/* Der Hinweis in der Kopfzeile stand per position:absolute in der Mitte und wusste damit
   nichts von den Schaltflächen daneben — bei vielen Aktionen lagen beide übereinander. Als
   normales Flex-Element wird er von der Kopfzeile mit eingeplant; er darf dafür schrumpfen
   und seinen Text kürzen, bevor irgendetwas überlappt. */
/* Nicht schrumpfen: ein auf das Warnzeichen zusammengedrueckter Hinweis ohne Betrag sagt
   nichts mehr. */
.s-efforts-hint {
  flex-shrink: 0;
}

/* Split-Editoren (Angebot, Projektplan, Brief) haben ihre Werkzeuge in der Kopfzeile, wo
   jeder Pixel zaehlt: der Nutzerblock rechts wird dort auf das Bild reduziert. Wer eingeloggt
   ist, sagt das Bild, und das Menue darunter nennt den Namen weiterhin. */
.s-split-editor .s-usermenu-details {
  display: none !important;
}

/* Bierdeckel-Knopf: Rundung wie die Phasen-Pille daneben (999px), damit beide als dieselbe
   Sorte Element lesen — aussen die Enden der Gruppe, innen das Summen-Badge. In einer btn-group
   setzt Bootstrap die Radien an den Kindern, deshalb erstes und letztes Kind einzeln; die
   Gruppe rendert je nach Rolle und Phase auch mal mit nur einem Kind. */
.s-efforts-hint > :first-child {
  border-top-left-radius: 999px;
  border-bottom-left-radius: 999px;
  padding-left: 0.6rem;
}
.s-efforts-hint > :last-child {
  border-top-right-radius: 999px;
  border-bottom-right-radius: 999px;
  padding-right: 0.6rem;
}

/* Die Summe darin erbt vom btn-group-sm nur rund 10px und ist damit kaum lesbar. Etwas
   groesser, dafuer knapper gepolstert, damit der Knopf nicht waechst. */
.s-efforts-hint .badge {
  font-size: 0.8rem;
  padding: 0.15rem 0.45rem;
  border-radius: 999px;
}

/* Kopfzeile des Angebotseditors. Die rechte Gruppe (Phasen-Pille, Symbole) darf immer in sich
   umbrechen, statt aus ihrem Bereich zu laufen und sich mit dem Rest zu ueberlagern. */
@media (min-width: 768px) {
  .s-offer-header > .navbar-nav {
    min-width: 0;
    flex-wrap: wrap;
    justify-content: flex-end;
  }
}

/* Nicht zentrierter Zustand: die Werkzeugleiste darf den freien Platz nicht aufsaugen, sonst
   schiebt sie den Bierdeckel-Knopf an den rechten Rand und es klafft eine Luecke dazwischen.
   Ohne flex-grow endet sie an ihrem Inhalt, der Knopf schliesst direkt an, und die Kopf-Symbole
   wandern wie gewohnt nach rechts. */
/* Beschriftungen in der Werkzeugleiste erst, wenn wirklich Platz ist: unter xl zeigen Zurueck,
   Speichern & Co. nur ihr Symbol (Tooltip nennt die Aktion) und belegen auch nur dessen Breite.
   Damit bleibt die Kopfzeile bis weit herunter eine Zeile — Ziel war, moeglichst alles in einer
   Zeile zu halten. */
@media (max-width: 1199.98px) {
  .s-offer-header .navbar-collapse > div > a.btn,
  .s-offer-header .dropdown > .btn {
    padding-left: 0.5rem;
    padding-right: 0.5rem;
  }
  .s-offer-header .navbar-collapse [data-footer-tab] .btn > span {
    display: none;
  }
}

/* Auf schmalen Schirmen bleiben die Tab-Aktionen als Symbol-Schaltflaechen stehen — nur ihre
   Beschriftung entfaellt, damit die Kopfzeile eine Zeile bleibt. Was als Symbol nicht
   selbsterklaerend ist (Layout), steckt im Aktionen-Menue und wird hier ausgeblendet.
   Bewusst hier und nicht per d-md-*-Klasse: das Tab-Skript schaltet an denselben Elementen
   d-none, und d-md-flex wuerde es aushebeln. */
/* Unter md stapelt Bootstrap die Kopfzeile. Dort alles von links aufreihen: mit
   space-between und rechts ausgerichteter Symbolreihe staffeln sich die Schaltflaechen quer
   ueber mehrere Zeilen, was zufaellig aussieht. */
@media (max-width: 767.98px) {
  /* .navbar > … mitschreiben: Bootstrap setzt space-between mit derselben Spezifitaet, eine
     einzelne Klasse verliert dagegen. */
  .navbar > .s-offer-header {
    justify-content: flex-start;
  }
  .s-offer-header > .navbar-nav {
    flex-wrap: wrap;
    justify-content: flex-start;
  }
  /* Alles in eine Zeile: Bootstrap legt den Collapse-Bereich unter md auf volle Breite, wodurch
     der Zurueck-Pfeil eine eigene Zeile bekam. Er darf hier so breit sein wie sein Inhalt und
     steht als erstes — die Reihenfolge im Quelltext ist eine andere. */
  .s-offer-header > .navbar-collapse {
    flex-basis: auto;
    width: auto;
    order: -1;
  }
}

@media (min-width: 768px) {
  .s-offer-header:not(.s-header-centred) > .navbar-collapse {
    flex-grow: 0;
  }
  /* space-between (Bootstrap-Vorgabe) reisst die beiden Elemente einer Zeile auseinander — der
     Knopf landete dadurch am rechten Rand. Von links aufreihen, und die Symbolreihe per
     auto-Rand rechts halten, damit sie dort bleibt, ob in derselben Zeile oder umgebrochen. */
  .navbar > .s-offer-header:not(.s-header-centred) {
    justify-content: flex-start;
  }
  .s-offer-header:not(.s-header-centred) > .navbar-nav {
    margin-left: auto;
  }
}

/* Der Bierdeckel-Knopf steht mittig — aber nur, solange die drei Bereiche der Kopfzeile
   tatsaechlich in eine Zeile passen. Ob sie passen, entscheidet kein Schwellenwert, sondern
   eine Messung: welche Schaltflaechen in der Leiste stehen, haengt von Tab, Rolle und Phase ab,
   und der aktive Tab wechselt zur Laufzeit — jede feste Breite waere irgendwann falsch. Das
   Skript in offers/edit.html setzt dafuer .s-header-centred.

   "1fr auto 1fr" setzt die Mitte dann auf die tatsaechliche Mitte, unabhaengig davon, wie breit
   die Seiten gerade sind. Frueher stand der Knopf per position:absolute mittig und war fuer das
   Layout unsichtbar — genau daher die Ueberlappungen. */
@media (min-width: 768px) {
  .navbar > .s-offer-header.s-header-centred {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    flex-wrap: nowrap;
  }
  /* grid-area statt nur der Spalte: im Quelltext stehen sie in der Reihenfolge Mitte, rechts,
     links — ohne Zeilenangabe schiebt die automatische Platzierung die Leiste in Zeile 2. */
  .s-header-centred > .navbar-collapse {
    grid-area: 1 / 1;
    min-width: 0;
  }
  .s-header-centred > .s-efforts-hint {
    grid-area: 1 / 2;
  }
  .s-header-centred > .navbar-nav {
    grid-area: 1 / 3;
    justify-self: end;
  }
}
/* Der unausgefuellte Teil der Status-Ringe (Projektlisten, Projektseite,
   Fortschritts-Donuts). Ohne diese Regel zeichnet der Ring gar nichts und der
   Kreis wirkt, als fehle ein Stueck. Farbe aus der Theme-Variablen, damit er im
   Dunkelmodus nicht verschwindet. */
.svg-donut-ring {
	stroke: var(--s-color-chart-bg);
}

.s-help{
	display: none;
}

.progress-wrapper-file-upload {
    width:100%;
}
.progress-wrapper-file-upload .progress {
    background-color: var(--s-color-done);
    width:0%;
    padding:5px 0px 5px 0px;
}

.s-badge-size-l {
	font-size: 0.9rem;
}

/******************* MARGINS *******************/

.s-margin-up-6 {
	margin-top: -6px !important;
}

.s-margin-up-5 {
	margin-top: -5px !important;
}

.s-margin-up-4 {
	margin-top: -4px !important;
}

.s-margin-up-3 {
	margin-top: -3px !important;
}

.s-margin-up-2 {
	margin-top: -2px !important;
}

.s-margin-up-1 {
	margin-top: -1px !important;
}

/******************* ICON SIZES *******************/

.s-icon-size-xxl {
	font-size: 2rem;
}

.s-icon-size-xl {
	font-size: 1.8rem;
}

.s-icon-size-l {
	font-size: 1.6rem;
}

.s-icon-size-m {
	font-size: 1.3rem;
}

.s-icon-size-s {
	font-size: 1.0rem;
}

/* Icon column on a file card: icon tile on top, edit/delete buttons in a
   row underneath. The buttons fade in when the card is hovered. */
.s-file-card-icon-wrap {
	flex-shrink: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	width: 3.5rem;
}

/* Big file-type icon used in the project-files card. Sits in a tinted
   square tile so the file format reads at a glance. */
.s-file-card-icon {
	width: 3.5rem;
	height: 3.5rem;
	border-radius: 0.5rem;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-size: 2.25rem;
	line-height: 1;
	background-color: rgba(32, 107, 196, 0.10); /* primary @ 10% */
	color: #206bc4;                              /* tabler primary */
}

/* Edit/Delete buttons sit at the bottom-right of the file card. Hidden
   by default; fade in when the card is hovered. On touch / no-hover
   devices they stay permanently visible so the actions remain reachable. */
.s-file-card-actions {
	display: flex;
	justify-content: flex-end;
	gap: 0.15rem;
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.15s ease-in-out;
}
@media (hover: hover) {
	.s-file-card:hover .s-file-card-actions,
	.s-file-card-actions:focus-within {
		opacity: 1;
		pointer-events: auto;
	}
}
@media (hover: none) {
	.s-file-card-actions {
		opacity: 1;
		pointer-events: auto;
	}
}

/* Rendered Markdown unterhalb der Metadaten auf einer Datei-/Notiz-Card.
   Dezenter Hintergrund hebt den Inhalt vom Card-Body ab, aber ohne Rahmen
   links. Wichtig: min-width:0 + overflow-hidden auf der Box, damit lange
   Code-Fences die Card nicht sprengen. */
.s-file-card-md {
	background-color: rgba(0, 0, 0, 0.025);
	border-radius: 0.25rem;
	padding: 0.75rem 1rem;
	font-size: 0.875rem;
	min-width: 0;
	max-width: 100%;
	overflow: hidden;
}
.s-file-card-md > :last-child {
	margin-bottom: 0;
}
.s-file-card-md p {
	margin-bottom: 0.5rem;
}
/* Code-Fences und Inline-Code im rendered Markdown:
   1) Layout-Schutz: <pre> bekommt min-width:0 + max-width:100% + overflow-x:auto,
      damit lange Code-Zeilen einen eigenen Scrollbar bekommen statt die Card
      auseinanderzudrücken (default white-space:pre erzeugt sonst min-width:max-content).
   2) Lesbarkeit: heller Hintergrund + dunkler Text — Tabler setzt per Default
      `color: var(--tblr-light)`, was auf hellem Hintergrund unsichtbar wäre.
      Wir überschreiben mit !important, weil Tabler eine spätere Regel hat. */
.s-file-card-md,
.markdown-body {
	min-width: 0;
}
.s-file-card-md pre,
.markdown-body pre {
	max-width: 100%;
	overflow-x: auto;
	min-width: 0;
	background-color: #1a1d24 !important;
	color: #e6e7ea !important;
	padding: 0.5rem 0.75rem;
	border-radius: 0.25rem;
	margin: 0.25rem 0;
}
.s-file-card-md pre code,
.markdown-body pre code {
	background-color: transparent !important;
	color: inherit !important;
	border: 0;
	padding: 0;
	white-space: pre;
	word-break: normal;
	overflow-wrap: normal;
}
.s-file-card-md code,
.markdown-body code {
	background-color: #eef0f4;
	color: #b14157;
	border: 1px solid rgba(0, 0, 0, 0.06);
	padding: 1px 5px;
	border-radius: 3px;
	font-size: 0.9em;
	word-break: break-word;
	overflow-wrap: anywhere;
}
/* Darkmode: Inline-Code etwas gedimmter, damit der helle Block auf
   dunklem Surface nicht unangenehm hervorsticht. */
[data-bs-theme="dark"] .s-file-card-md code,
[data-bs-theme="dark"] .markdown-body code {
	background-color: rgba(255, 255, 255, 0.08);
	color: #f08b9b;
	border-color: rgba(255, 255, 255, 0.10);
}

/* Diff-Block (Versionen-Vergleich für Notizen + YAML): muss in beiden
   Color-Schemes lesbar bleiben. Anstatt eines hartcodierten bg-light
   nutzen wir die Tabler-Surface-Variable, die im Darkmode automatisch
   dunkler wird, mit dem entsprechenden Body-Color. */
.s-diff-pre {
	background-color: var(--tblr-bg-surface-secondary);
	color: var(--tblr-body-color);
	padding: 0.75rem 1rem;
	white-space: pre-wrap;
	margin: 0;
	border-radius: 0.25rem;
}
/* Blockquotes: linker Strich in Tabler-Primary, Text dezent gedimmt. */
.s-file-card-md blockquote,
.markdown-body blockquote {
	border-left: 3px solid var(--tblr-primary, #206bc4);
	background-color: transparent;
	padding: 0.25rem 0.75rem;
	margin: 0.5rem 0;
	color: var(--tblr-secondary, #4b5565);
}
.s-file-card-md blockquote > :last-child,
.markdown-body blockquote > :last-child {
	margin-bottom: 0;
}

/* Statuswechsel-Nachricht (Angebots-Timeline + Listen-Popover): optisch wie
   ein Markdown-Blockquote — linker Strich in Tabler-Primary, transparenter
   Hintergrund, dezent gedimmter Text. Whitespace bleibt erhalten. */
.status-message-quote {
	border-left: 3px solid var(--tblr-primary, #206bc4);
	background-color: rgba(0, 0, 0, 0.05);
	border-radius: 0 0.25rem 0.25rem 0;
	padding: 0.5rem 0.75rem;
	color: var(--tblr-secondary, #4b5565);
	white-space: pre-wrap;
}

/* Tabler's .card-sm shrinks font-size — undo that for our file cards so
   the metadata reads at default body size. */
.card-sm.s-file-card,
.card-sm.s-file-card .card-body {
	font-size: 1rem;
}

/* Dateien und Notizen in Angeboten/Projekten rahmen-/schattenlos darstellen:
   einfach eine horizontale Linie ZWISCHEN aufeinanderfolgenden Einträgen,
   nicht nach dem letzten. Inneres card-body verliert seine Padding (kommt
   sonst zusätzlich zur Padding der äußeren Wrapper-Card), damit die Einträge
   nicht doppelt eingerückt wirken. */
.s-file-card[id^="file-"],
.s-file-card[id^="note-"] {
	border: 0;
	box-shadow: none;
	background-color: transparent;
	border-radius: 0;
}
.s-file-card[id^="file-"] .card-body,
.s-file-card[id^="note-"] .card-body {
	padding: 0.5rem 0;
}
/* Linie OBERHALB jeder Card außer der ersten. Drei Selektoren decken die
   bekannten Wrappings ab:
   - Angebote (Files-Tab/Notes-Tab): Cards sind direkte Geschwister.
   - Projekte (Files-Card): jede Card sitzt in einem eigenen .col-12.
   Zusätzlich mehr Padding-Top im card-body der nachfolgenden Karten, damit
   der Inhalt deutlich von der Trennlinie abgesetzt ist. */
.s-file-card[id^="file-"] + .s-file-card[id^="file-"],
.s-file-card[id^="note-"] + .s-file-card[id^="note-"],
.col-12 + .col-12 > .s-file-card[id^="file-"] {
	border-top: 1px solid var(--tblr-border-color, rgba(0, 0, 0, 0.1));
}
.s-file-card[id^="file-"] + .s-file-card[id^="file-"] .card-body,
.s-file-card[id^="note-"] + .s-file-card[id^="note-"] .card-body,
.col-12 + .col-12 > .s-file-card[id^="file-"] .card-body {
	padding-top: 1rem;
}

/* Layout-Guard: Datei-/Notiz-Karte muss ihre Spaltenbreite respektieren.
   Ohne diesen Block schiebt ein <pre>-Code-Fence im Markdown (min-content)
   die ganze Card seitlich aus dem Grid. min-width:0 erlaubt Schrumpfen
   im Flex/Grid, overflow:hidden klippt verbleibendes Out-of-Bounds-Material
   (das innere <pre> hat seinen eigenen Scrollbar). */
.s-file-card {
	min-width: 0;
	max-width: 100%;
	overflow: hidden;
}
.s-file-card .card-body,
.s-file-card .card-body > .d-flex,
.s-file-card .card-body > .d-flex > .flex-fill {
	min-width: 0;
}

/* Archived file cards: dimmed background, faded foreground so they read
   as "still here for reference, but no longer active". */
.s-file-card.s-file-card-archived {
	opacity: 0.85;
}
.s-file-card.s-file-card-archived .s-file-card-icon {
	background-color: rgba(0, 0, 0, 0.08);
	color: #6c757d; /* tabler text-secondary */
}
.s-file-card.s-file-card-archived a {
	text-decoration: line-through;
}

/* Tag autocomplete: a dropdown anchored under a comma-separated input.
   Drives off a <datalist> on the same page; matches against the token
   after the last comma so users can keep typing more tags. */
.s-tags-autocomplete {
	position: relative;
}
.s-tags-autocomplete-list {
	position: absolute;
	top: 100%;
	left: 0;
	right: 0;
	z-index: 1090;                  /* above bootstrap modal-body */
	/* Theme surface, not a hard-coded #fff: otherwise the light-on-dark body text
	   is unreadable on a white box in dark mode. */
	background: var(--tblr-bg-surface, #fff);
	color: var(--tblr-body-color, inherit);
	border: 1px solid var(--tblr-border-color, #dee2e6);
	border-radius: 0.25rem;
	max-height: 240px;
	overflow-y: auto;
	box-shadow: 0 4px 12px rgba(0, 0, 0, 0.10);
	display: none;
	margin-top: 0.15rem;
}
.s-tags-autocomplete-list.show {
	display: block;
}
.s-tags-autocomplete-item {
	padding: 0.4rem 0.75rem;
	cursor: pointer;
}
.s-tags-autocomplete-item:hover,
.s-tags-autocomplete-item.active {
	background-color: rgba(32, 107, 196, 0.10);
}

/******************* COLORS *******************/

.s-color-waiting {
	color: var(--s-color-waiting);
}
.s-color-editing {
	color: var(--s-color-editing);
}
.s-color-customer {
	color: var(--s-color-customer);
}
.s-color-done {
	color: var(--s-color-done);
}

.s-bgcolor-waiting {
	background: var(--s-color-waiting);
}
.s-bgcolor-editing {
	background: var(--s-color-editing);
}
.s-bgcolor-customer {
	background: var(--s-color-customer);
}
.s-bgcolor-done {
	background: var(--s-color-done);
}

/******************* MIN WIDTHS *******************/

.s-min-width-50{
	min-width: 50px;
}
.s-min-width-60{
	min-width: 60px;
}
.s-min-width-70{
	min-width: 70px;
}
.s-min-width-80{
	min-width: 80px;
}
.s-min-width-90{
	min-width: 90px;
}
.s-min-width-100{
	min-width: 100px;
}
.s-min-width-110{
	min-width: 110px;
}
.s-min-width-120{
	min-width: 120px;
}
.s-min-width-130{
	min-width: 130px;
}
.s-min-width-140{
	min-width: 140px;
}
.s-min-width-150{
	min-width: 150px;
}
.s-min-width-160{
	min-width: 160px;
}
.s-min-width-170{
	min-width: 170px;
}
.s-min-width-180{
	min-width: 180px;
}
.s-min-width-190{
	min-width: 190px;
}
.s-min-width-200{
	min-width: 200px;
}

.s-minimum-width{
	width:1%;
}

/******************* CODE MIRROR *******************/

.CodeMirror{
	border: 1px solid #d9dbde
}

/******************* NO IDEA *******************/

@media (min-width: 768px) {
	.s-formrow {
	    --tblr-gutter-x: 1rem;
	    --tblr-gutter-y: 0;
	    display: flex;
	    flex-wrap: wrap;
	    margin-top: calc(-1 * var(--tblr-gutter-y));
	    margin-right: calc(-.5 * var(--tblr-gutter-x));
	    margin-left: calc(-.5 * var(--tblr-gutter-x));
	}
}

/******************* TOOLTIP *******************/

.tooltip.show {
  opacity: 1;
}
.tooltip-inner {
    background-color: var(--s-color-tooltip);
    box-shadow: 0px 0px 2px black;
}
/* Bootstrap 5 (Tabler) uses .bs-tooltip-end/-start (not BS4's -right/-left) and the
   Popper auto variant, so the arrow colour has to target those to match .tooltip-inner. */
.tooltip.bs-tooltip-end .tooltip-arrow::before,
.tooltip.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before {
    border-right-color: var(--s-color-tooltip) !important;
}
.tooltip.bs-tooltip-start .tooltip-arrow::before,
.tooltip.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before {
    border-left-color: var(--s-color-tooltip) !important;
}
.tooltip.bs-tooltip-bottom .tooltip-arrow::before {
    border-bottom-color: var(--s-color-tooltip) !important;
}
.tooltip.bs-tooltip-top .tooltip-arrow::before {
    border-top-color: var(--s-color-tooltip) !important;
}
.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before, .bs-tooltip-top .tooltip-arrow::before {
    border-top-color: var(--s-color-tooltip);
}

.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before, .bs-tooltip-bottom .tooltip-arrow::before {
    border-bottom-color: var(--s-color-tooltip);
}

/******************* AJAX *******************/

.htmx-indicator{
    display:none;
}
.htmx-request .htmx-indicator{
    display:inline;
}
.htmx-request.htmx-indicator{
    display:inline;
}

/******************* AJAX LOADER *******************/

.lds-ring,
.lds-ring div {
  margin-top:8px;
  box-sizing: border-box;
}
.lds-ring {
  display: inline-block;
  position: relative;
  width: 30px;
  height: 30px;
}
.lds-ring div {
  box-sizing: border-box;
  display: block;
  position: absolute;
  width: 24px;
  height: 24px;
  margin: 3px;
  border: 3px solid currentColor;
  border-radius: 50%;
  animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
  border-color: currentColor transparent transparent transparent;
}
.lds-ring div:nth-child(1) {
  animation-delay: -0.45s;
}
.lds-ring div:nth-child(2) {
  animation-delay: -0.3s;
}
.lds-ring div:nth-child(3) {
  animation-delay: -0.15s;
}
@keyframes lds-ring {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

/******************* CONTROLLING *******************/

.s-controlling{
	display: none;
}

.controlling-action-column{
	padding-top: 0.25rem !important; 
	padding-right: 0.25rem !important; 
	padding-left:0rem !important; 
	width:30px !important;
}

.controlling-action-placeholder{
	padding-right: 0.75rem;
}

/* No divider line below the last row in a card-table */
.card-table > tbody > tr:last-child > td {
	border-bottom: 0;
}

/* Project timeline: cap at ~6 entries with scrollbar. */
.timeline-scroll {
	max-height: 40em;
	overflow-y: auto;
	scrollbar-gutter: stable;
	padding-right: 0.5rem;
}

/* Profile avatar: large circular image with hover-overlay action icons */
.profile-avatar-wrap {
	position: relative;
	width: 320px;
	height: 320px;
	max-width: 100%;
	aspect-ratio: 1 / 1;
	border-radius: 50%;
	overflow: hidden;
	margin: 0 auto;
}
.profile-avatar {
	display: block;
	width: 100%;
	height: 100%;
	background-size: cover;
	background-position: center;
	background-repeat: no-repeat;
}
.profile-avatar-actions {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: flex-end;
	justify-content: center;
	gap: 0.5rem;
	padding-bottom: 1.1rem;
	background: linear-gradient(to top, rgba(0,0,0,0.55) 0%, rgba(0,0,0,0.35) 45%, rgba(0,0,0,0) 75%);
	opacity: 0;
	transition: opacity 0.2s ease;
	pointer-events: none;
}
.profile-avatar-wrap:hover .profile-avatar-actions,
.profile-avatar-wrap:focus-within .profile-avatar-actions {
	opacity: 1;
	pointer-events: auto;
}
.profile-avatar-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	border-radius: 50%;
	background: rgba(255,255,255,0.85);
	color: #333;
	border: 0;
	padding: 0;
	font-size: 1.1rem;
	transition: background-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
	cursor: pointer;
}
.profile-avatar-btn:hover,
.profile-avatar-btn:focus {
	background: #fff;
	color: #000;
	transform: scale(1.1);
}
.profile-avatar-btn.profile-avatar-btn-delete {
	color: #b02a37;
}
.profile-avatar-btn.profile-avatar-btn-delete:hover,
.profile-avatar-btn.profile-avatar-btn-delete:focus {
	background: #b02a37;
	color: #fff;
}

/* CodeMirror Darkmode: das Default-Theme ist hart auf weiß codiert.
   Wir überschreiben die wichtigsten Slots (Background, Text, Cursor,
   Selection, Gutter, Aktive-Zeile, YAML-Mode-Tokens), sobald Tabler
   in den Darkmode wechselt. */
[data-bs-theme="dark"] .CodeMirror {
	background: #1a1d24 !important;
	color: #e6e7ea !important;
}
[data-bs-theme="dark"] .CodeMirror-gutters {
	background: #181a20 !important;
	border-right: 1px solid #2a2d36 !important;
}
[data-bs-theme="dark"] .CodeMirror-linenumber {
	color: #6c757d !important;
}
[data-bs-theme="dark"] .CodeMirror-cursor {
	border-left-color: #e6e7ea !important;
}
[data-bs-theme="dark"] .CodeMirror-selected {
	background: rgba(32, 107, 196, 0.30) !important;
}
[data-bs-theme="dark"] .CodeMirror-focused .CodeMirror-selected {
	background: rgba(32, 107, 196, 0.45) !important;
}
[data-bs-theme="dark"] .CodeMirror-activeline-background {
	background: rgba(255, 255, 255, 0.03) !important;
}
[data-bs-theme="dark"] .CodeMirror-matchingbracket {
	color: #ffd166 !important;
	background: rgba(255, 209, 102, 0.10);
}
/* YAML/Markdown Token-Farben für Darkmode. */
[data-bs-theme="dark"] .CodeMirror .cm-keyword     { color: #c792ea; }
[data-bs-theme="dark"] .CodeMirror .cm-atom        { color: #f78c6c; }
[data-bs-theme="dark"] .CodeMirror .cm-number      { color: #f78c6c; }
[data-bs-theme="dark"] .CodeMirror .cm-def         { color: #82aaff; }
[data-bs-theme="dark"] .CodeMirror .cm-variable    { color: #e6e7ea; }
[data-bs-theme="dark"] .CodeMirror .cm-property    { color: #82aaff; }
[data-bs-theme="dark"] .CodeMirror .cm-operator    { color: #89ddff; }
[data-bs-theme="dark"] .CodeMirror .cm-string      { color: #c3e88d; }
[data-bs-theme="dark"] .CodeMirror .cm-string-2    { color: #c3e88d; }
[data-bs-theme="dark"] .CodeMirror .cm-comment     { color: #6c7a89; font-style: italic; }
[data-bs-theme="dark"] .CodeMirror .cm-meta        { color: #ffcb6b; }
[data-bs-theme="dark"] .CodeMirror .cm-tag         { color: #f07178; }
[data-bs-theme="dark"] .CodeMirror .cm-attribute   { color: #ffcb6b; }
[data-bs-theme="dark"] .CodeMirror .cm-header      { color: #82aaff; font-weight: bold; }
[data-bs-theme="dark"] .CodeMirror .cm-quote       { color: #c3e88d; font-style: italic; }
[data-bs-theme="dark"] .CodeMirror .cm-hr          { color: #6c7a89; }
[data-bs-theme="dark"] .CodeMirror .cm-link        { color: #82aaff; text-decoration: underline; }

/* TOAST UI Editor: tighter spacing on toolbar and content area */
.toastui-editor-defaultUI-toolbar {
	padding: 0 !important;
}
.toastui-editor-defaultUI .ProseMirror {
	padding: 15px 15px !important;
}

/* TOAST UI WYSIWYG: Code-Blöcke und Inline-Code lesbar machen.
   Der Editor rendert Code-Fences als <pre> mit hellem Hintergrund, setzt
   den Textinhalt aber auf eine fast unsichtbare Hellgrau-Farbe. Wir
   erzwingen schwarzen Text + dezenten Hintergrund, sowohl für Inline-
   Code (`code`), Fence-Blöcke (`pre code`) als auch für das vom Editor
   eigens gewrappte WYSIWYG-Code-Block-Element. */
.toastui-editor-contents pre,
.toastui-editor-contents pre code,
.toastui-editor-ww-container .ProseMirror pre,
.toastui-editor-ww-container .ProseMirror pre code,
.toastui-editor-ww-code-block,
.toastui-editor-ww-code-block-language {
	color: #1f2937 !important;
	background-color: #f4f5f7 !important;
}
.toastui-editor-contents code,
.toastui-editor-ww-container .ProseMirror code {
	color: #1f2937 !important;
	background-color: #f4f5f7 !important;
	padding: 1px 4px;
	border-radius: 3px;
}
.toastui-editor-contents pre code,
.toastui-editor-ww-container .ProseMirror pre code {
	padding: 0;
	background-color: transparent !important;
}

/* Markdown task lists (GFM): hide the list bullet on items that carry a
   checkbox, and align the checkbox where the bullet would normally sit. */
.markdown-body ul {
	padding-left: 1.5em;
}
.markdown-body li.task-list-item {
	list-style: none;
	margin-left: -1.25em;
}
/* Disabled checkboxes in rendered Markdown are greyed out by every browser
   regardless of `accent-color`. Bypass with a custom-drawn checkbox so the
   checked state shows up in the project's primary color. */
.markdown-body input[type="checkbox"] {
	-webkit-appearance: none;
	appearance: none;
	width: 1em;
	height: 1em;
	margin: 0 0.4em 0 0;
	padding: 0;
	border: 1px solid var(--tblr-border-color, #ced4da);
	border-radius: 3px;
	background-color: #fff;
	vertical-align: middle;
	position: relative;
	cursor: default;
	opacity: 1;
}
.markdown-body input[type="checkbox"]:checked {
	background-color: var(--tblr-primary, #066fd1);
	border-color: var(--tblr-primary, #066fd1);
}
.markdown-body input[type="checkbox"]:checked::after {
	content: "";
	position: absolute;
	left: 0.28em;
	top: 0.05em;
	width: 0.30em;
	height: 0.60em;
	border: solid #fff;
	border-width: 0 0.13em 0.13em 0;
	transform: rotate(45deg);
}

/* Markdown tables: give plain flexmark output Tabler-like borders + header */
.markdown-body table {
	width: auto;
	border-collapse: collapse;
	margin-bottom: 1rem;
}
.markdown-body table th,
.markdown-body table td {
	border: 1px solid var(--tblr-border-color, #dee2e6);
	padding: 0.5rem 0.75rem;
	vertical-align: top;
}
.markdown-body table thead th {
	background-color: #e9edf3;
	border-bottom: 2px solid var(--tblr-border-color, #adb5bd);
	font-weight: 600;
	text-align: left;
}
.markdown-body table tbody tr:nth-of-type(even) {
	background-color: rgba(0, 0, 0, 0.025);
}

/* ============================ NAVBAR JOB CHIPS ============================
   Compact pill: icon + numbers. On hover/focus-within the title slides in
   from max-width 0. Numbers use tabular-nums to keep the chip stable when
   counters go 9 -> 10 -> 100. */
.job-chip {
	display: inline-flex;
	align-items: center;
	border: 1px solid var(--tblr-border-color, #dee2e6);
	border-radius: 9999px;
	padding: 0.15rem 0.5rem;
	margin-right: 0.5rem;
	line-height: 1;
	white-space: nowrap;
}
.job-chip .job-chip-icon {
	font-size: 1.25rem;
	line-height: 1;
	margin-right: 0.25rem;
}
.job-chip .job-chip-numbers {
	font-variant-numeric: tabular-nums;
	font-feature-settings: "tnum";
	display: inline-block;
	min-width: 2.5ch;
	text-align: right;
	font-size: 0.875rem;
}
.job-chip .job-chip-title {
	display: inline-block;
	max-width: 0;
	opacity: 0;
	overflow: hidden;
	white-space: nowrap;
	transition: max-width 0.25s ease, opacity 0.2s ease, margin-left 0.25s ease;
	margin-left: 0;
	font-weight: 500;
	font-size: 0.875rem;
}
.job-chip:hover .job-chip-title,
.job-chip:focus-within .job-chip-title {
	max-width: 16rem;
	opacity: 1;
	margin-left: 0.5rem;
}
.job-chip.job-chip-snap .job-chip-title {
	transition: none;
}
.job-chip .job-chip-cancel {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	background: transparent;
	border: 0;
	padding: 0;
	margin-left: 0.35rem;
	color: var(--tblr-secondary, #6c757d);
	opacity: 0.65;
	transition: opacity 0.15s ease, color 0.15s ease;
	cursor: pointer;
	line-height: 1;
}
.job-chip .job-chip-cancel:hover,
.job-chip .job-chip-cancel:focus {
	opacity: 1;
	color: var(--tblr-red, #d6336c);
}
.job-chip .job-chip-cancel .ti {
	font-size: 1rem;
	line-height: 1;
}

.breadcrumb {
	margin-bottom: .5rem !important;
	margin-top: -.5rem;
}

/* Empty-State Icon-Kreis (z.B. Offers-Liste, leerer Tab). Dezenter,
   runder Hintergrund mit komfortablem Abstand zur Headline darunter.
   Display:block + reset der line-height auf Container-Ebene, damit die
   tatsächliche Kreis-Höhe als Layout-Höhe verwendet wird und nicht in
   die nachfolgende Headline ragt. */
.s-empty-icon-circle {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 7rem;
	height: 7rem;
	border-radius: 0.75rem;
	background-color: rgba(0, 0, 0, 0.04);
	margin: 0 auto 2rem auto;
	line-height: 1;
}
.s-empty-icon-circle i {
	font-size: 3.25rem;
	line-height: 1;
}
[data-bs-theme="dark"] .s-empty-icon-circle {
	background-color: rgba(255, 255, 255, 0.05);
}

/* Side-by-Side-Diff braucht deutlich mehr Platz als modal-xl (~1140px).
   95vw nutzt fast den ganzen Viewport, laesst aber etwas Rand. */
.s-modal-wide {
	max-width: 95vw;
}

/* Zweispaltiges Label/Value-Grid in der Angebots-Vorschau. Die erste
   Spalte ist so breit wie der laengste Label-Text — damit starten alle
   Werte rechts daneben in einer einheitlichen Spalte. */
.s-meta-grid {
	display: grid;
	grid-template-columns: auto 1fr;
	column-gap: 1.5rem;
	row-gap: 0.25rem;
	align-items: baseline;
}

/* Dezente Status-Pill: nur der Statuswert, Rahmen in gray-400. */
.s-status-pill {
	display: inline-flex;
	align-items: center;
	padding: 0.35rem 0.9rem;
	border: 1px solid var(--tblr-gray-400, #c1c8d1);
	border-radius: 999px;
	background-color: var(--tblr-bg-surface, #ffffff);
	font-size: 0.875rem;
	line-height: 1.2;
}
[data-bs-theme="dark"] .s-status-pill {
	background-color: var(--tblr-bg-surface, #1e1f25);
}

/* Tighter overlap for stacked editor avatars in offers list. Tabler default
   leaves a wide gap; we want them clearly stacked. */
.avatar-list-stacked .avatar {
	margin-right: calc(-.2 * var(--tblr-avatar-size)) !important;
}


/* Status-Popover (auf den Listen /projects, /problems, /pools).
   Default-max-width von Bootstrap-Popovers (~276px) ist knapp; wir geben
   etwas Luft, damit die längsten Flag-Labels nicht umbrechen. Anwendung
   erfolgt über die customClass-Option in installStatusPopovers(). Plus
   ein deutlicherer Schatten + leicht dunklere Border, damit der Popover
   sich auf weißem Card-Hintergrund klar abhebt. */
.popover.status-popover {
    max-width: 280px;
    border: 1px solid rgba(0, 0, 0, 0.12);
    box-shadow:
        0 1rem 2.5rem rgba(0, 0, 0, 0.18),
        0 0.25rem 0.5rem rgba(0, 0, 0, 0.08);
}
.popover.status-popover .popover-body {
    padding: 0.75rem;
}
/* Dark mode: the black border + dark shadow above are invisible on a dark
   surface, so the popover blurs into the background. Drive the Bootstrap popover
   variables (body + arrow) to a lighter, elevated surface with a visible border. */
[data-bs-theme="dark"] .popover.status-popover {
    --bs-popover-bg: var(--tblr-bg-surface-secondary);
    --bs-popover-border-color: rgba(255, 255, 255, 0.18);
    border-color: rgba(255, 255, 255, 0.18);
    box-shadow:
        0 1rem 2.5rem rgba(0, 0, 0, 0.6),
        0 0.25rem 0.5rem rgba(0, 0, 0, 0.4);
}
/* Erledigte Status-Flags greifen die Farbe des Donut-Rings auf — die
   CSS-Variable --status-color wird im Fragment je nach Fortschritt (0–12)
   gesetzt. Fallback auf Tabler-Primary für andere Verwendungen. */
.popover.status-popover .ti-square-check-filled {
    color: var(--status-color, var(--tblr-primary));
}
/* Nicht erledigte Flags deutlich blasser, damit die erledigten visuell
   führen. */
.popover.status-popover .ti-square {
    opacity: 0.35;
}
/* Status-Icons etwas größer als der Default 1em — erhöht die Lesbarkeit
   der Check-/Empty-Indikatoren ohne Layout-Sprung. */
.popover.status-popover li .ti {
    font-size: 1.15rem;
}

/******************* TOM SELECT (Auswahlfeld) *******************/

/* Das Vendor-CSS (tom-select.bootstrap5.min.css) wird NACH schaltzentrale.css
   geladen und laesst .ts-dropdown ohne eigenen Hintergrund und mit niedrigem
   z-index. Das aufgeklappte Dropdown liegt dadurch UNTER den folgenden
   Labels/Feldern, die durchscheinen. Mit erhöhter Spezifität überschreiben wir
   das ladereihenfolgen-unabhängig und erzwingen einen opaken Hintergrund.
   z-index 2000 liegt klar über dem Modal-Inhalt (Modal selbst: 1055).

   Gilt überall und nicht nur im Modal: die Auswahlfelder standen anfangs nur
   dort, aber durchscheinende Vorschläge sind auf einer normalen Seite genauso
   unbrauchbar. */
.ts-wrapper .ts-dropdown,
.modal .ts-dropdown {
    z-index: 2000;
    background-color: var(--tblr-bg-surface, #fff);
}
[data-bs-theme="dark"] .ts-wrapper .ts-dropdown,
[data-bs-theme="dark"] .modal .ts-dropdown {
    background-color: var(--tblr-bg-surface, #1e1f25);
}

/* Ein leeres Auswahlfeld fällt sonst auf die Höhe seiner leeren Eingabezeile
   zusammen und steht als dünner Strich zwischen normal hohen Feldern. */
.ts-wrapper.form-select .ts-control {
    min-height: calc(1.4285714286em + 0.5625rem + 2px);
}

/* GRUNDSATZ: Auto-Suggest-Text muss in JEDEM Theme lesbar sein. Das Vendor-CSS
   (tom-select.bootstrap5) lässt die Optionen/Eingabe im Dark-Mode dunkel — hier
   app-weit auf die Theme-Textfarbe zwingen, aktive/gehoverte Option auf Primary. */
[data-bs-theme="dark"] .ts-control,
[data-bs-theme="dark"] .ts-control input,
[data-bs-theme="dark"] .ts-dropdown,
[data-bs-theme="dark"] .ts-dropdown .option,
[data-bs-theme="dark"] .ts-dropdown .optgroup-header,
[data-bs-theme="dark"] .ts-dropdown .no-results {
    color: var(--tblr-body-color);
}
[data-bs-theme="dark"] .ts-dropdown .option.active,
[data-bs-theme="dark"] .ts-dropdown .active {
    background-color: var(--tblr-primary);
    color: #fff;
}
/* GRUNDSATZ: aufgeklappte Dropdowns müssen sich im Dark-Mode vom Hintergrund abheben
   (wie Modals) — sichtbarer Rand + Schatten. Gilt für TomSelect und die eigene
   Tag-Autocomplete. */
[data-bs-theme="dark"] .ts-dropdown,
[data-bs-theme="dark"] .s-tags-autocomplete-list {
    border: 1px solid rgba(255, 255, 255, 0.22);
    box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.6);
}

/* Same problem on the customer-assignment page (not a modal): the open bulk
   dropdown would sit behind the following table card. Page-scoped selector beats
   the later-loaded vendor ".ts-dropdown" rule via higher specificity. */
.s-assign-page .ts-dropdown {
    z-index: 1056;
    background-color: var(--tblr-bg-surface, #fff);
}
[data-bs-theme="dark"] .s-assign-page .ts-dropdown {
    background-color: var(--tblr-bg-surface, #1e1f25);
}

/* Falt-Markierung im YAML-Editor: Tabler-Chevron-Icons (als DOM-Elemente ueber
   indicatorOpen/indicatorFolded gesetzt). Die Vendor-foldgutter.css bleibt
   unveraendert; ihre Standard-Pfeil-:after-Inhalte greifen hier nicht, weil die
   Marker eigene <i class="ti ...">-Elemente sind. */
.CodeMirror .CodeMirror-foldgutter {
    width: 20px;
    text-align: center;
}
.cm-fold-icon {
    color: #495057;
    font-size: 13px;
    line-height: 1;
    cursor: pointer;
    vertical-align: middle;
}
[data-bs-theme="dark"] .cm-fold-icon {
    color: #adb5bd;
}

/* Snippet-Kontextmenue im Editor: kraeftiger Schatten + Rand, damit es sich
   klar vom YAML-Hintergrund abhebt. */
#snippetContextMenu {
    box-shadow: 0 .75rem 2rem rgba(0, 0, 0, .35) !important;
    border: 1px solid var(--tblr-border-color, rgba(0, 0, 0, .15));
}
[data-bs-theme="dark"] #snippetContextMenu {
    box-shadow: 0 .75rem 2rem rgba(0, 0, 0, .6) !important;
    border-color: rgba(255, 255, 255, .12);
}

/* Beim Ziehen einer Tabellenzeile (SortableJS) den (weissen) Hintergrund
   behalten und voll deckend lassen, statt durchscheinend. */
tr.sortable-chosen,
tr.sortable-drag {
    background-color: #fff !important;
    opacity: 1 !important;
}
tr.sortable-chosen td,
tr.sortable-drag td {
    background-color: #fff !important;
}
[data-bs-theme="dark"] tr.sortable-chosen,
[data-bs-theme="dark"] tr.sortable-drag,
[data-bs-theme="dark"] tr.sortable-chosen td,
[data-bs-theme="dark"] tr.sortable-drag td {
    background-color: var(--tblr-bg-surface, #1e1f25) !important;
}

/* Sortierbare Spaltenkoepfe in rechtsbuendigen Spalten ebenfalls rechtsbuendig.
   Tabler rendert .table-sort als width:100%-Block mit negativen Seiten-Margins
   (margin:-.5rem -.75rem) und Innenabstand – fuer linksbuendige Spalten gedacht.
   In text-end-Spalten endet der Header-Text dadurch deutlich links vom Wert.
   Hier die horizontalen Abstaende neutralisieren und Label + Sortierpfeil per
   Flexbox an den rechten Spaltenrand schieben, sodass die Kopfzeile der
   Ausrichtung der Datenzellen folgt. */
.table th.text-end .table-sort {
    display: flex;
    justify-content: flex-end;
    width: 100%;
    margin-left: 0;
    margin-right: 0;
    padding-left: 0;
    padding-right: 0;
}

/* Stummgeschaltete Support-Tickets abgedunkelt darstellen, OHNE das Aktions-
   Dropdown mitzudimmen. opacity auf dem ganzen <tr> wuerde den kompletten Subtree
   (inkl. des positionierten Dropdown-Menues) auf 50% setzen und laesst sich von
   Kindelementen nicht zuruecksetzen -> das geoeffnete Menue wird halbtransparent
   und ueberlagert die Nachbarzeilen. Daher nur die Datenzellen dimmen und die
   letzte Zelle (Aktionen/Dropdown) ausnehmen. */
.table-tbody tr.s-row-muted > td:not(:last-child) {
    opacity: .5;
}

/* ===== Drag & Drop Upload in der Projektliste ===== */
.drop-upload-zone {
    position: relative;
}

.drop-upload-overlay {
    position: absolute;
    inset: 0;
    z-index: 1020;
    display: none;
    align-items: center;
    justify-content: center;
    border: 2px dashed var(--tblr-primary, #066fd1);
    border-radius: var(--tblr-border-radius, 4px);
    background: rgba(255, 255, 255, 0.85);
    /* rein visuell: Drag-/Drop-Events sollen an die Karte gehen, nicht ans Overlay */
    pointer-events: none;
    text-align: center;
}

.drop-upload-zone.drop-upload-active .drop-upload-overlay {
    display: flex;
}

.drop-upload-overlay__label {
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--tblr-primary, #066fd1);
}

.drop-upload-hint {
    display: none;
}

.drop-upload-hint.is-visible {
    display: block;
}


/* Kurzes Hervorheben in der Angebots-Vorschau nach dem Speichern (siehe
   highlightChangedWords in offers/edit.html): hinzugefügte/geänderte Wörter
   werden (zusammenhängend) umschlossen, eine reine Löschung markiert die ganze
   Textzeile. Der Hintergrund blitzt amber auf und verblasst über 4s. */
/* Gemeinsame Signalfarbe für "hier hat sich gerade etwas geändert": Wort-Diff in der
   Angebotsvorschau und die Tagesmarkierung im Urlaubskalender teilen sie sich, damit
   dieselbe Bedeutung überall gleich aussieht. */
:root {
	--s-changed-rgb: 245, 191, 0;
}

@keyframes sWordChangedFlash {
	0%, 35% { background-color: rgba(var(--s-changed-rgb), 0.65); }
	100%    { background-color: transparent; }
}
.s-word-changed {
	/* Horizontales Padding wird über einen gleich großen negativen Margin
	   ausgeglichen, damit der Nachbartext nicht verrutscht; vertikales Padding
	   beeinflusst die Zeilenhöhe bei Inline-Elementen ohnehin nicht. */
	padding: 0.1em 0.25em;
	margin: 0 -0.25em;
	border-radius: 3px;
	animation: sWordChangedFlash 4s ease-out;
}

/* Globale Suche: Treffer als 2x2-Raster — links Typ/Nummer, rechts Kunde/Titel.
   Lange Titel brechen um (Bootstrap setzt .dropdown-item sonst auf nowrap). */
#globalSearchResults .dropdown-item {
	white-space: normal;
	word-break: break-word;
}
#globalSearchResults .s-search-item {
	display: grid;
	/* Spalte 1 fix (Typ/Nummer, über alle Treffer bündig), Spalte 2: Kunde/Titel,
	   Spalte 3: Status-Donut (rechts, über beide Zeilen). */
	grid-template-columns: 7.5rem 1fr auto;
	column-gap: 0.75rem;
	row-gap: 0.1rem;
	align-items: start;
}
#globalSearchResults .s-search-item > .badge {
	justify-self: start;
}
#globalSearchResults .s-search-donut {
	grid-column: 3;
	grid-row: 1 / span 2;
	align-self: center;
}
#globalSearchResults .s-search-donut svg {
	display: block;
	width: 2rem;
	height: 2rem;
}
/* Plan-Zeile: gehört zum Treffer darüber; erkennbar am „Plan"-Badge und dem
   Plan-Icon rechts. Spalten bleiben mit der Projektzeile bündig. */
/* Plan-Treffer: runder Chip in derselben 2rem-Größe wie die Fortschritts-Donuts,
   damit das Icon nicht lieblos zwischen den Kreisen sitzt; Farbe passend zum
   lila „Plan"-Badge. */
#globalSearchResults .s-search-plan-icon {
	width: 2rem;
	height: 2rem;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 1.1rem;
	color: var(--tblr-purple, #ae3ec9);
	background: var(--tblr-purple-lt, #f6e7fb);
}
/* Angebotseditor: Editor (links, CodeMirror) und Vorschau (rechts) unabhängig
   scrollbar — die Vorschau-Spalte bekommt eine eigene Höhe (per JS gesetzt) +
   Scroll, damit nicht die ganze Seite scrollt. Nur Desktop/breit (lg+). */
@media (min-width: 992px) {
	/* Die Auftragsbestaetigung tritt an dieselbe Stelle und bekommt deshalb
	   dieselbe Hoehe — sonst waechst ihre Karte mit dem Dokument, und weil die
	   Seite im Editor nicht scrollt, kaeme man an die unteren Seiten nicht heran. */
	#offerPreview,
	#confirmationPreview {
		height: var(--offer-pane-h, 75vh);
		overflow-y: auto;
	}
	/* Nicht die Spalte scrollt, sondern das Dokument darin: die Karte fuellt die
	   Hoehe, ihr Koerper gibt den Rest an den Bildbereich weiter. */
	#confirmationPreview {
		overflow-y: hidden;
	}
	/* Alle übrigen Reiter der linken Spalte — Übersicht, Notizen, Dateien,
	   Verlauf, Versionen, Stammdaten — scrollen ebenfalls intern. Die Seite
	   selbst scrollt im Editor nicht (overflow:hidden weiter unten), ohne
	   diese Regel bliebe daher alles unterhalb des Bildschirmrands
	   unerreichbar: die letzten Versionen, die Status-Haken der Stammdaten,
	   ältere Kommentare in der Übersicht.

	   Eigene Variable statt --offer-pane-h: die Reiter beginnen unterhalb der
	   Reiterleiste und damit tiefer als die Vorschau daneben. Mit deren Höhe
	   ragten sie genau um die Höhe der Leiste unter den Bildschirmrand — und
	   die letzten Zeilen blieben trotz Scroll abgeschnitten.

	   Der YAML-Reiter ist ausgenommen: CodeMirror bringt Höhe und Scroll mit. */
	body.s-split-editor #yamlForm > .card-body > .tab-content > .tab-pane:not(#tab-yaml) {
		max-height: var(--offer-tabpane-h, 70vh);
		overflow-y: auto;
	}
	/* Kopfleiste mit dem Aktionsmenü angepinnt lassen. */
	body.s-split-editor .navbar {
		position: sticky;
		top: 0;
		z-index: 1030;
	}

	/* Die Seite selbst scrollt nicht mehr — nur die beiden Bereiche scrollen
	   intern. So bleibt das Menü oben immer sichtbar. */
	body.s-split-editor {
		overflow: hidden;
	}

	/* Geringerer Abstand zwischen Menü und Editor: Tablers großzügiges
	   page-body-Padding oben verschenkt hier Platz. Weniger Abstand → der
	   Editor startet höher und wird höher (die Höhe wird aus der Oberkante
	   berechnet). */
	body.s-split-editor .page-body {
		margin-top: 0;
		padding-top: .5rem;
	}

	/* Footer aus dem Layout nehmen: fix am unteren Rand, standardmäßig
	   ausgeblendet, beim Hovern am unteren Rand (Hot-Zone) eingeblendet —
	   analog zur Präsentationsleiste im Plan-Editor. Damit muss das Layout
	   keine Rücksicht auf den Footer nehmen. */
	body.s-split-editor .footer {
		position: fixed;
		left: 0;
		right: 0;
		bottom: 0;
		z-index: 1025;
		background: var(--tblr-bg-surface, #fff);
		border-top: 1px solid var(--tblr-border-color, #e6e7e9);
		transform: translateY(100%);
		transition: transform .2s ease;
	}
	body.s-split-editor .s-footer-hotzone {
		position: fixed;
		left: 0;
		right: 0;
		bottom: 0;
		height: 12px;
		z-index: 1024;
	}
	body.s-split-editor .s-footer-hotzone:hover ~ .footer,
	body.s-split-editor .footer:hover {
		transform: translateY(0);
	}
}

/* Angebots-Vorschau auf schmalen Screens: Positionstabelle nicht zerquetschen,
   sondern im .table-responsive-Container horizontal scrollen lassen. */
@media (max-width: 991.98px) {
	#offerPreview .offer-items-table {
		min-width: 34rem;
	}
}

/* Angebots-/Presupuesto-Positionstabelle in der Vorschau: Linien und Abstände
   wie im erzeugten PDF (HelperYaml). Grau (150,150,150) für Kategorie-Überschrift
   und Zwischensumme, Luft über jeder Kategorie und vor den Gesamtsummen. Nur ab
   Tablet aufwärts — die Telefon-Karten-Darstellung (max-width:767) bleibt unberührt. */
@media (min-width: 768px) {
	/* Eine Linie unter jeder Position, wie im PDF: HelperYaml ruft nach jedem Posten
	   addLine(table). Sie fehlte hier, und die Vorschau sah damit anders aus als das
	   Dokument und als die Positionstabelle der Projektseite. */
	.offer-items-table > tbody > tr > td {
		border-top: 0;
		border-bottom: 1px solid var(--tblr-border-color, #e6e7e9);
	}
	/* nur die Kopfzeile trägt eine Trennlinie, wie im PDF */
	.offer-items-table > thead > tr > th {
		border-bottom: 1px solid var(--tblr-border-color, #e6e7e9);
	}
	/* Kategorie-Überschrift: grau, deutlich Luft darüber, wenig darunter */
	.offer-items-table > tbody > tr.s-cat-heading > td {
		color: #969696;
		font-weight: 600;
		padding-top: 1.75rem;
		padding-bottom: 0.1rem;
	}
	/* die erste Kategorie steht direkt unter der Kopfzeile — ohne den großen Vorabstand */
	.offer-items-table > tbody > tr.s-cat-heading:first-child > td {
		padding-top: 0.35rem;
	}
	/* Zwischensumme: grau und ohne Linie darunter — sie schliesst den Abschnitt
	   selbst ab, genau wie im PDF. */
	.offer-items-table > tbody > tr.s-cat-subtotal > td {
		color: #969696;
		padding-top: 0.2rem;
		padding-bottom: 0.1rem;
		border-bottom: 0;
	}
	/* Abstand vor den Gesamtsummen (netto/USt/brutto). !important, weil die Zelle
	   eine Bootstrap-Spacing-Utility (pt-2/pt-3) trägt, die selbst !important ist. */
	.offer-items-table > tbody > tr.s-total-lead > td {
		padding-top: 1.75rem !important;
	}
}

/* Projektdetails: links die Felder, rechts abgesetzt die Status-Haken.

   Bewusst über Container-Abfragen statt über das Bootstrap-Raster: dieselben
   Felder stehen einmal auf der vollen Seite (Neuanlage, Upload) und einmal im
   Reiter des Editors, der nur die halbe Fensterbreite hat. Bootstraps
   Haltepunkte messen das Fenster und würden im Reiter zweispaltig umbrechen,
   wo längst kein Platz mehr ist. Zwei ineinander liegende Container: der
   äußere entscheidet über die Statusspalte, der innere über die Feldpaare —
   der linke Bereich ist ja schmaler als das Ganze. */
.s-master-fields,
.s-master-fields__main {
	container-type: inline-size;
}
.s-master-fields__body {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 1rem;
}
.s-master-fields__status > .form-label {
	margin-bottom: 0;
}
/* Schmal: Status unterhalb der Felder, mit Linie darüber abgesetzt. Dieselbe
   Farbe und Staerke wie die waagerechte Trennlinie in den Feldern — beide
   gliedern, beide sollen gleich lesen. */
.s-master-fields__status {
	border-top: 3px solid var(--tblr-border-color, #e6e7e9);
	padding-top: 1rem;
}
@container (min-width: 34rem) {
	/* :has — bei einer Neuanlage gibt es noch keine Status-Haken. Ohne die
	   Bedingung bliebe die rechte Spalte reserviert und leer, und die Felder
	   drängten sich auf zwei Dritteln der Breite. */
	.s-master-fields__body:has(.s-master-fields__status) {
		grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
	}
	/* Breit: Statusspalte rechts, Linie links davon statt darüber. */
	.s-master-fields__status {
		border-top: 0;
		border-left: 3px solid var(--tblr-border-color, #e6e7e9);
		padding-top: 0;
		padding-left: 1rem;
	}
}
/* Feldpaare (Nummer/Auftraggeber, Titel/Präfix, …) nur, wenn der linke Bereich
   dafür breit genug ist. Bis dahin steht jedes Feld auf eigener Zeile. */
.s-master-fields__main .col-lg-6,
.s-master-fields__main .col-lg-4,
.s-master-fields__main .col-lg-8 {
	flex: 0 0 100%;
	max-width: 100%;
}
@container (min-width: 26rem) {
	.s-master-fields__main .col-lg-6 { flex: 0 0 50%; max-width: 50%; }
	.s-master-fields__main .col-lg-4 { flex: 0 0 33.3333%; max-width: 33.3333%; }
	.s-master-fields__main .col-lg-8 { flex: 0 0 66.6667%; max-width: 66.6667%; }
}

/* Auswahlfeld, das noch auf seinem ersten Eintrag steht: der ist eine
   Aufforderung und kein Wert und wird deshalb gedaempft wie ein Platzhalter —
   dieselbe Farbe, die Bootstrap fuer ::placeholder verwendet. Die aufgeklappte
   Liste bleibt normal lesbar, sonst waeren die Namen darin ebenfalls blass. */
.form-select.s-select-placeholder {
	color: var(--tblr-gray-400, #9ca3af);
}
.form-select.s-select-placeholder option {
	color: var(--tblr-body-color, #374151);
}

/* Ticketliste eines Postens im Projektplan: breit genug fuer Betreff und Status,
   aber gedeckelt — an manchen Posten haengen dutzende Tickets. */
.s-plan-tickets {
	max-width: 32rem;
	max-height: 20rem;
	overflow-y: auto;
}
.s-plan-tickets .dropdown-item {
	font-size: 0.8125rem;
}
/* Der Betreff gibt nach, der Status nicht: ohne das schob der lange Betreff die
   Statusplakette ueber den rechten Rand hinaus und sie war angeschnitten. Ein
   Flex-Kind kuerzt ausserdem nur mit min-width: 0 — sonst ist seine Mindestbreite
   der ganze Text. */
.s-plan-tickets .dropdown-item > .text-truncate {
	flex: 1 1 auto;
	min-width: 0;
}
.s-plan-tickets .dropdown-item > .badge {
	flex: 0 0 auto;
}

/* Farbpunkt vor einer Beschriftung, etwa in der Aufschluesselung der eigenen
   Tickets neben dem Ring. Die Farbe kommt aus den s-bgcolor-*-Klassen. */
.s-legend-dot {
	display: inline-block;
	width: 0.6rem;
	height: 0.6rem;
	border-radius: 50%;
	margin-right: 0.4rem;
	vertical-align: baseline;
}

/* Zwischengroesse fuer die Bilder in der Spalte Umsetzung: avatar-xs (20px) ist
   neben dem Datum zu unscheinbar, avatar-sm (32px) treibt die Zeile auseinander. */
.avatar.s-avatar-24 {
	width: 1.5rem;
	height: 1.5rem;
	font-size: 0.6rem;
}

/* Kurze Faktenliste neben der Anschrift (Umsetzung auf der Projektseite).
   Jede Zeile ist gleich hoch, egal was drinsteht: eine reine Textzeile, ein Name
   mit Bild oder ein Datum als Plakette. Ohne das treiben Bild und Plakette ihre
   Zeile jeweils anders weit auseinander und die Liste wirkt ungeordnet. Mehrzeilige
   Werte bleiben im Raster, weil sie Vielfache derselben Zeilenhoehe belegen. */
.s-facts-table > tbody > tr > th,
.s-facts-table > tbody > tr > td {
	padding-top: 0;
	padding-bottom: 0;
	line-height: 1.5rem;
}
/* Der Zellinhalt bildet einen eigenen Block. Als inline-Element haenge er sonst
   an der Grundlinie, und die Schachtel mit Bild darin machte die Zeile ein
   knappes Pixel hoeher als eine reine Textzeile — genau das, was die Liste
   ungleichmaessig wirken liess. */
/* Nicht fuer Plaketten: die sollen so breit sein wie ihr Inhalt, nicht wie die
   Zelle — als Block liefe die Deadline sonst als Farbbalken durch die Zeile. */
.s-facts-table > tbody > tr > td > a,
.s-facts-table > tbody > tr > td > span:not(.badge) {
	display: flex;
	align-items: center;
	min-height: 1.5rem;
}
.s-facts-table .d-inline-flex {
	line-height: 1.5rem;
}
.s-facts-table .avatar {
	width: 1.25rem;
	height: 1.25rem;
	font-size: 0.55rem;
}
/* Die Plakette bringt eigene Polsterung mit; hier zaehlt nur die Zeilenhoehe. */
.s-facts-table .badge {
	padding-top: 0;
	padding-bottom: 0;
	line-height: 1.25rem;
}

/* Gliedernde Trennlinie: die uebliche helle Rahmenfarbe, dafuer dreifach so
   dick — so trennt sie den Abschnitt ueber die Staerke statt ueber die Farbe. Bootstraps hr
   arbeitet ueber border-top + opacity; ohne das Zuruecksetzen der Deckkraft
   bliebe die Linie blasser als gewollt. */
.s-divider-section {
	border-top: 3px solid var(--tblr-border-color, #e6e7e9);
	opacity: 1;
}

/* Das Schloss steht neben dem Feld oben buendig zur ersten Zeile — bei den
   mitwachsenden Textareas (Titel, Projektmappe) waere die Mitte sonst je nach
   Textlaenge woanders und das Symbol wanderte beim Tippen. Der Versatz ist die
   halbe Zeilenhoehe eines form-control abzueglich der halben Symbolhoehe. */
.s-lock-icon {
	margin-top: 0.75rem;
}

/* Gesperrte Felder (abgeleiteter Titel, feste Projektnummer): bleiben Eingabe-
   felder, sind aber gedaempft und tragen den Textcursor nicht — zusammen mit dem
   Schloss daneben ist erkennbar, dass hier nichts hineingeschrieben wird. Farbe
   aus den Theme-Variablen, damit der Kontrast in beiden Modi stimmt. */
.form-control.s-locked-field {
	background-color: var(--tblr-bg-surface-secondary, #f6f8fb);
	/* Gedaempft, aber klar lesbar: der Wert ist ja der Inhalt des Feldes und
	   nicht bloss ein Hinweis. Nicht dieselbe (hellere) Farbe wie die Trennlinien
	   verwenden — die duerfen zuruecktreten, dieser Text nicht. */
	color: var(--tblr-secondary, #667382);
	cursor: default;
}

/* Inhalts-Indikatoren in der Projektliste: klein und farbig, direkt hinter der
   Projektnummer. Farbe kommt aus den text-*-Klassen. */
.s-content-flags { white-space: nowrap; }
.s-content-flags .ti {
	font-size: .95rem;
	margin-left: .2rem;
	vertical-align: baseline;
}
/* Notiz: Pink — gut lesbar auf Weiß und klar von Datei (Blau)/Plan (Lila) abgesetzt. */
.s-content-flags .s-flag-note { color: #d6336c; }

/* Nur die Trefferliste scrollt; die Fußzeile bleibt als Geschwister darunter. */
#globalSearchResults .s-search-list {
	max-height: 60vh;
	overflow-y: auto;
}
/* Fußzeile mit Gesamttrefferzahl und Nachlade-Schaltfläche, klar unter der
   (scrollenden) Trefferliste abgesetzt. */
#globalSearchResults .s-search-footer {
	border-top: 1px solid var(--tblr-border-color, #e6e7e9);
}

/* Globale Suche im Header: auf md+ mittig in der Kopfzeile und wachsend; auf
   schmalen Screens (Telefon, Hochformat) volle Breite in einer eigenen Zeile
   unter der Brand-/Menü-Zeile (Navbar bricht um). */
.s-header-search {
	display: flex;
	justify-content: center;
}
@media (min-width: 768px) {
	.s-header-search {
		flex: 1 1 auto;
		padding-left: 1.5rem;
		padding-right: 1.5rem;
	}
}
@media (max-width: 767.98px) {
	.s-header-search {
		order: 3;
		flex: 0 0 100%;
		margin-top: 0.5rem;
	}
}

/* Vacation timeline: highlight the whole employee row on hover. The weekday
   grid cells are transparent, so this tint shows through across the row. */
.vac-timeline-row:hover {
	background-color: var(--tblr-table-hover-bg, rgba(0, 0, 0, 0.04));
}

/* Every table highlights the row under the mouse — the same state Tabler's
   .table-hover sets, applied globally so no template needs the extra class. */
.table > tbody > tr:hover > * {
	--tblr-table-color-state: var(--tblr-table-hover-color);
	--tblr-table-bg-state: var(--tblr-table-hover-bg);
}
/* Tabler's light hover tint is fairly strong for whole rows; soften it there. */
:root:not([data-bs-theme="dark"]) .table > tbody > tr:hover > * {
	--tblr-table-bg-state: color-mix(in srgb, var(--tblr-table-hover-bg) 55%, transparent);
}

/* Sick leave: with AU in a dark grey (gray-700), without AU in a lighter grey
   (gray-400), so the two are clearly distinct. */
.bg-sick-au {
	background-color: #6b7280;
	color: #fff;
}
.bg-sick-no-au {
	background-color: #9ca3af;
	color: #fff;
}
/* Partial sick day (fell ill on a day already under way): same grey family, with a
   cool (slate) cast — related to the sick greys, distinct from both and from the warm
   child-sick taupe. Matches the calendar colour #7b8794. */
.bg-sick-partial {
	background-color: #7b8794;
	color: #fff;
}
/* Child sick: same muted family as the sick greys, but a warm (taupe) cast so it
   stays clearly distinguishable from both. */
.bg-sick-child {
	background-color: #8a7f72;
	color: #fff;
}
/* Home office: purple, distinct from the sick greys and the other leave colours
   (special is azure, unpaid indigo). Matches the calendar colour #ae3ec9. */
.bg-homeoffice {
	background-color: #ae3ec9;
	color: #fff;
}

/* Special / unpaid leave badges: same colour families as the calendar, shaded by
   status (requested -> light, eingegangen -> medium, genehmigt -> full). Special is
   purple, unpaid is indigo. */
.badge.bg-special-req  { background-color: #93c6f0; color: #fff; }
.badge.bg-special-once { background-color: #5ba3e6; color: #fff; }
.badge.bg-special-app  { background-color: #4299e1; color: #fff; }
.badge.bg-unpaid-req   { background-color: #93a3f2; color: #fff; }
.badge.bg-unpaid-once  { background-color: #6c81ee; color: #fff; }
.badge.bg-unpaid-app   { background-color: #4263eb; color: #fff; }

/* Role badges (user list + user edit): the Tabler ".bg-*-lt" soft badges have
   coloured text on a tinted background but no outline. Give them a 1px border in
   the same colour as the text (currentColor) so each role reads as a clear pill. */
.badge.js-role-badge {
	border: 1px solid currentColor;
}

/* Small square icon-only button (e.g. the row delete in the user-edit sidebar
   tables). Tabler's .btn-icon zeroes horizontal padding, which with a font icon
   renders portrait; instead give equal padding on all sides and a fixed icon
   size (line-height:1 + display:block so the glyph box stays square). */
.s-btn-icon-square {
	/* set Tabler's own padding vars (which .btn's padding declaration reads) so we
	   win without a specificity fight; equal x/y keeps the button square */
	--tblr-btn-padding-x: 0.2rem;
	--tblr-btn-padding-y: 0.2rem;
	line-height: 1;
}
.s-btn-icon-square > .ti {
	font-size: 1.1rem;
	display: block;
}
/* Small icon button (btn-sm btn-icon) with the same padding on all sides. Tabler drops
   the horizontal padding of btn-icon, which leaves a narrow upright button. */
.btn.s-btn-sm-square {
	padding-left: var(--tblr-btn-padding-y);
	padding-right: var(--tblr-btn-padding-y);
}

/* Alerts: Tabler's soft alerts use a 10% colour tint and a 20% border, which
   barely lifts off a white page. Nudge the tint and border up so they read as a
   distinct block (without going to the solid `alert-important` look). Driven by
   the alert colour variables, so success/info/warning/danger all improve alike
   and it stays correct in dark mode. */
.alert {
	--tblr-alert-bg: color-mix(in srgb, var(--tblr-alert-color) 24%, transparent);
	--tblr-alert-border-color: color-mix(in srgb, var(--tblr-alert-color) 60%, transparent);
}
/* The text of soft alerts stays in the body colour: in the alert colour it would sit
   on its own tint (orange on orange for warnings) and be hard to read. Background,
   border and icon carry the colour; solid alert-important boxes keep their white text. */
.alert:not(.alert-important) {
	color: var(--tblr-body-color);
}

/* Read-only key field in the edit dialogs (the date / year that identifies the
   entry): it must stay fixed but still be submitted, so it is [readonly] — which
   Tabler renders like an editable field. Give it the muted, not-editable look a
   disabled field has, so users see it cannot be changed. */
.form-control.s-readonly {
	background-color: var(--tblr-bg-surface-secondary, #f4f6fa);
	color: var(--tblr-secondary, #6c757d);
	cursor: not-allowed;
}

/* Plan status rendered from Markdown (clickable links etc.): sits in a tight table
   cell, so strip the block margins of the wrapping <p> and keep links visibly
   underlined. */
.s-status-md p {
	margin-bottom: 0;
}
.s-status-md > :last-child {
	margin-bottom: 0;
}
.s-status-md a {
	text-decoration: underline;
}

/* FullCalendar theming: #employeeCalendar / #employeeYearCalendar ARE the .fc root
   elements — FullCalendar puts its .fc classes on the mount node itself, so a
   descendant ".fc" selector matches nothing. Target the ids directly. Follow the
   Tabler theme instead of the library's light defaults (white cells/header, dark text). */
#employeeCalendar,
#employeeYearCalendar {
	--fc-border-color: var(--tblr-border-color);
	--fc-page-bg-color: transparent;
	--fc-neutral-bg-color: var(--tblr-bg-surface-secondary, rgba(0, 0, 0, 0.03));
	--fc-today-bg-color: rgba(var(--tblr-primary-rgb, 32, 107, 196), 0.12);
	color: var(--tblr-body-color);
}
/* day numbers and weekday headers are links; let them use the theme text colour */
#employeeCalendar a,
#employeeYearCalendar a {
	color: inherit;
}
/* Dark mode: the neutral background (weekday header row, off-range areas) would be a
   light Tabler surface — drop it to transparent so the header follows the dark card. */
[data-bs-theme="dark"] #employeeCalendar,
[data-bs-theme="dark"] #employeeYearCalendar {
	--fc-neutral-bg-color: transparent;
}

/* Dark mode: FullCalendar sets some text colours explicitly, so force day numbers,
   weekday headers and (year view) month titles to the theme colour to stay legible. */
[data-bs-theme="dark"] #employeeCalendar,
[data-bs-theme="dark"] #employeeYearCalendar,
[data-bs-theme="dark"] #employeeCalendar .fc-col-header-cell-cushion,
[data-bs-theme="dark"] #employeeYearCalendar .fc-col-header-cell-cushion,
[data-bs-theme="dark"] #employeeCalendar .fc-daygrid-day-number,
[data-bs-theme="dark"] #employeeYearCalendar .fc-daygrid-day-number,
[data-bs-theme="dark"] #employeeYearCalendar .fc-multimonth-title {
	color: var(--tblr-body-color) !important;
}
[data-bs-theme="dark"] #employeeYearCalendar .fc-multimonth-title {
	background-color: var(--tblr-bg-surface-secondary) !important;
}

/* Dark mode: FullCalendar paints the header row and day cells with a light page
   background that does not follow the theme. Force them transparent (the dark card
   shows through); the today highlight is preserved. */
[data-bs-theme="dark"] #employeeCalendar .fc-scrollgrid,
[data-bs-theme="dark"] #employeeYearCalendar .fc-scrollgrid,
[data-bs-theme="dark"] #employeeCalendar .fc-col-header-cell,
[data-bs-theme="dark"] #employeeYearCalendar .fc-col-header-cell,
[data-bs-theme="dark"] #employeeCalendar .fc-daygrid-day:not(.fc-day-today),
[data-bs-theme="dark"] #employeeYearCalendar .fc-daygrid-day:not(.fc-day-today),
[data-bs-theme="dark"] #employeeYearCalendar .fc-multimonth,
[data-bs-theme="dark"] #employeeYearCalendar .fc-multimonth-daygrid {
	background-color: transparent !important;
}

/* Editor-Kopfleisten (Plan- und Angebotseditor, beide body.s-split-editor):
   größere Icons in den Menü-Buttons, ohne die Buttons zu vergrößern —
   line-height:1 hält die Zeilenhöhe niedrig, sodass die Button-Höhe
   (durch Padding + Text-Buttons) unverändert bleibt. */
.s-split-editor header.navbar .btn > .ti {
	font-size: 1.4rem;
	line-height: 1;
	vertical-align: -0.15em;
}

/* Projektliste (#table-default): on small screens the six-column table would need
   horizontal scrolling. Below the md breakpoint, drop the header row and turn each
   row into a stacked card — every cell becomes a "label: value" line — so nothing
   scrolls sideways. The label text comes from each td's data-label attribute. */
@media (max-width: 767.98px) {
	#table-default {
		overflow-x: visible;
	}
	#table-default table.datatable thead {
		display: none;
	}
	#table-default table.datatable,
	#table-default table.datatable tbody,
	#table-default table.datatable tr {
		display: block;
		width: 100%;
	}
	#table-default table.datatable tr {
		border: 1px solid var(--tblr-border-color);
		border-radius: var(--tblr-border-radius, 4px);
		margin-bottom: 0.75rem;
		padding: 0.25rem 0.75rem;
	}
	#table-default table.datatable td {
		display: flex;
		flex-wrap: wrap;
		align-items: flex-start;
		gap: 0.15rem 1rem;
		width: 100%;
		padding: 0.45rem 0;
		border: 0 !important;
		text-align: right;
	}
	/* The usage (Verbrauch) cell carries an inline "display: table-cell" from the
	   controlling-column toggle (schaltzentrale.js), which would otherwise beat the
	   flex layout and leave the value stuck on the left. Only override it when the
	   column is shown; a hidden cell keeps its inline "display: none" and stays gone. */
	#table-default table.datatable td.s-controlling[style*="table-cell"] {
		display: flex !important;
	}
	#table-default table.datatable td:not(:last-child) {
		border-bottom: 1px solid var(--tblr-border-color) !important;
	}
	/* label on the left, muted; margin-right:auto pushes the value(s) to the right
	   edge — works for text and element values alike (space-between misbehaves when
	   a cell has a hidden second child). */
	#table-default table.datatable td::before {
		content: attr(data-label);
		font-weight: 600;
		color: var(--tblr-secondary, #6c757d);
		text-align: left;
		margin-right: auto;
	}
	/* Angebot number and project title each hold two lines: stack them on their own
	   full-width rows and keep them left-aligned so long titles wrap cleanly. */
	#table-default table.datatable td[data-number],
	#table-default table.datatable td[data-project] {
		text-align: left;
	}
	#table-default table.datatable td[data-number] > div,
	#table-default table.datatable td[data-project] > div {
		flex: 1 1 100%;
	}
	/* keep the project-number line modest, not an oversized headline */
	#table-default table.datatable td[data-number] {
		font-size: 0.875rem;
	}
	#table-default table.datatable td[data-number] .d-flex {
		font-weight: 600;
	}
}

/* Project detail (#offerCard): the offer document — a customer address/logo header,
   label/value grid pairs and a six-column line-item table — must reflow on phones.
   Scoped to screen so the printed quote layout is never affected. */
@media screen and (max-width: 767.98px) {
	/* logo and any image must not overflow their column */
	#offerCard img {
		max-width: 100%;
		height: auto;
	}
	/* stack the header (customer / logo) and every label:value grid pair full width.
	   The project detail uses col-2/col-10, the offer-editor preview col-3/col-9. */
	#offerCard .card-body > .row > .col-6,
	#offerCard .col-2,
	#offerCard .col-10,
	#offerCard .col-3,
	#offerCard .col-9 {
		flex: 0 0 100%;
		max-width: 100%;
	}
	#offerCard .col-2 > p,
	#offerCard .col-3 > p {
		margin-bottom: 0;
	}

	/* line-item table -> stacked cards; each cell becomes a "label: value" line */
	#offerCard table.table thead {
		display: none;
	}
	#offerCard table.table,
	#offerCard table.table tbody {
		display: block;
		width: 100%;
		/* override the offer-editor preview's min-width:34rem so the stacked
		   cards are not forced wider than the viewport */
		min-width: 0;
	}
	#offerCard table.table > tbody > tr {
		display: block;
		border: 1px solid var(--tblr-border-color);
		border-radius: var(--tblr-border-radius, 4px);
		margin-bottom: 0.6rem;
		padding: 0.25rem 0.75rem;
	}
	#offerCard table.table > tbody > tr > td {
		display: flex;
		flex-wrap: wrap;
		align-items: flex-start;
		gap: 0.15rem 1rem;
		border: 0 !important;
		padding: 0.35rem 0;
		text-align: right;
	}
	/* the controlling cell carries an inline display:table-cell from the column
	   toggle; force it into the flex row only when shown, so a hidden cell keeps
	   its inline display:none and stays hidden */
	#offerCard table.table > tbody > tr > td.s-controlling[style*="table-cell"] {
		display: flex !important;
	}
	#offerCard table.table > tbody > tr > td:not(:last-child) {
		border-bottom: 1px solid var(--tblr-border-color) !important;
	}
	#offerCard table.table > tbody > tr > td::before {
		content: attr(data-label);
		font-weight: 600;
		color: var(--tblr-secondary, #6c757d);
		text-align: left;
		margin-right: auto;
	}
	/* description holds a title + bullet list: keep the label on its own line and
	   the content left-aligned across the full width */
	#offerCard table.table > tbody > tr > td.s-desc-cell {
		text-align: left;
	}
	#offerCard table.table > tbody > tr > td.s-desc-cell > * {
		flex: 1 1 100%;
	}
	/* netto / vat / brutto: compact right-aligned one-liners, no card frame */
	#offerCard table.table > tbody > tr.s-offer-total {
		display: flex;
		flex-wrap: wrap;
		justify-content: flex-end;
		gap: 0.25rem 0.75rem;
		border: 0;
		margin: 0;
		padding: 0 0.75rem;
	}
	#offerCard table.table > tbody > tr.s-offer-total > td {
		display: inline-block;
		width: auto;
		border: 0 !important;
		padding: 0.1rem 0;
		text-align: right;
	}
	#offerCard table.table > tbody > tr.s-offer-total > td.s-controlling[style*="table-cell"] {
		display: inline-block !important;
	}
	#offerCard table.table > tbody > tr.s-offer-total > td::before {
		content: "";
		margin: 0;
	}
}

/* Angebote list (#offersTable): same card-stack treatment as the projects list so
   the multi-column table (number, customer, title, editors, changed, confirmer,
   download) reflows instead of scrolling sideways on phones. */
@media (max-width: 767.98px) {
	#offersTable thead {
		display: none;
	}
	#offersTable,
	#offersTable tbody,
	#offersTable tr {
		display: block;
		width: 100%;
	}
	#offersTable tbody tr {
		border: 1px solid var(--tblr-border-color);
		border-radius: var(--tblr-border-radius, 4px);
		margin-bottom: 0.75rem;
		padding: 0.25rem 0.75rem;
	}
	#offersTable tbody td {
		display: flex;
		flex-wrap: wrap;
		align-items: flex-start;
		gap: 0.15rem 1rem;
		width: 100%;
		padding: 0.45rem 0;
		border: 0 !important;
		text-align: right;
		white-space: normal !important; /* override the number cell's inline nowrap */
	}
	#offersTable tbody td:not(:last-child) {
		border-bottom: 1px solid var(--tblr-border-color) !important;
	}
	/* label left, value(s) pushed to the right edge */
	#offersTable tbody td::before {
		content: attr(data-label);
		font-weight: 600;
		color: var(--tblr-secondary, #6c757d);
		text-align: left;
		margin-right: auto;
	}
}

/* Worktime header stamp badge: at rest it shows the status + elapsed time; on
   hover/focus it cross-fades to the action (icon + Kommen/Gehen) the click performs.
   Both states are stacked in one grid cell, so the badge width stays constant (the
   wider of the two) and there is no layout shift — only an opacity fade. */
.wt-stamp { padding-left: .8rem; padding-right: .8rem; }
.wt-stamp .wt-stamp-swap { display: inline-grid; align-items: center; }
.wt-stamp .wt-stamp-status,
.wt-stamp .wt-stamp-action {
	grid-area: 1 / 1;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	white-space: nowrap;
	transition: opacity .2s ease, transform .2s ease;
}
.wt-stamp .wt-stamp-status { opacity: 1; transform: translateY(0); }
.wt-stamp .wt-stamp-action { opacity: 0; transform: translateY(0.35em); }
.wt-stamp:hover .wt-stamp-status,
.wt-stamp:focus-visible .wt-stamp-status { opacity: 0; transform: translateY(-0.35em); }
.wt-stamp:hover .wt-stamp-action,
.wt-stamp:focus-visible .wt-stamp-action { opacity: 1; transform: translateY(0); }

/* Heute work block: the delete button only appears on hover/focus of the block; on
   touch devices (no hover) it stays visible so it remains reachable. */
.timeline-event-card .wt-del { opacity: 0; transition: opacity .12s ease; }
.timeline-event-card:hover .wt-del,
.timeline-event-card:focus-within .wt-del { opacity: 1; }
@media (hover: none) { .timeline-event-card .wt-del { opacity: 1; } }

/* Break events get extra vertical room; centre their icon so it stays level with the
   centred "Pause" label (Tabler anchors timeline icons at the top by default). */
.timeline-event-icon.wt-break-icon { top: 50%; transform: translateY(-50%); }

/* Worktime overview: give the time columns comfortable room only where the display
   has space; on phones they stay tight (icon headers) so the row fits without scroll. */
/* Die Zeitspalten brauchten 6,5rem, damit die Ueberschriften nicht umbrechen. Neben der
   Mitarbeiterliste bleibt dafuer aber zu wenig: sechs Spalten a 6,5rem sind mehr als die
   halbe Karte, und die Wochentabelle scrollte seitlich. Ab xl ist wieder Platz. */
@media (min-width: 768px) { .table .wt-time-col { min-width: 5rem; } }
@media (min-width: 1200px) { .table .wt-time-col { min-width: 6.5rem; } }

/* Day modal: reason field and save button stay hidden until the time is edited. A JS
   handler adds .wt-dirty to the form on the first change to its time input. */
/* Tabler 1.6 gives the icon addon the height of a normal input; next to a small input it would sit below the
   middle, so there it spans the input instead. */
.input-icon:has(.form-control-sm) .input-icon-addon { height: auto; }
.wt-editform .wt-reveal { display: none; }
.wt-editform.wt-dirty .wt-reveal { display: block; }

/* A row marked for deletion in the day modal is dimmed so it reads as "will be removed on save". */
.wt-editform:has(input[name="deleteId"]:checked) { opacity: .45; }

/* Terminal look for the read-only API example commands (CodeMirror shell mode). Dark background with
   syntax colors readable on black; overrides the default light theme only for these editors. */
.cm-terminal.CodeMirror {
  background: #1e1e1e;
  color: #e6e6e6;
  border: 1px solid #333;
  border-radius: 6px;
  height: auto;
}
.cm-terminal .CodeMirror-lines { padding: 8px 4px; }
.cm-terminal .CodeMirror-gutters { background: #1e1e1e; border: none; }
.cm-terminal .CodeMirror-cursor { border-left-color: #e6e6e6; }
.cm-terminal.cm-s-default .cm-builtin  { color: #4ec9b0; }  /* curl */
.cm-terminal.cm-s-default .cm-attribute{ color: #9cdcfe; }  /* flags like -H / -X */
.cm-terminal.cm-s-default .cm-keyword  { color: #569cd6; }
.cm-terminal.cm-s-default .cm-string   { color: #ce9178; }  /* quoted header */
.cm-terminal.cm-s-default .cm-def,
.cm-terminal.cm-s-default .cm-variable-2{ color: #dcdcaa; }
.cm-terminal.cm-s-default .cm-number   { color: #b5cea8; }
.cm-terminal.cm-s-default .cm-operator { color: #d4d4d4; }  /* the | pipe */
.cm-terminal.cm-s-default .cm-comment  { color: #6a9955; }

/* ===== Briefdokumente-Editor (body.s-split-editor) =====
   Live-PDF-Vorschau rechts: eigener Scroll-Bereich mit neutralem Hintergrund,
   damit die weißen A4-Seiten mit ihrem Schatten abgesetzt wirken. Höhe wird
   per JS gesetzt (analog Angebotseditor), damit nur die Bereiche scrollen. */
.s-letter-preview {
	overflow-y: auto;
	background: var(--tblr-bg-surface-secondary, #f5f6f8);
	min-height: 200px;
}
[data-bs-theme="dark"] .s-letter-preview {
	background: var(--tblr-bg-surface-secondary, #1a1d24);
}

/* ===== Team-Timeline: Tage anklickbar (nur Personal) =====
   Der Klick wird auf der Spur abgefangen, nicht auf den Tageszellen — so zählt auch
   ein Klick auf einen Balken, ohne dass dieser sein Hover-Popover verliert. Der
   Hover-Hinweis liegt deshalb ebenfalls auf der Spur. */
.vac-timeline-track {
	cursor: pointer;
}

/* Nur der Tag unter dem Zeiger wird hervorgehoben (per JS gesetzt), nicht die ganze
   Zeile: der Klick trifft positionsbasiert genau diesen Tag, und das muss man vorher
   sehen. Über einem Balken bleibt die Markierung stehen, weil sie an der Zelle hängt. */
.vac-day-cell.is-day-hover {
	background-color: var(--tblr-active-bg, rgba(var(--tblr-primary-rgb), 0.18));
	box-shadow: inset 0 0 0 1px rgba(var(--tblr-primary-rgb), 0.45);
}

/* Balken behalten ihren eigenen Cursor, damit erkennbar bleibt, dass dort ein
   vorhandener Eintrag liegt (der Klick landet trotzdem auf der Spur). */
.vac-timeline-track [data-status-popover] {
	cursor: pointer !important;
}

/* "Alle anzeigen"-Schalter: blendet die eingeschränkten Einträge (Krankheit,
   Kind-krank, Home-Office) aus, solange er nicht gesetzt ist. Steht global, weil
   sowohl die Mitarbeiterseite als auch der Team-Kalender denselben Schalter tragen. */
body.s-hide-all .js-all-row,
body.s-hide-all .js-all-event {
	display: none !important;
}

/* Team-Timeline: die gesamte Zeile hebt sich beim Überfahren ab, damit man bei
   vielen Mitarbeitern die Zeile hält, in der man gerade ist. */
.vac-timeline-row:hover {
	background-color: var(--tblr-bg-surface-secondary);
}

/* Nach dem Speichern kurz aufleuchten: markiert den Zeitraum, der gerade geändert wurde.

   Ein einzelnes, frei positioniertes Rechteck statt eingefärbter Tageszellen — Position
   und Breite misst das Skript aus der ersten und letzten betroffenen Zelle. Dadurch ist es
   nicht an das Tagesraster gebunden: es ragt seitlich über den Balken hinaus, füllt die
   volle Zeilenhöhe und kann abgerundet sein.

   Es wird hinter den Balken eingefügt, der Balken bleibt also unverändert davor. Volle
   Deckkraft statt der 0.65 des Wort-Diffs, weil hier nur der Rand rundherum sichtbar ist.
   Farbe ist --s-changed-rgb, dieselbe wie beim Wort-Diff der Angebotsvorschau. */
.vac-day-changed {
	position: absolute;
	/* Negativ, damit das Rechteck die Zeile voll ausfüllt und oben wie unten bis an die
	   Kante geht; die Spur schneidet den Überstand ab. */
	top: -2px;
	bottom: -2px;
	border-radius: 5px;
	pointer-events: none;
	animation: s-day-changed 2.6s ease-out 1;
}

/* Steht ruhig und klingt dann aus — kein Blinken. Gleicher Verlauf wie beim Wort-Diff
   der Angebote: halten, dann weich verschwinden. */
@keyframes s-day-changed {
	0%, 45% { background-color: rgba(var(--s-changed-rgb), 1); }
	100%    { background-color: transparent; }
}

/* Wer Bewegung reduziert haben will, bekommt die Markierung ohne Ausblenden. */
@media (prefers-reduced-motion: reduce) {
	.vac-day-changed {
		animation: none;
		background-color: rgba(var(--s-changed-rgb), 1);
	}
}

/* intranda-Blau als eine Quelle. Der Ton steckt sonst nur hart in den Mail-Vorlagen
   und in MailStyle.BRAND_COLOR; für die Oberfläche gab es ihn bisher nicht. */
:root {
	--s-brand: #438AC9;
}

/* Runde Markierung in Markenfarbe (z. B. der Bierdeckel-Vermerk in Angebotskopf und
   -liste).

   Bewusst NICHT über .btn/.btn-icon: Tablers .btn-icon nimmt nur die seitliche Polsterung
   weg und setzt keine Breite — die Höhe stammt dann aus der Polsterung, die Breite aus dem
   Icon, und heraus kommt ein hohes, schmales Oval statt eines Kreises.

   Der Durchmesser wird stattdessen aus denselben Button-Maßen berechnet, die auch die
   Schaltflächen daneben verwenden. Damit bleibt er ohne feste Pixelwerte gleich groß,
   selbst wenn am Theme gedreht wird. Es ist kein Bedienelement, daher normaler Zeiger. */
.s-icon-circle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: calc(var(--tblr-btn-line-height, 1.25rem) + 2 * var(--tblr-btn-padding-y, 0.5625rem));
	height: calc(var(--tblr-btn-line-height, 1.25rem) + 2 * var(--tblr-btn-padding-y, 0.5625rem));
	border-radius: 50%;
	background-color: var(--s-brand);
	color: #fff;
	line-height: 1;
	cursor: default;
}

/* Kleinere Ausführung für Tabellenzeilen, damit sie die Zeilenhöhe nicht aufbläht. */
.s-icon-circle-sm {
	width: 1.75rem;
	height: 1.75rem;
	font-size: 0.875rem;
}

/* Public holiday in the team timeline. Its own, warmer tint rather than the weekend
   grey: a holiday is not a weekend, and someone scanning the columns should see the
   difference. Deliberately restrained so the bars on top stay readable. */
.vac-holiday {
	background-color: rgba(var(--tblr-red-rgb), 0.12);
}

/* Public holiday in the employee calendar. Rendered as a background event so a vacation
   on the same day stays visible on top; the name is also on the title attribute. */
#employeeCalendar .fc-holiday,
#employeeYearCalendar .fc-holiday {
	/* FullCalendar gives background events opacity: 0.3 — which also washes out the
	   name. Take the opacity back and let the semi-transparent colour alone provide
	   the restraint. */
	opacity: 1;
	background-color: rgba(var(--tblr-red-rgb), 0.12);
}

/* Der Name darf nicht unter die Tageszahl laufen: lange Bezeichnungen wie
   "Christi Himmelfahrt" sind länger als die Zelle breit ist. Deshalb kleiner setzen,
   Platz für die Zahl freihalten und bei Bedarf umbrechen — der volle Name steht
   ohnehin im title-Attribut. */
/* FullCalendar wraps event content in its own positioned container with padding. That
   container would be the reference frame for the name sitting at the bottom and would eat
   its width — so take it out of the positioning context. */
#employeeCalendar .fc-holiday .fc-event-main,
#employeeYearCalendar .fc-holiday .fc-event-main {
	position: static;
}

#employeeCalendar .fc-holiday .fc-event-title,
#employeeYearCalendar .fc-holiday .fc-event-title {
	/* The name sits at the bottom of the cell, not the top: up there the day number is
	   in the way, down here the full cell width is available. The background event
	   already fills the cell, so positioning at its lower edge is enough. */
	position: absolute;
	left: 0.15rem;
	right: 0.15rem;
	bottom: 0.15rem;
	/* small enough for "Christi Himmelfahrt" to fit a cell — including dropping the
	   spacing FullCalendar otherwise gives its events */
	padding: 0;
	margin: 0;
	font-size: 0.7rem;
	line-height: 1.15;
	/* FullCalendar sets event titles in italics; for a day name that only hurts */
	font-style: normal;
	/* Red like the tint of the day, not the pale secondary grey: the name should be
	   readable and recognisable as a holiday. */
	color: var(--tblr-red);
	/* "Tag der Deutschen Einheit" does not fit one cell width at any readable size, so
	   the name may wrap — at a space, mid-word only when there is no other way. */
	white-space: normal;
	overflow-wrap: break-word;
	word-break: normal;
	hyphens: none;
}

/* Caret-Richtung: Tabler zeichnet den Pfeil als Chevron und dreht ihn bei .dropup nach
   oben (rotate(135deg)). Der Pfeil soll überall nach unten zeigen — er steht für "hier
   klappt eine Auswahl auf", nicht für die Richtung, in die das Menü Platz findet (die
   entscheidet Popper ohnehin je nach Viewport). Nur die Rotation überschreiben, damit
   die Chevron-Optik der übrigen Menüs erhalten bleibt. Betrifft z. B. den
   Sprachumschalter im Footer. */
.dropup > .dropdown-toggle::after,
.dropup-center > .dropdown-toggle::after {
	transform: rotate(-45deg);
}

/* Sprachumschalter: btn-sm haelt den Button kompakt, seine 12px-Schrift faellt neben
   Copyright und Version (14px) aber ab. Die Schriftgroesse vom Umgebungskontext erben,
   damit der Umschalter in Footer wie Login-Seite genauso gross wirkt wie der Text
   daneben; Groesse und Zeilenhoehe zusammen, sonst sitzt das Label vertikal schief. */
.s-lang-switch {
	font-size: inherit;
	line-height: inherit;
}

/* Betraege in der Angebots-/Presupuesto-Tabelle nie umbrechen: "1.234.567,89 €" soll
   auch siebenstellig in einer Zeile stehen. Die Breitenangaben im Kopf (width:100px/115px)
   sind bei table-layout:auto nur ein Wunsch — nowrap laesst die Spalte stattdessen
   mitwachsen. Ausgenommen sind Zellen mit colspan: das sind die Label der Zwischen-
   und Gesamtsummen (Kategoriename), die weiter umbrechen duerfen. */
.offer-items-table > tbody > tr > td.text-end:not([colspan]),
.offer-items-table > thead > tr > th.text-end {
	white-space: nowrap;
}

/* Unterunterpunkte: Strich statt Punkt, damit die Ebene auf einen Blick erkennbar ist —
   dasselbe Zeichen, das das PDF fuer eine verschachtelte Liste zeichnet (BULLET_SUB). */
.s-detail-sublist {
	list-style: none;
	padding-left: 1.1rem;
}
.s-detail-sublist > li::before {
	content: "\2013";   /* en dash */
	display: inline-block;
	width: 1.1rem;
	margin-left: -1.1rem;
}

/* Inline-Code in Angebotstexten: gleiche Anmutung wie im Markdown der Korrespondenz —
   eigene Schriftfarbe auf zartem Grund, damit `Feldnamen` als solche lesbar sind. Die Werte
   sind dieselben, die LetterPdfService fuer <code> setzt, und die HelperYaml ins Angebots-PDF
   zeichnet; Vorschau und Dokument sehen damit gleich aus. */
.offer-items-table code {
	font-size: 0.9em;
	color: #bf7704;
	background: #f6f7f8;
	border: 1px solid rgba(0, 0, 0, 0.06);
	padding: 0.05rem 0.25rem;
	border-radius: 3px;
}
/* Im Darkmode wuerde der helle Grund grell stechen: gedaempfter Grund, hellere Schrift. */
[data-bs-theme="dark"] .offer-items-table code {
	color: #e0a03a;
	background: rgba(255, 255, 255, 0.08);
	border-color: rgba(255, 255, 255, 0.10);
}

/* Quelltext-Editor (editType='markdown') ohne die eigene Vorschau von TOAST UI.
   Im Briefeditor steht rechts das fertige PDF — eine zweite, andere Vorschau
   daneben beantwortet dieselbe Frage zweimal und widerspricht sich dabei.

   !important ist hier kein Holzhammer, sondern die einzige Moeglichkeit: TOAST UI
   setzt display:block als Inline-Stil am Element, dagegen kommt keine noch so
   genaue Regel an. Die Vendor-Datei selbst wird nicht angefasst. */
.js-toastui-wrap.s-md-source .toastui-editor-md-tab-container {
	display: none !important;
}

/* ── Suchpalette fuer Positionsvorlagen (Angebots-Editor) ───────────────────────
   Feste Hoehe beider Spalten: mit max-height schrumpfte das Modal bei jedem
   Tastendruck auf die Hoehe der Trefferliste und sprang beim Loeschen wieder auf.
   So bleibt der Rahmen stehen, und nur der Inhalt wechselt. */
.s-palette-box {
	height: 30rem;
	overflow-y: auto;
	/* Ecken bewusst eckig: ein gerundeter Kasten schneidet seinen Inhalt entlang der
	   Rundung ab, und die 3px-Kante der ausgewaehlten Zeile lief in der ersten und
	   letzten Zeile sichtbar um die Kurve. */
	border-radius: 0;
}
/* Zwei Spalten wie im Finder: die Pfeiltasten nach links und rechts wechseln
   zwischen ihnen, hoch und runter bewegen sich in der aktiven. Welche das ist,
   muss man sehen — sonst tippt man ins Leere. */
.s-palette-box.is-active {
	box-shadow: inset 0 0 0 2px rgba(32, 107, 196, 0.35);
}
/* Ohne vergebene Kategorien hat die linke Spalte nichts zu zeigen; sie wird dann
   ausgeblendet und die Trefferliste nimmt die volle Breite ein (siehe
   snippet-palette.js). */
.s-palette-cats:not(.d-none) + #snippetPaletteHitCol {
	flex: 0 0 auto;
	width: 66.66666667%;
}
/* Die Eintraege sind Bedienelemente, keine Aufzaehlung: Zeigefinger, deutlicher
   Hover und eine Auswahl, die man aus zwei Metern erkennt. */
.s-palette-hit {
	cursor: pointer;
	border-left: 3px solid transparent;
}
.s-palette-hit:hover {
	background-color: var(--tblr-bg-surface-secondary, #f6f8fb);
}
/* Kraeftig nur in der aktiven Spalte. In der anderen bleibt die Auswahl sichtbar,
   tritt aber zurueck — sonst leuchten zwei Zeilen gleich stark und es ist nicht
   zu erkennen, welche die Tasten gerade bewegen. */
.s-palette-box.is-active .s-palette-hit.active,
.s-palette-box.is-active .s-palette-hit.active:hover {
	background-color: var(--tblr-primary, #206bc4);
	border-left-color: var(--tblr-primary-darken, #1a568f);
	color: #fff;
}
/* Die gewaehlte Kategorie filtert weiter, auch wenn die Tasten gerade in der
   Trefferliste arbeiten. Sie bleibt deshalb deutlich gekennzeichnet — getoenter
   Grund, blaue Kante, halbfett. Als schlichtes Grau war nicht mehr zu erkennen,
   wonach die Liste daneben ueberhaupt gefiltert ist. */
.s-palette-box:not(.is-active) .s-palette-hit.active {
	background-color: rgba(32, 107, 196, 0.13);
	border-left-color: var(--tblr-primary, #206bc4);
	font-weight: 600;
}
/* Alles in der ausgewaehlten Zeile muss mitziehen — sonst steht grauer
   Sekundaertext auf blauem Grund. */
.s-palette-box.is-active .s-palette-hit.active .text-secondary,
.s-palette-box.is-active .s-palette-hit.active .s-palette-info {
	color: rgba(255, 255, 255, 0.85) !important;
}
/* Das helle Kennzeichen (V/G) verschwindet auf blauem Grund fast; in der Auswahl
   bekommt es einen durchscheinenden Grund statt seiner eigenen Farbe. */
.s-palette-box.is-active .s-palette-hit.active .badge {
	background-color: rgba(255, 255, 255, 0.22) !important;
	color: #fff !important;
}
/* Kategoriezeile: Name links, Anzahl als Plakette rechts, eingerueckt nach Tiefe. */
.s-palette-cat {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	position: relative;
	padding-left: calc(0.5rem + var(--tiefe, 0) * 1.1rem) !important;
}
/* Die Trennlinie beginnt erst dort, wo der Name steht. Ueber die volle Breite lief sie
   auch durch den leeren Einrueckungsbereich davor und zerschnitt die Gliederung, die
   die Fuehrungslinie dort gerade aufbaut. */
.s-palette-cat {
	border-bottom: 0;
}
.s-palette-cat::after {
	content: "";
	position: absolute;
	/* Auf der Wurzelebene genau wie zuvor: von ganz links bis ganz rechts. Unterebenen
	   beginnen genau an ihrer Fuehrungslinie — dort treffen sich senkrechter und
	   waagerechter Strich zur Ecke, statt eine Luecke zu lassen. */
	left: max(0px, calc(var(--tiefe, 0) * 1.1rem - 0.25rem));
	right: 0;
	bottom: 0;
	height: 1px;
	background: var(--tblr-border-color, #e6e7e9);
}
/* Unter der letzten Zeile trennt nichts mehr. */
.s-palette-cat:last-child::after {
	display: none;
}
/* Fuehrungslinie auf Hoehe der Elternebene. Untereinander stehende Geschwister
   ergeben so einen durchgehenden Strich — daran sieht man, was zu wem gehoert;
   die blosse Einrueckung war dafuer zu leise. */
.s-palette-cat[style*="--tiefe"]::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	left: calc(0.85rem + (var(--tiefe, 0) - 1) * 1.1rem);
	width: 1px;
	background: var(--tblr-border-color, #e6e7e9);
}
/* Die Wurzelebene hat keinen Elternteil, also auch keine Linie. */
.s-palette-cat[style*="--tiefe: 0"]::before {
	display: none;
}
/* Der Hinweis auf die Eingabetaste steht nur an der Zeile, die sie gerade trifft. */
.s-palette-hit .s-palette-enter {
	display: none;
}
.s-palette-box.is-active .s-palette-hit.active .s-palette-enter {
	display: inline;
}

/* Knopf zum Ausblenden der Kopfdaten im Briefeditor: er sitzt am rechten Ende der
   Werkzeugleiste von TOAST UI, also ueber dem Editor statt daneben. Ohne die
   Ueberlagerung braeuchte er eine eigene Zeile — genau die Hoehe, die er gewinnen soll.

   Masse und Abstaende sind die der Werkzeugleiste selbst (32 x 32 bei 7px/5px Rand),
   damit er in der Reihe steht und nicht als Fremdkoerper darin. */
.s-editor-maximize {
	position: absolute;
	top: 7px;
	right: 5px;
	z-index: 3;
	width: 32px;
	height: 32px;
	padding: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: 1px solid transparent;
	border-radius: 3px;
}

/* Offer and plan editor: the item under the cursor is tinted in the YAML and in the preview,
   and every item block in the YAML carries its number as a faint watermark at its top right
   (yaml-preview-sync.js). Theme colours, so both stay subtle in light and dark mode. */
.CodeMirror .s-item-active {
	--s-item-tint: rgba(var(--tblr-primary-rgb), 0.07);
	background-color: var(--s-item-tint);
}
/* on the near-black dark background the light values vanish: stronger tint and number */
[data-bs-theme="dark"] .CodeMirror .s-item-active {
	--s-item-tint: rgba(var(--tblr-primary-rgb), 0.28);
}
[data-bs-theme="dark"] #offerPreview tr.s-item-active,
[data-bs-theme="dark"] #planPreview tr.s-item-active,
[data-bs-theme="dark"] #planPreview .gantt-row.s-item-active {
	background-color: rgba(var(--tblr-primary-rgb), 0.28);
}
[data-bs-theme="dark"] .s-item-mark {
	opacity: 0.18;
}
/* a little air above the first and below the last line of the item, drawn as a shadow in
   the same tint so the lines themselves do not move */
.CodeMirror .s-item-active.s-item-active-first {
	box-shadow: 0 -3px 0 0 var(--s-item-tint);
}
.CodeMirror .s-item-active.s-item-active-last {
	box-shadow: 0 6px 0 0 var(--s-item-tint);
}
.CodeMirror .s-item-active.s-item-active-first.s-item-active-last {
	box-shadow: 0 -3px 0 0 var(--s-item-tint), 0 6px 0 0 var(--s-item-tint);
}
/* the whole row, from rule to rule: the plan preview lays its rows out as a padded grid,
   where tinting the cells alone would leave light gaps between and around them */
#offerPreview tr.s-item-active,
#planPreview tr.s-item-active,
#planPreview .gantt-row.s-item-active {
	background-color: rgba(var(--tblr-primary-rgb), 0.07);
}
#offerPreview tr.s-item-active > td,
#planPreview tr.s-item-active > td {
	background-color: transparent;
}
#offerPreview tr[data-item],
body:not(.plan-presentation) #planPreview [data-item] {
	cursor: pointer;
}
/* the plan's full-screen view shows the document only: no editor, so no marking either */
body.plan-presentation #planPreview .s-item-active {
	background-color: transparent !important;
}
.s-item-marks {
	position: absolute;
	inset: 0;
	overflow: hidden;
	pointer-events: none;
	z-index: 3;
}
.s-item-mark {
	position: absolute;
	font-size: 1.75rem;
	font-weight: 700;
	line-height: 1;
	color: var(--tblr-body-color);
	opacity: 0.08;
	user-select: none;
}

/* Channel choice in the "mark as sent" dialog: Tabler has no style for a disabled
   selectgroup box, so the channel that is not available yet looked like the others. */
.form-selectgroup-input:disabled + .form-selectgroup-label {
	opacity: 0.55;
	cursor: not-allowed;
}

/* Signature button in the letter editor toolbar: centre the Tabler icon like the built-in ones. */
.toastui-editor-toolbar-icons.s-toolbar-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background-image: none;
  color: inherit;
}
.toastui-editor-toolbar-icons.s-toolbar-icon-btn .ti { font-size: 18px; line-height: 1; }
/* A custom toolbar item sits in a wrapper that already carries the toolbar's top margin;
   the button's own margin would push it down a second time. */
.toastui-editor-toolbar-item-wrapper > .toastui-editor-toolbar-icons.s-toolbar-icon-btn { margin-top: 0; }
/* Without a stored signature the button stays enabled (so its tooltip shows) but looks disabled. */
.toastui-editor-toolbar-icons.s-signature-btn.s-signature-btn-off { opacity: .4; cursor: not-allowed; }
.toastui-editor-defaultUI-toolbar button.s-signature-btn-off:hover {
  background-color: transparent;
  border-color: transparent;
}

/* Section head inside a card that groups several lists (employee edit page): a quiet
   subheader with its add button, instead of one card header per list. */
.s-card-section-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 1rem .5rem;
}
/* A heading, not a label: it must stand apart from the small uppercase table head below,
   yet stay under the card title (1rem) — body size, set apart by weight only. */
.s-card-section-title {
  margin: 0;
  font-size: .875rem;
  font-weight: var(--tblr-font-weight-semibold, 600);
  color: var(--tblr-body-color);
}

/* Row actions that only show while the row is hovered or focused, so a list does not
   carry a column of red buttons. Devices without hover always show them. */
.s-row-hover-actions .s-row-action { opacity: 0; transition: opacity .15s; }
.s-row-hover-actions:hover .s-row-action,
.s-row-hover-actions:focus-within .s-row-action { opacity: 1; }
@media (hover: none) {
  .s-row-hover-actions .s-row-action { opacity: 1; }
}

/* Long titles that open a record from a list: body color with a little more weight, so the
   clickable column stands out without a column full of blue; primary and underlined on hover.
   Short identifiers (invoice or project numbers) stay ordinary primary links. */
a.s-row-link,
button.s-row-link {
	color: var(--tblr-body-color);
	font-weight: var(--tblr-font-weight-medium, 500);
	text-decoration: none;
}
/* rows shown muted (e.g. future days) keep their links muted */
.text-secondary > td a.s-row-link,
.text-secondary > td button.s-row-link {
	color: inherit;
}
/* the same look for buttons that start an action (POST forms, modals) */
button.s-row-link {
	background: none;
	border: 0;
	padding: 0;
	text-align: start;
	cursor: pointer;
}
a.s-row-link:hover,
a.s-row-link:focus-visible,
button.s-row-link:hover,
button.s-row-link:focus-visible {
	color: var(--tblr-primary);
	text-decoration: underline;
}

/* ================================ TOASTS ================================
   Feedback after an action (schaltzentrale.js, window.szToast): dark whatever the theme, at the bottom centre, one at
   a time. ok and info show a ring around the close button for the time left. */
.s-toasts {
	position: fixed;
	left: 50%;
	bottom: 1.5rem;
	transform: translateX(-50%);
	z-index: 1090;
	width: max-content;
	max-width: min(34rem, calc(100vw - 2rem));
	pointer-events: none;
}
.s-toast {
	pointer-events: auto;
	display: flex;
	align-items: flex-start; /* icon and close stay at the top of a sentence over several lines */
	gap: .75rem;
	padding: .65rem .65rem .65rem 1rem;
	border-radius: 1rem;
	/* neutral like the themes (no blue cast): dark on the light theme, a step lighter than the cards on the dark one */
	background-color: oklch(0.26 0 0);
	color: oklch(0.97 0 0);
	box-shadow: 0 .75rem 2rem rgba(0, 0, 0, .3);
	font-size: .9375rem;
	font-weight: 600;
	animation: s-toast-in .2s ease-out;
}
/* icon, first line of the sentence and close share one centre line (the close button's 2.25rem) */
.s-toast-icon {
	flex: 0 0 auto;
	height: 2.25rem;
	display: inline-flex;
	align-items: center;
	font-size: 1.75rem;
}
.s-toast-ok .s-toast-icon { color: #4ade80; }
.s-toast-info .s-toast-icon { color: #60a5fa; }
.s-toast-warn .s-toast-icon { color: #fbbf24; }
.s-toast-error .s-toast-icon { color: #f87171; }
.s-toast-text {
	flex: 1 1 auto;
	line-height: 1.4;
	padding-block: calc((2.25rem - 1.4em) / 2);
}
.s-toast-close {
	position: relative;
	flex: 0 0 auto;
	width: 2.25rem;
	height: 2.25rem;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: 0;
	border-radius: 50%;
	background: transparent;
	color: inherit;
	font-size: 1.125rem;
}
.s-toast-close:hover,
.s-toast-close:focus-visible {
	background-color: rgba(255, 255, 255, .12);
}
.s-toast-ring {
	position: absolute;
	inset: 0;
	transform: rotate(-90deg);
}
.s-toast-ring circle {
	fill: none;
	stroke: rgba(255, 255, 255, .55);
	stroke-width: 2;
	stroke-dasharray: 100.53;
	stroke-dashoffset: 0;
	animation-name: s-toast-ring;
	animation-timing-function: linear;
	animation-fill-mode: forwards;
}
.s-toast.is-paused .s-toast-ring circle {
	animation-play-state: paused;
}
[data-bs-theme="dark"] .s-toast {
	background-color: oklch(0.36 0 0);
	box-shadow: 0 0 0 1px var(--tblr-border-color), 0 .75rem 2rem rgba(0, 0, 0, .5);
}
@keyframes s-toast-ring {
	to { stroke-dashoffset: 100.53; }
}
@keyframes s-toast-in {
	from { opacity: 0; transform: translateY(.5rem); }
	to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
	.s-toast { animation: none; }
	.s-toast-ring { display: none; }
}

/* Notice: a sentence that stays on the page, a Tabler alert with the class s-notice. The icon of its tone stands
   in front, drawn here so a script may replace the text of the alert. For warnings and errors the sentence is in the
   text colour, only frame, surface and icon carry the colour; it reads better on the light tint. */
.alert.s-notice {
	position: relative;
	padding-inline-start: calc(var(--tblr-alert-padding-x) + var(--tblr-alert-icon-size) + .75rem);
}
.alert.s-notice::before {
	position: absolute;
	inset-inline-start: var(--tblr-alert-padding-x);
	top: var(--tblr-alert-padding-y);
	font-family: "tabler-icons";
	font-size: var(--tblr-alert-icon-size);
	line-height: 1.1;
	color: var(--tblr-alert-color);
	content: "\eac5";
}
.alert.s-notice.alert-success::before { content: "\ea67"; }
.alert.s-notice.alert-warning::before { content: "\ea06"; color: var(--tblr-warning); }
.alert.s-notice.alert-danger::before { content: "\ea05"; color: var(--tblr-danger); }
.alert.s-notice.alert-warning,
.alert.s-notice.alert-danger {
	color: var(--tblr-body-color);
}
/* on the dark theme the notice takes the neutral surface with only a hint of its tone, instead of Tabler's tinted
   fill that clashes with the grey dark theme; frame and icon keep the colour */
[data-bs-theme="dark"] .alert.s-notice {
	background-color: color-mix(in oklab, var(--tblr-alert-color) 10%, var(--tblr-bg-surface));
	border-color: color-mix(in oklab, var(--tblr-alert-color) 45%, var(--tblr-bg-surface));
	color: var(--tblr-body-color);
}
/* the decider's choice of a person: compact rows, small pictures */
.bk-person-list .list-group-item { padding-block: .4rem; gap: .6rem !important; }
.bk-person-list .avatar { --tblr-avatar-size: 1.6rem; }
/* a decider looking at a colleague: on phones picture and "Zu mir wechseln" on the first line, the sentence below */
@media (max-width: 575.98px) {
	[data-booking-viewing] .bk-viewing-text { order: 3; flex-basis: 100%; }
}
/* a notice that brings an icon of its own in the markup */
.alert.s-notice.s-notice-own-icon {
	padding-inline-start: var(--tblr-alert-padding-x);
}
.alert.s-notice.s-notice-own-icon::before {
	content: none;
}
/* the own icon in the size of the notice icons */
.alert.s-notice.s-notice-own-icon > .ti:first-child {
	font-size: var(--tblr-alert-icon-size);
}

/* Customer picker (TomSelect): the address under the name stays readable on the highlighted row */
.ts-dropdown .option.active .text-secondary {
	color: inherit !important;
	opacity: .8;
}

/* Pool icon next to the hours badge in the plan preview: as tall as the badge. */
.s-hours i.s-offered {
	font-size: 1.25rem;
	vertical-align: middle;
}

/* ================================ BOOKING PAGE ================================
   Week/day overview and booking modal (/booking). Category colours as in the Ticket Finder: solid for bars and
   dots, a light/dark pair for the hours badge; the ticket number pill takes the colour of its tracker. */
:root {
	--bk-support: #5D6D7E;
	--bk-projects: #4A90D9;
	--bk-internal: #E55039;
	--bk-unbooked: #F2C14E;
	--bk-rest: #D9DDE2;
	--bk-track: #ECEEF1;
	--bk-support-bg: #ECEEF0;
	--bk-support-fg: #4C5A68;
	--bk-internal-bg: #FCE7E2;
	--bk-internal-fg: #B23A28;
	--bk-projects-bg: #E7F0FA;
	--bk-projects-fg: #2C6FB5;
}
[data-bs-theme="dark"] {
	--bk-rest: #4A5561;
	--bk-track: #2A323B;
	--bk-support-bg: #2A323B;
	--bk-support-fg: #ADBBC7;
	--bk-internal-bg: #3A2622;
	--bk-internal-fg: #E49382;
	--bk-projects-bg: #1B2C3D;
	--bk-projects-fg: #6FB1EB;
}
.bk-c-support { --bk-c: var(--bk-support); }
.bk-c-projects { --bk-c: var(--bk-projects); }
.bk-c-internal { --bk-c: var(--bk-internal); }
.bk-c-unbooked { --bk-c: var(--bk-unbooked); }
.bk-c-rest { --bk-c: var(--bk-rest); }
/* attended time that cannot be split into booked/unbooked while a tracker fails: left blank */
.bk-c-unknown { --bk-c: transparent; }
.bk-num { font-variant-numeric: tabular-nums; }
.bk-min-0 { min-width: 0; }
.bk-seg .nav-link { min-width: 4.5rem; }
.bk-seg .nav-link.active { font-weight: 600; }
/* like a slider: the chosen view is a filled knob in the secondary colour on Tabler's grey track */
.nav-segmented.bk-seg .nav-link.active { background: var(--tblr-secondary); color: #fff;
	box-shadow: 0 1px 3px rgba(0, 0, 0, .18); }
/* app: segmented switch like a slider: a white pill as track (like the cards and the search field on the light
   blue page), the chosen segment a strong blue pill with white text inside it; segments of equal width (as wide as
   the widest label) */
.app .nav-segmented.bk-seg { padding: 3px; gap: 0; border: 1px solid var(--tblr-border-color); border-radius: 999px;
	box-shadow: 0 1px 2px rgba(0, 0, 0, .04); background: var(--tblr-bg-surface);
	display: inline-grid; grid-auto-flow: column; grid-auto-columns: 1fr; }
.app .nav-segmented.bk-seg .nav-link { min-width: 0; justify-content: center; gap: .4rem; margin: 0; border: 0;
	border-radius: 999px; padding: .35rem .8rem; color: var(--tblr-body-color); background: transparent;
	box-shadow: none; }
/* its icons as large as the text beside them reads, not the small default */
.app .nav-segmented.bk-seg .nav-link .ti { font-size: 1.15rem; }
.app .nav-segmented.bk-seg .nav-link:hover { background: color-mix(in srgb, var(--tblr-primary) 8%, transparent); }
.app .nav-segmented.bk-seg .nav-link.active { font-weight: 600; color: #fff; background: var(--tblr-primary);
	box-shadow: 0 1px 3px rgba(0, 0, 0, .2); }
/* Overview header: toggle left, paging centred, "Heute" right; stacked paging on phones. */
.bk-nav-head { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: .5rem; }
.bk-nav-head .bk-today { justify-self: end; }
/* app: paging alone, arrows at the ends */
.bk-nav-head.bk-nav-head-app { display: block; padding: .25rem 0; min-height: 0; border: 0; }
/* app: the paging line stands on the page, without a card around it */
.app .bk-nav-card { background: transparent; border: 0; box-shadow: none; }
.app .bk-nav-head-app .btn.btn-icon { min-height: 0; min-width: 0; width: 2.1rem; height: 2.1rem;
	--bk-pg: color-mix(in srgb, var(--tblr-primary) 80%, var(--tblr-bg-surface));
	background: var(--bk-pg); border-color: var(--bk-pg); color: #fff; }
.app .bk-nav-head-app .btn.btn-icon:hover { background: var(--tblr-primary); }
.app .bk-nav-head-app .btn.btn-icon:disabled { opacity: .35; }
.bk-nav-head-app .bk-nav { justify-content: space-between; }
/* app with the week's ring: paging as one group on the left (arrows close around the date, its digits of equal width
   so the right arrow keeps its place), the booked total with the ring as the second group on the right */
.bk-nav-head-app .bk-nav:has(.bk-donut-jump) { justify-content: flex-start; gap: .25rem !important; }
.bk-nav-head-app .bk-nav:has(.bk-donut-jump) .bk-nav-label { font-variant-numeric: tabular-nums; }
.bk-nav-head-app .bk-donut-jump { margin-left: auto; }
/* the right group on a white pill like the day cards below: one element, and visibly something to tap */
.app .bk-donut-jump { padding: .2rem .25rem .2rem .7rem; border-radius: 999px; background: var(--tblr-bg-surface);
	box-shadow: var(--tblr-shadow-card); }
.bk-donut-jump { flex: none; display: inline-flex; align-items: center; gap: .4rem; color: inherit; text-decoration: none; }
.bk-donut-jump:hover { color: inherit; text-decoration: none; }
.bk-donut-jump-total { font-weight: 700; font-variant-numeric: tabular-nums; }
.bk-donut.bk-donut-mini { display: block; width: 2.1rem; height: 2.1rem; }
/* app bar: week/day as in the Ticket Finder, the chosen one white on a light track */
[data-app-person-title] { user-select: none; -webkit-user-select: none; touch-action: manipulation; }
.app-bar-seg { display: inline-grid; grid-auto-flow: column; grid-auto-columns: 1fr; flex: none; padding: 3px;
	border-radius: 999px; background: rgba(255, 255, 255, .18); }
.app-bar-seg > button, .app-bar-seg > a { display: inline-flex; align-items: center; justify-content: center; border: 0;
	border-radius: 999px; padding: .25rem .7rem; background: transparent; color: #fff; font-weight: 600; font-size: .78rem;
	text-decoration: none; }
.app-bar-seg > a .ti { font-size: 1.2rem; }
.app-bar-seg > button.active, .app-bar-seg > a.active { background: #fff; color: var(--tblr-primary); box-shadow: 0 1px 3px rgba(0, 0, 0, .15); }
/* keep the week/day switch at its natural width; the grid cell would otherwise stretch it on phones */
.bk-nav-head .bk-seg { justify-self: start; }
/* a little air between the paging buttons and the date */
.bk-nav-label { padding: 0 .3rem; }
@media (max-width: 575.98px) {
  .bk-nav-head { grid-template-columns: 1fr auto; }
  .bk-nav-head .bk-nav { grid-column: 1 / -1; grid-row: 2; justify-content: space-between; }
}

/* bars: the week bar below the summary, the day bar as the 6px top edge of a day card */
.bk-stack { display: flex; height: .7rem; border-radius: 999px; overflow: hidden; cursor: help; }
.bk-stack > span { display: block; height: 100%; background: var(--bk-c); }
.bk-stack.bk-day-bar { height: 6px; border-radius: 0; }

/* the bar legend inside a Bootstrap tooltip (classes only: the tooltip sanitizer drops inline styles) */
.tooltip-inner:has(.bk-legend) { max-width: 18rem; text-align: left; }
.bk-legend { font-size: .8rem; line-height: 1.6; min-width: 13.5rem; }
.bk-legend-row { display: flex; align-items: center; gap: .45rem; }
.bk-legend-t { margin-left: auto; font-variant-numeric: tabular-nums; }
/* a light ring keeps dark dots (Support) visible on the dark tooltip */
.bk-legend .bk-dot { box-shadow: 0 0 0 1.5px rgba(255, 255, 255, .85); }
/* absences in the week tooltip: no colour in the bar, so no dot, a little quieter */
.bk-legend-absence { opacity: .8; }
.bk-legend-sum { border-top: 1px solid rgba(255, 255, 255, .3); margin-top: .2rem; padding-top: .2rem; font-weight: 600; }
.bk-dot { display: inline-block; width: .6rem; height: .6rem; border-radius: 50%; background: var(--bk-c); flex: none; }

/* day cards */
.bk-day-card { margin-top: 1.25rem; overflow: hidden; }
.bk-day-head { background: var(--tblr-bg-surface); border-bottom: 1px solid var(--tblr-border-color); }
/* Today: the card lifts off the page with a strong shadow and more room around it; no coloured frame. */
.bk-day-card.bk-day-card-today { margin-top: 2rem; margin-bottom: 2rem;
  box-shadow: 0 1rem 2.5rem rgba(24, 36, 51, .3), 0 .15rem .4rem rgba(24, 36, 51, .14); }
.bk-day-add { width: 1.5rem !important; min-width: 0 !important; height: 1.5rem; min-height: 0; padding: 0;
	border-radius: .35rem; color: var(--tblr-secondary); border-color: var(--tblr-border-color); }
.bk-day-add .ti { font-size: .9rem; }
.bk-entry { cursor: pointer; }
.bk-entry:hover { background: color-mix(in srgb, var(--tblr-primary) 5%, transparent); }
a.bk-entry, a.bk-entry:hover { color: inherit; text-decoration: none; }
/* an entry without a ticket opens nothing */
.bk-entry.bk-entry-plain { cursor: default; }
.bk-entry.bk-entry-plain:hover { background: none; }
.bk-entry .bk-title { font-weight: 600; }
/* folder and project, ticket pill (and status): a pill that wraps gets its own line with air above, not indented */
.bk-meta { display: flex; flex-wrap: wrap; align-items: center; gap: .45rem .5rem; font-size: .8rem; color: var(--tblr-secondary); }

/* hours badge by category, ticket number pill by tracker */
.bk-hb { display: inline-block; padding: .3rem .6rem; border-radius: .6rem; font-weight: 600;
	font-variant-numeric: tabular-nums; white-space: nowrap; }
.bk-hb-support { background: var(--bk-support-bg); color: var(--bk-support-fg); }
.bk-hb-projects { background: var(--bk-projects-bg); color: var(--bk-projects-fg); }
.bk-hb-internal { background: var(--bk-internal-bg); color: var(--bk-internal-fg); }
.bk-pill { display: inline-block; padding: 0 .45rem; font-size: .78rem; line-height: 1.25; border: 1px solid; white-space: nowrap; }
/* Title, note and folder line of an entry stack with one even gap; the pill fits the text line. */
.bk-lines { display: flex; flex-direction: column; gap: .2rem; line-height: 1.35; }
.bk-lines > * { margin: 0; }
.bk-entry, .bk-recent-row { padding-top: .75rem; padding-bottom: .75rem; }
.bk-pill-bugs { background: var(--bk-projects-bg); color: var(--bk-projects-fg); border-color: var(--bk-projects-fg); }
.bk-pill-support { background: var(--bk-support-bg); color: var(--bk-support-fg); border-color: var(--bk-support-fg); }

/* distribution of the hours: donut of the viewed week with its legend, then one stacked bar per week */
.bk-dist { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.25rem; }
/* Chart.js draws the ring into the canvas; the booked total sits in its middle as plain text */
.bk-donut { position: relative; width: 8.5rem; height: 8.5rem; flex: none; }
.bk-donut canvas { position: absolute; inset: 0; }
.bk-donut-center { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center;
	justify-content: center; pointer-events: none; line-height: 1.15; }
.bk-donut-total { font-size: 1.3rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.bk-donut-sub { font-size: .7rem; color: var(--tblr-secondary); }
/* the donut's tooltip (booking.js), dark like a Bootstrap tooltip */
.bk-donut-tip { position: absolute; z-index: 1080; pointer-events: none; opacity: 0; transition: opacity .1s;
	padding: .25rem .5rem; border-radius: var(--tblr-border-radius); background: var(--tblr-gray-900, #182433);
	color: #fff; }
.bk-dist-legend { flex: 1 1 10rem; min-width: 0; display: flex; flex-direction: column; gap: .6rem; }
/* dot, label, value: a long label ("Ohne Buchung") wraps instead of running into the value */
.bk-dist-row { display: grid; grid-template-columns: auto minmax(4.25rem, 1fr) auto; align-items: center; gap: .5rem; }
.bk-dist-row .bk-num { white-space: nowrap; }
/* target, attendance and booked under the donut, set off by a line */
.bk-dist-facts { display: flex; flex-direction: column; gap: .6rem; margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--tblr-border-color); }
.bk-dist-fact { display: flex; justify-content: space-between; gap: .5rem; }
.bk-dist-fact .bk-num { white-space: nowrap; }
/* website side column: a smaller donut, so it still fits beside its legend */
.bk-side .bk-donut { width: 7rem; height: 7rem; }
.bk-side .bk-dist { gap: 1rem; }
.bk-side .bk-dist-row { grid-template-columns: auto minmax(0, 1fr) auto; }
.bk-side .bk-dist-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 1399.98px) {
	.bk-side .bk-donut { width: 6rem; height: 6rem; }
	.bk-side .bk-donut-total { font-size: 1.1rem; }
}
@media (max-width: 420px) {
	.bk-donut { width: 7rem; height: 7rem; }
	.bk-dist { gap: 1rem; }
}
/* Narrow card (phone): date and total on one line above a full-width bar; the values are in the bar's tooltip. */
.bk-weeks { container-type: inline-size; }
.bk-week-row { display: grid; grid-template-columns: minmax(0, 1fr) auto;
	grid-template-areas: "label total" "bar bar"; align-items: center; gap: .35rem .6rem;
	padding: .45rem 0; font-size: .85rem; }
.bk-week-label { grid-area: label; }
.bk-week-stack { grid-area: bar; }
.bk-week-total { grid-area: total; }
/* Wider card: date column left, bar, total right. */
@container (min-width: 18rem) {
	.bk-week-row { grid-template-columns: 6.2rem minmax(0, 1fr) 3rem;
		grid-template-areas: "label bar total"; padding: .3rem 0; }
}
.bk-week-stack { display: flex; height: .55rem; border-radius: 999px; overflow: hidden; background: var(--bk-track); }
.bk-week-stack > span { display: block; height: 100%; background: var(--bk-c); }
.bk-week-total { text-align: right; font-weight: 600; }
.bk-week-legend { display: flex; justify-content: center; flex-wrap: wrap; gap: .25rem 1rem; margin-top: .75rem;
	font-size: .8rem; color: var(--tblr-secondary); }
.bk-week-legend > span { display: inline-flex; align-items: center; gap: .35rem; }
/* "Arbeitszeit" on the app's distribution page: label and hours on a line, the bar below; --bk-goal marks the target */
.bk-hours-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .3rem .5rem; padding: .3rem 0; }
.bk-hours-bar { grid-column: 1 / -1; position: relative; display: flex; height: .55rem; border-radius: 999px;
	background: var(--bk-track); }
.bk-hours-bar > span { display: block; height: 100%; background: var(--bk-c); }
.bk-hours-bar > span:first-child { border-radius: 999px 0 0 999px; }
.bk-hours-bar > span:last-child { border-top-right-radius: 999px; border-bottom-right-radius: 999px; }
.bk-hours-target { --bk-c: var(--bk-rest); }
.bk-hours-attended { --bk-c: color-mix(in srgb, var(--tblr-body-color) 45%, transparent); }
.bk-hours-bar::after { content: ""; position: absolute; top: -.2rem; bottom: -.2rem; left: var(--bk-goal);
	width: 2px; margin-left: -1px; border-radius: 1px; background: var(--tblr-body-color); opacity: .55; }
/* the side column is a quiet sidebar: no card frames, straight on the page background, small grey headings,
   so the week overview on the left reads as the main part */
.bk-side .card { background: transparent; border: 0; box-shadow: none; }
.bk-side .card-header { padding-inline: 0; padding-top: 0; border-bottom: 0; min-height: 0; }
.bk-side .card-body { padding-inline: 0; }
.bk-side .card-header .card-title, .bk-side .bk-weeks > h4, .bk-side .bk-hours > h4 { font-size: .75rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .04em; color: var(--tblr-secondary); }
.bk-side .card + .card { margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid var(--tblr-border-color); border-radius: 0; }
.bk-side .bk-recent-list { margin-inline: -.5rem; }
.bk-side .bk-recent-list .list-group-item { background: transparent; border: 0; padding-inline: .5rem;
  border-radius: var(--tblr-border-radius); }
.bk-side .bk-recent-list .list-group-item-action:hover { background: var(--tblr-bg-surface); }
/* app: the section labels on the grey page darker, so they stand out */
.app .bk-side .card-header .card-title, .app .bk-side .bk-weeks > h4, .app .bk-side .bk-hours > h4,
.app-ticket .bk-section-title {
	color: color-mix(in srgb, var(--tblr-body-color) 80%, transparent); }
/* app: "Zuletzt gebucht" a little further from the days above and closer to its list */
.app-booking #booking-recent > .card-header { padding-top: 1.25rem; padding-bottom: .5rem; }
/* app: the recently booked entries framed as one list without gaps, like the own entries on the ticket */
.app-booking .bk-side .bk-recent-list { margin-inline: -.5rem; }
.app-booking .bk-side .bk-recent-list .list-group-item { padding-inline: 1rem; border: 1px solid var(--tblr-border-color);
	border-radius: 0; background: var(--tblr-bg-surface); }
.app-booking .bk-side .bk-recent-list .list-group-item + .list-group-item { border-top: 0; }
.app-booking .bk-side .bk-recent-list .list-group-item:first-child { border-top-left-radius: var(--tblr-border-radius);
	border-top-right-radius: var(--tblr-border-radius); }
.app-booking .bk-side .bk-recent-list .list-group-item:last-child { border-bottom-left-radius: var(--tblr-border-radius);
	border-bottom-right-radius: var(--tblr-border-radius); }
/* app: a tighter legend */
.app .bk-side .bk-dist-legend { gap: .3rem; }
/* app: the sidebar's content a little in from the edge, so it does not stick to it */
.app .bk-side { padding-inline: calc(var(--tblr-gutter-x) * .5 + .5rem); }
/* Desktop: more room between the overview's cards and the sidebar */
@media (min-width: 992px) {
  .bk-side { padding-left: calc(var(--tblr-gutter-x) * .5 + 1.5rem); }
}
.bk-recent-row .bk-dot { width: .55rem; height: .55rem; margin-top: .45rem; }
.bk-recent-row .bk-title { font-weight: 600; }
.bk-when { width: 3.6rem; text-align: right; flex: none; }

/* phones: round floating button instead of the page button */
.bk-fab { position: fixed; right: 1rem; bottom: calc(1rem + env(safe-area-inset-bottom)); z-index: 1030;
	width: 3.5rem; height: 3.5rem; padding: 0; border-radius: 50%; box-shadow: 0 6px 16px rgba(0, 0, 0, .18); }
.bk-fab .ti { font-size: 1.75rem; }

/* booking modal */
.bk-suggest { position: absolute; left: 0; right: 0; top: 100%; z-index: 10; max-height: 22rem; overflow: auto; }
/* wider screens (website and app): more tickets at once, down to the window's edge (the room is measured by the scripts) */
@media (min-width: 768px) and (min-height: 500px) { .bk-suggest { max-height: min(40rem, var(--bk-suggest-room, 22rem)); } }
.bk-suggest .list-group-item { padding-top: .4rem; padding-bottom: .4rem; }
.bk-suggest-row .bk-dot { width: .55rem; height: .55rem; margin-top: .4rem; }
.bk-suggest-row .bk-title { font-weight: 600; }
.bk-suggest .list-group-item.active-item { background: color-mix(in srgb, var(--tblr-primary) 8%, transparent); }
.bk-picked { display: flex; align-items: flex-start; gap: .5rem; height: auto; min-height: 2.5rem;
	padding-top: .45rem; padding-bottom: .45rem; }
.bk-picked[hidden] { display: none; }

/* ticket view (website modal, app page): description and notes are the tracker's Markdown, rendered and sanitized */
.bk-ticket-subject { font-size: 1.15rem; line-height: 1.35; }
.bk-ticket-facts dt { font-weight: 400; color: var(--tblr-secondary); }
.bk-ticket-facts dd { margin-bottom: .25rem; }
/* the person's own entries in the ticket view: hours badge, date and note, "Ändern" on the right */
.bk-ticket-entries .list-group-item { padding: .5rem .75rem; }
.bk-entry-edit { flex: none; }
.bk-delete-icon { font-size: 2rem; }
/* The discard question loads into the clock dialog; it keeps the small size of the other confirmations. */
#clockModal .modal-dialog:has(> [data-clock-confirm]) { max-width: 380px; }
.bk-ticket-text { white-space: pre-wrap; overflow-wrap: anywhere; }
.bk-ticket-md { overflow-wrap: anywhere; }
.bk-ticket-md > :last-child { margin-bottom: 0; }
/* code blocks wrap instead of scrolling sideways on a phone */
.bk-ticket-md.markdown-body pre, .bk-ticket-md.markdown-body pre code { white-space: pre-wrap; overflow-wrap: anywhere; font-size: .82rem; }
/* the tracker's code blocks follow the theme here instead of the global dark block, which is too heavy in light mode */
.bk-ticket-md.markdown-body pre { background-color: var(--tblr-bg-surface-secondary) !important; color: var(--tblr-body-color) !important; border: 1px solid var(--tblr-border-color); }
/* always set off from the box around them: white in a grey box (app), grey in a white one (the modal's ticket card) */
.bk-ticket-box.bk-ticket-md.markdown-body pre { background-color: var(--tblr-bg-surface) !important; }
.bk-ticket-head .bk-ticket-box.bk-ticket-md.markdown-body pre { background-color: var(--tblr-bg-surface-secondary) !important; }
/* the wide ticket modal: own entries in the right column on their own background from top to bottom of the modal,
   kept in view while the ticket scrolls */
@media (min-width: 992px) {
  .bk-ticket-aside-inner > h4:first-child { margin-top: 0 !important; }
  .bk-ticket-aside { margin: calc(-1 * var(--tblr-modal-padding)) calc(-1 * var(--tblr-modal-padding)) calc(-1 * var(--tblr-modal-padding)) 0;
    padding: var(--tblr-modal-padding); background: var(--tblr-bg-surface-secondary); border-left: 1px solid var(--tblr-border-color); }
  .bk-ticket-aside-inner { position: sticky; top: 0; }
}
.bk-person { display: inline-flex; align-items: center; gap: .4rem; }
.bk-person .bk-avatar, .bk-journal .bk-avatar { flex: none; }
/* the ticket's card in the wide modal on a light grey; the boxes inside (description, checklist) a slightly deeper
   grey, set apart from the card and from the modal's own background */
.bk-ticket-head { background: var(--tblr-bg-surface-secondary); }
/* ticket status as in the Ticket Finder: a rounded badge with frame in the colour of its group */
.badge.bk-status { --bk-st-bg: #EEF0F3; --bk-st-fg: #51606E; border-radius: 999px; border: 1px solid var(--bk-st-fg);
	background: var(--bk-st-bg); color: var(--bk-st-fg); font-weight: 500; }
.badge.bk-status-neu { --bk-st-bg: #FBE9E9; --bk-st-fg: #B23A3A; }
.badge.bk-status-arbeit { --bk-st-bg: #E5EFFB; --bk-st-fg: #1C5D99; }
.badge.bk-status-klaerung { --bk-st-bg: #FCE9D3; --bk-st-fg: #B25E16; }
.badge.bk-status-zugewiesen { --bk-st-bg: #FBF1D2; --bk-st-fg: #8A6A00; }
.badge.bk-status-warten { --bk-st-bg: #F6ECDB; --bk-st-fg: #8A5A0B; }
.badge.bk-status-geschlossen { --bk-st-bg: #D7E4C6; --bk-st-fg: #2C5410; }
.badge.bk-status-geloest { --bk-st-bg: #E7F1DC; --bk-st-fg: #3B6D11; }
[data-bs-theme="dark"] .badge.bk-status { --bk-st-bg: #272E36; --bk-st-fg: #9FB0BE; }
[data-bs-theme="dark"] .badge.bk-status-neu { --bk-st-bg: #3A2527; --bk-st-fg: #E99A9A; }
[data-bs-theme="dark"] .badge.bk-status-arbeit { --bk-st-bg: #1B2C3D; --bk-st-fg: #7FB4E8; }
[data-bs-theme="dark"] .badge.bk-status-klaerung { --bk-st-bg: #382A1B; --bk-st-fg: #E3A977; }
[data-bs-theme="dark"] .badge.bk-status-zugewiesen { --bk-st-bg: #332E1A; --bk-st-fg: #D9C173; }
[data-bs-theme="dark"] .badge.bk-status-warten { --bk-st-bg: #33291A; --bk-st-fg: #DBB079; }
[data-bs-theme="dark"] .badge.bk-status-geschlossen { --bk-st-bg: #243017; --bk-st-fg: #9FC97C; }
[data-bs-theme="dark"] .badge.bk-status-geloest { --bk-st-bg: #26331A; --bk-st-fg: #A3D17F; }
/* app ticket page: the ticket edge to edge on white at the top, below it on the page's own colour the history's
   entries and the own entries, each in a small white box */
body.app.app-ticket { background: #F4F7FB; }
/* the history on the darker page colour: grey texts darker, so they stay easy to read */
.app-ticket .bk-journal .text-secondary, .app-ticket .bk-changes th {
	color: var(--tblr-body-color) !important; opacity: .85; }
.app-ticket .bk-journal { color: var(--tblr-body-color); }
[data-bs-theme="dark"] body.app.app-ticket { background: #14181D; }
.app-ticket #ticket-view > .card { background: transparent; border: 0; box-shadow: none; }
.app-ticket #ticket-view > .card > .card-body { padding: 0; }
.app-ticket .bk-ticket-head { margin: -1rem -1rem 0; padding: 1rem; border: 0; border-radius: 0; box-shadow: none;
	background: var(--tblr-bg-surface);
	border-bottom: 1px solid color-mix(in srgb, var(--tblr-body-color) 28%, transparent); }
/* every entry of the history in its own small white box, like the own entries below */
.app-ticket .bk-journal { margin-bottom: .5rem; padding: .75rem 1rem; border: 1px solid var(--tblr-border-color);
	border-radius: var(--tblr-border-radius); background: var(--tblr-bg-surface); }
/* the headings of history and own entries as section labels, like the sidebar's headings: small, grey, capitals */
.app-ticket .bk-section-title { margin-bottom: 1rem !important; font-size: .75rem; font-weight: 600;
	text-transform: uppercase; letter-spacing: .05em; }
/* "Verlauf" on the page's grey right below the white ticket */
.app-ticket .bk-journals-title { margin: 0 !important; padding: 1.5rem 0 .75rem; }
.app-ticket h4 + .bk-journal { border-top: 1px solid var(--tblr-border-color); padding-top: .75rem; }
/* the facts' labels need little room: a narrow first column, the values get the rest */
.app-ticket .bk-ticket-facts > dt { flex: 0 0 auto; width: 6.5rem; }
.app-ticket .bk-ticket-facts > dd { flex: 0 0 auto; width: calc(100% - 6.5rem); min-width: 0; }
/* the same for the changes in the history */
.app-ticket .bk-changes th { min-width: 5rem; padding-right: .5rem; }
/* the own entries edge to edge on white below the boxed history, set off by a line above and below */
.app-ticket .bk-ticket-own { margin: .5rem -1rem 0; padding: 1rem; border: 0; border-radius: 0;
	border-top: 1px solid color-mix(in srgb, var(--tblr-body-color) 28%, transparent);
	border-bottom: 1px solid color-mix(in srgb, var(--tblr-body-color) 28%, transparent); background: var(--tblr-bg-surface); }
/* its entries on the light grey of the other boxes */
.app-ticket .bk-ticket-own .bk-ticket-entries .list-group-item { background: var(--tblr-bg-surface-secondary); }
.bk-ticket-own > h4:first-child { margin-top: 0 !important; }
/* app ticket page: "Nochmal buchen" on the right ("Im Tracker öffnen" is in the bar on top) */
.bk-ticket-actions .btn-list { justify-content: flex-end; }
.bk-ticket-head .bk-ticket-box { background: color-mix(in srgb, var(--tblr-body-color) 5%, var(--tblr-bg-surface)); }
/* in the app the ticket's head is white: its boxes on the light grey of the own entries, code in them white again */
.app-ticket .bk-ticket-head .bk-ticket-box { background: var(--tblr-bg-surface-secondary); }
.app-ticket .bk-ticket-head .bk-ticket-box.bk-ticket-md.markdown-body pre { background-color: var(--tblr-bg-surface) !important; }
.bk-ticket-box { padding: .75rem 1rem; background: var(--tblr-bg-surface-secondary); border: 1px solid var(--tblr-border-color); }
.bk-journal { padding: .75rem 0; border-top: 1px solid var(--tblr-border-color); }
h4 + .bk-journal { border-top: 0; padding-top: 0; }
/* the changes of a journal as in the Ticket Finder: label and new value in two aligned columns */
.bk-changes { border-collapse: collapse; font-size: .82rem; }
.bk-changes th { font-weight: 400; color: var(--tblr-secondary); white-space: nowrap; vertical-align: top;
	min-width: 6.5rem; padding: .2rem .75rem 0 0; }
.bk-changes td { padding: .2rem 0 0; overflow-wrap: anywhere; }
.bk-change-badge { display: inline-block; padding: 0 .55rem; border: 1px solid currentColor; border-radius: 999px;
	line-height: 1.5; }
.bk-change-text { line-height: 1.35; }
/* progress on a red → green scale in steps of 10 % (Ticket Finder), lighter in the dark theme */
.bk-progress-0 { color: #C0392B; } .bk-progress-1 { color: #D14B25; } .bk-progress-2 { color: #E06A1F; }
.bk-progress-3 { color: #E68A14; } .bk-progress-4 { color: #D9A400; } .bk-progress-5 { color: #B7A50E; }
.bk-progress-6 { color: #8FA014; } .bk-progress-7 { color: #6B991A; } .bk-progress-8 { color: #4F8B1C; }
.bk-progress-9 { color: #3F7D1A; } .bk-progress-10 { color: #3B6D11; }
[data-bs-theme="dark"] .bk-progress-0 { color: #E57368; } [data-bs-theme="dark"] .bk-progress-1 { color: #E9805F; }
[data-bs-theme="dark"] .bk-progress-2 { color: #EC9A5C; } [data-bs-theme="dark"] .bk-progress-3 { color: #EDAE55; }
[data-bs-theme="dark"] .bk-progress-4 { color: #DFC04E; } [data-bs-theme="dark"] .bk-progress-5 { color: #C6C155; }
[data-bs-theme="dark"] .bk-progress-6 { color: #A8C25C; } [data-bs-theme="dark"] .bk-progress-7 { color: #8FC161; }
[data-bs-theme="dark"] .bk-progress-8 { color: #7CBF63; } [data-bs-theme="dark"] .bk-progress-9 { color: #72BC62; }
[data-bs-theme="dark"] .bk-progress-10 { color: #6FB85C; }
/* the ticket's checklist: sections bold, items with a box, done items muted and struck through */
.bk-check-section { font-weight: 700; margin-top: 1rem; margin-bottom: .25rem; }
.bk-check-section:first-child { margin-top: 0; }
.bk-check-item { display: flex; align-items: flex-start; gap: .5rem; padding: .15rem 0; }
.bk-check-item .ti { font-size: 1.1rem; line-height: 1.25; color: var(--tblr-secondary); flex: none; }
.bk-check-item.is-done { color: var(--tblr-secondary); }
.bk-check-item.is-done > span { text-decoration: line-through; }
.bk-check-item.is-done .ti { color: var(--tblr-green); }
.bk-picked-main { min-width: 0; flex: 1; line-height: 1.35; }
.bk-picked .btn-close { width: .75rem; height: .75rem; background-size: .75rem; }
.bk-step-btn { border: 0; background: none; padding: 0; line-height: 1; flex: none;
               color: var(--tblr-secondary); opacity: .7; }
.bk-step-btn .ti { font-size: 1.9rem; }
.bk-step-btn:hover:not(:disabled) { color: var(--tblr-primary); opacity: 1; }
.bk-step-btn:disabled { opacity: .25; }
/* date and effort share a row, also on phones: the effort field gives up side padding to stay between its buttons */
.bk-dur { min-width: 3.5rem; padding-left: .25rem; padding-right: .25rem; }
textarea.bk-autogrow { resize: none; overflow: hidden; min-height: 2.5rem; }
.bk-hist-box { margin-top: .5rem; border: 1px solid #D5DADF; border-radius: var(--tblr-border-radius); background: #F7F8FA;
	box-shadow: 0 2px 6px rgba(0, 0, 0, .06); overflow: hidden; }
.bk-hist-head { padding: .45rem .75rem; font-size: .8rem; font-weight: 600; color: #343A40; background: #EEF0F3;
	border-bottom: 1px solid #D5DADF; }
.bk-hist { max-height: 13rem; overflow-y: auto; }
.bk-hist .list-group-item { background: transparent; border-color: #E3E6EA; border-left: 0; border-right: 0; cursor: pointer; }
.bk-hist .list-group-item:first-child { border-top: 0; }
.bk-hist .list-group-item:last-child { border-bottom: 0; }
.bk-hist .list-group-item:hover { background: color-mix(in srgb, var(--tblr-primary) 12%, var(--tblr-bg-surface)); }
.bk-hist-when { font-weight: 600; color: var(--tblr-body-color); }
.bk-hist-txt { display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
[data-bs-theme="dark"] .bk-hist-box { border-color: var(--tblr-border-color); background: var(--tblr-bg-surface-secondary); }
[data-bs-theme="dark"] .bk-hist-head { color: var(--tblr-body-color); background: var(--tblr-bg-surface-tertiary);
	border-bottom-color: var(--tblr-border-color); }
[data-bs-theme="dark"] .bk-hist .list-group-item { border-color: var(--tblr-border-color); }
/* the unbooked hint is an alert at the end of the modal body, gone while nothing is unbooked */
#bookModal .bk-gap-hint:not(:has(span)) { display: none; }
/* delete sits on the left of the footer, cancel and save on the right */
#bookModal .modal-footer [data-booking-delete] { margin-right: auto; }
/* on phones the buttons share one row: delete on the left, cancel and save on the right, with tighter padding so
   the three fit side by side */
@media (max-width: 575.98px) {
	#bookModal .modal-footer { flex-wrap: wrap; padding-left: .75rem; padding-right: .75rem; }
	#bookModal .modal-footer > * { margin: .25rem; }
	#bookModal .modal-footer .btn-ghost-secondary { margin-left: auto; }
	#bookModal .modal-footer .btn { padding-left: .65rem; padding-right: .65rem; }
}

/* Opened from the installed app, the website runs under iOS's translucent status bar (viewport-fit=cover): it keeps
   that strip free, in the colour of its header. In a browser the inset is 0. */
body:not(.app) { padding-top: env(safe-area-inset-top); background-image: linear-gradient(var(--tblr-bg-surface), var(--tblr-bg-surface));
  background-size: 100% env(safe-area-inset-top); background-repeat: no-repeat; }
/* entries that only make sense inside the installed app, such as the way back to it from the website */
.s-in-app { display: none !important; }
@media (display-mode: standalone) { .s-in-app { display: block !important; } }

/* phone app */
/* the Ticket Finder's light blue-grey page background */
body.app { background: #F1F5FA; }
[data-bs-theme="dark"] body.app { background: #14181D; }
/* buttons in the app are round like the Ticket Finder's: pills, icon buttons circles */
.app .btn { border-radius: 999px; }
.app .btn-icon { border-radius: 50%; }
/* Primary is the Ticket Finder's action blue, the end colour of the app bar. Tabler derives the
   darker, lighter and link shades on :root, so they are restated here for the new base colour. */
body.app {
	--tblr-primary: #2F6EA8;
	--tblr-primary-rgb: 47, 110, 168;
	--tblr-primary-darken: oklch(from var(--tblr-primary) calc(l - 0.06) c h);
	--tblr-primary-lt: color-mix(in oklab, var(--tblr-primary) 10%, transparent);
	--tblr-primary-lt-rgb: 231, 240, 250;
	--tblr-primary-bg-subtle: light-dark(color-mix(in oklab, var(--tblr-white) 80%, var(--tblr-primary)), color-mix(in oklab, var(--tblr-black) 80%, var(--tblr-primary)));
	--tblr-primary-border-subtle: light-dark(color-mix(in oklab, var(--tblr-white) 60%, var(--tblr-primary)), color-mix(in oklab, var(--tblr-black) 40%, var(--tblr-primary)));
	--tblr-primary-text-emphasis: light-dark(color-mix(in oklab, var(--tblr-black) 60%, var(--tblr-primary)), color-mix(in oklab, var(--tblr-white) 40%, var(--tblr-primary)));
	--tblr-link-color: light-dark(var(--tblr-primary), color-mix(in oklab, var(--tblr-white) 40%, var(--tblr-primary)));
	--tblr-link-color-rgb: 47, 110, 168;
	--tblr-link-hover-color: light-dark(color-mix(in oklab, var(--tblr-black) 20%, var(--tblr-link-color)), color-mix(in oklab, var(--tblr-white) 20%, var(--tblr-link-color)));
}
/* App pages read like a native app: everything in rem (text, paddings, controls) about an eighth larger than on
   the website, so body text is near 16px instead of Tabler's 14px; buttons are at least the 44px touch target. */
html:has(body.app) { font-size: 18px; }
/* The page itself never scrolls: the column is exactly as high as the screen, with the bar on top, the stamping bar
   at the bottom and only the content between them scrolling (.app-scroll). iOS moves fixed elements when it bounces
   the page past an end, and in an app started from the home screen it anchors them 62px short of the bottom. */
html:has(body.app) { height: 100%; overflow: hidden; overscroll-behavior: none; background-color: #F1F5FA; }
html[data-bs-theme="dark"]:has(body.app) { background-color: #14181D; }
body.app { height: auto; overscroll-behavior: none; }
.app .btn:not(.btn-sm) { min-height: 44px; }
.app .btn-icon:not(.btn-sm) { min-width: 44px; }
.app .nav-segmented .nav-link { min-height: 40px; }
.app .bk-entry-edit { width: 40px; height: 40px; }
.app .btn.bk-day-add { width: 2.25rem !important; height: 2.25rem; min-height: 0; }
.app-column { position: relative; max-width: 32rem; margin: 0 auto; height: 100vh; height: 100dvh; display: flex; flex-direction: column; }
/* Started from the home screen iOS takes the status bar off 100dvh; 100vh is the full screen there. */
@media (display-mode: standalone) { .app-column { height: 100vh; } }
/* The content scrolls and bounces on its own, always: it is at least a pixel higher than its box, so even a short
   page can be pulled down to reload (app.js). */
.app-scroll { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior-y: contain; }
.app-scroll > main { min-height: calc(100% + 1px); }
/* A tap on the status bar takes iOS to the top of the page, not of .app-scroll: there the page is a pixel higher than
   the screen and kept a pixel down, so the tap has somewhere to go (app.js). */
html.app-status-tap:has(body.app) { overflow-y: auto; }
html.app-status-tap body.app { padding-bottom: 1px; }
/* The bar has the same height on every page (room for the start page's avatar), so the pull-to-reload hint can sit
   just below it; it stays above that hint. */
:root { --app-bar-h: calc(3.7rem + env(safe-area-inset-top)); }
.app-bar { position: relative; flex: none; height: var(--app-bar-h); box-sizing: border-box; z-index: 1020; background: #4286C3; color: #fff; padding: calc(.4rem + env(safe-area-inset-top)) 1rem .4rem; display: flex; align-items: center; gap: .75rem; }
.app-bar-title { font-size: 1rem; font-weight: 600; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.app-bar-logo { width: 2.5rem; height: 2.5rem; flex: none; border-radius: 22%;
	box-shadow: 0 0 0 1.5px rgba(255, 255, 255, .55), 0 2px 6px rgba(0, 0, 0, .18); }
.app-bar-btn { width: 2.5rem; height: 2.5rem; flex: none; display: inline-flex; align-items: center; justify-content: center; border: 0; border-radius: 50%; background: rgba(255,255,255,.15); color: #fff; text-decoration: none; }
.app-bar-btn:hover { color: #fff; }
.app-bar-btn .ti { font-size: 1.4rem; }
/* the user menu is the round avatar itself, without the square button behind it */
.app-bar-avatar { background: none; border-radius: 50%; }
.app-bar-avatar .avatar { --tblr-avatar-size: 2.5rem; box-shadow: 0 0 0 2px rgba(255,255,255,.6); }
.app-tiles { flex: 1; padding: 1rem; display: flex; flex-direction: column; gap: .75rem; }
.app-tile { display: flex; align-items: center; gap: .9rem; padding: .9rem 1rem; background: var(--tblr-bg-surface); border-radius: .9rem; box-shadow: 0 1px 3px rgba(0,0,0,.06); color: inherit; text-decoration: none; }
.app-tile { -webkit-tap-highlight-color: transparent; transition: background-color .12s ease, transform .12s ease; }
.app-tile:hover, .app-tile:focus, .app-tile:active { color: inherit; text-decoration: none; }
/* the whole card reacts to the touch instead of an underlined title */
/* Hover tint only with a real pointer: a phone keeps :hover on the last tapped element, so the tile stayed tinted
   after coming back to the start page. A tap still answers through :active. */
@media (hover: hover) {
	.app-tile:hover { background: color-mix(in srgb, var(--tblr-primary) 5%, var(--tblr-bg-surface)); }
}
/* the same for the ticket rows of the app's lists (Tabler tints .list-group-item-action on hover) */
@media (hover: none) {
	.app .list-group-item-action:hover:not(:active) { background-color: var(--tblr-list-group-bg, var(--tblr-bg-surface)); }
}
.app-tile:active { background: color-mix(in srgb, var(--tblr-primary) 14%, var(--tblr-bg-surface)); transform: scale(.99); }
/* no underlined links anywhere in the app; rows and cards show their own pressed state */
.app a:hover, .app a:focus, .app a:active { text-decoration: none; }
.app .list-group-item-action { -webkit-tap-highlight-color: transparent; }
.app-tile-ic { width: 3rem; height: 3rem; border-radius: .8rem; display: flex; align-items: center; justify-content: center; color: #fff; flex: none; }
.app-tile-ic .ti { font-size: 1.6rem; }
.app-tile-t { display: block; font-weight: 600; font-size: 1rem; }
.app-tile-s { display: block; font-size: .82rem; color: var(--tblr-secondary); line-height: 1.3; }
.app-tile-chev { margin-left: auto; color: var(--tblr-secondary); }
.app-g-blue { background: linear-gradient(135deg, #4F97D6, #2F6EA8); }
.app-g-violet { background: linear-gradient(135deg, #8E7CD6, #5B4BA8); }
.app-g-slate { background: linear-gradient(135deg, #7D8B99, #4C5A68); }
.app-g-teal { background: linear-gradient(135deg, #3FB3A8, #23807A); }
.app-support .app-main, .app-search .app-main { flex: 1; padding: 1rem 1rem calc(1rem + env(safe-area-inset-bottom)); }
/* how long a support ticket has been quiet, as in the Ticket Finder: a pill whose icon part is filled */
.bk-quiet { --bk-q: var(--tblr-secondary); display: inline-flex; align-items: stretch; flex: none; overflow: hidden;
	border: 1px solid var(--bk-q); border-radius: 999px; color: var(--bk-q); font-size: .75rem; font-weight: 600;
	line-height: 1.5; }
.bk-quiet > .ti { display: flex; align-items: center; padding: 0 .3rem 0 .4rem; background: var(--bk-q); color: #fff;
	font-size: .8rem; }
.bk-quiet > span { padding: 0 .55rem 0 .35rem; }
.bk-quiet-14 { --bk-q: #B8860B; }
.bk-quiet-30 { --bk-q: #C97400; }
.bk-quiet-60 { --bk-q: #D62828; }
.app-tickets .app-main { flex: 1; padding: 1rem 1rem calc(1rem + env(safe-area-inset-bottom)); }
.bk-ticket-row { padding-top: .8rem; padding-bottom: .8rem; }
.bk-ticket-row .bk-title { font-weight: 600; }
.app-empty { color: var(--tblr-secondary); text-align: center; margin: 2rem 0; }

/* phone app: stamping bar, below the scrolling tiles */
.app-stamp { flex: none; background: var(--tblr-bg-surface); border-top: 1px solid var(--tblr-border-color); padding: .5rem 1rem max(.5rem, env(safe-area-inset-bottom)); box-shadow: 0 -2px 10px rgba(0,0,0,.05); }
.app-stamp-status { display: flex; align-items: center; justify-content: center; gap: .6rem; margin-bottom: .45rem; }
.app-stamp-dot { width: .7rem; height: .7rem; border-radius: 50%; flex: none; background: #C9A13A; box-shadow: 0 0 0 4px rgba(201,161,58,.22); }
.app-stamp-dot.is-present { background: #4F7A3D; box-shadow: 0 0 0 4px rgba(79,122,61,.22); }
.app-stamp-line { display: flex; align-items: center; gap: .6rem; min-width: 0; }
.app-stamp-l1 { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.app-stamp-l2 { flex: none; padding-left: .6rem; border-left: 1px solid var(--tblr-border-color); line-height: 1;
	font-size: .8rem; font-weight: 500; color: var(--tblr-secondary); white-space: nowrap; }
.app-slider { --p: 0; --c: #4F7A3D; --track: #ECEEF1; position: relative; height: 3.75rem; border-radius: 999px; overflow: hidden; user-select: none; -webkit-user-select: none;
	background: color-mix(in srgb, var(--c) calc(var(--p) * 100%), var(--track)); transition: background .22s ease-out; }
.app-slider.is-leave { --c: #D1382A; }
.app-slider.is-dragging { transition: none; }
[data-bs-theme=dark] .app-slider { --track: #2A323B; }
.app-slider-label { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 1.03rem; font-weight: 700; color: var(--tblr-body-color); opacity: clamp(0, calc(1 - var(--p) * 1.4), 1); pointer-events: none; }
.app-slider-knob { position: absolute; top: .375rem; left: calc(.375rem + var(--p) * (100% - 3.75rem)); width: 3rem; height: 3rem; padding: 0; border: 0; border-radius: 50%; background: var(--c); color: #fff;
	display: flex; align-items: center; justify-content: center; font-size: 1.25rem; box-shadow: 0 2px 8px color-mix(in srgb, var(--c) 45%, transparent); touch-action: none; cursor: grab; transition: left .22s ease-out; }
.app-slider.is-dragging .app-slider-knob { transition: none; cursor: grabbing; }
.app-slider.is-busy, .app-slider.is-done { pointer-events: none; }
.app-slider-spinner { width: 1.1rem; height: 1.1rem; border: 2px solid rgba(255,255,255,.4); border-top-color: #fff; border-radius: 50%; animation: app-spin .7s linear infinite; }
@keyframes app-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
/* pull to reload in the app started from the home screen (app.js): a round arrow that comes out from under the bar
   into the gap the pull opens and turns with the finger; once letting go reloads it turns blue and spins, until the
   reloaded page replaces it */
.app-ptr { --ptr: 0; position: fixed; top: calc(var(--app-bar-h) + .25rem); left: 50%; z-index: 1010;
	width: 2.5rem; height: 2.5rem; border-radius: 50%; display: flex; align-items: center; justify-content: center;
	background: var(--tblr-bg-surface); color: var(--tblr-secondary); box-shadow: 0 2px 8px rgba(0, 0, 0, .15);
	pointer-events: none; opacity: min(var(--ptr), 1);
	transform: translate(-50%, calc(var(--ptr) * 3rem - 3rem)); }
.app-ptr .ti { display: inline-block; font-size: 1.25rem; transform: rotate(calc(var(--ptr) * -300deg)); }
.app-ptr.is-armed { color: var(--tblr-primary); }
/* anticlockwise, like the turn while pulling */
.app-ptr.is-armed .ti, .app-ptr.is-loading .ti { animation: app-spin 1.6s linear infinite reverse; }
/* while it reloads, the content keeps the gap the indicator turns in instead of sliding under it */
.app-scroll.is-reloading > main { margin-top: 2.75rem; }

/* phone app: the booking page. One column at every width, the floating button always shown (it replaces the
   website's page button) and kept inside the column, above the bottom safe area. */
.app-booking .app-main { flex: 1; padding: 1rem 1rem calc(5.5rem + env(safe-area-inset-bottom)); }
.app-ticket .app-main { flex: 1; padding: 1rem 1rem calc(1rem + env(safe-area-inset-bottom)); }
.app-booking .col-lg-7, .app-booking .col-lg-5 { flex: 0 0 100%; max-width: 100%; }
/* placed on the page, which is exactly as high as the screen, not on the screen: iOS misplaces fixed elements in the
   app started from the home screen; 100% is the page's width, the column sits in its middle */
.app-booking .bk-fab { position: absolute; display: inline-flex !important; align-items: center; justify-content: center;
	right: max(1rem, calc((100% - 32rem) / 2 + 1rem)); }
.app-booking [data-booking-open] { display: none !important; }

/* phone app: the clocks on the booking page (clocks.js). Calm and small next to the real work: the time in a
   seven-segment face no larger than the text around it, small square buttons, the stop button filled grey, no
   running dot. A paused time is grey, one running over 10 hours red. Self-hosted DSEG7-Classic (OFL, see the font's
   LICENSE beside it). */
@font-face { font-family: 'DSEG7-Classic'; font-style: normal; font-weight: 400; font-display: swap;
	src: url('/fonts/dseg7/DSEG7Classic-Regular.woff2') format('woff2'); }
/* the time as a small digital display: dark panel, light digits (mockup-desktop-v16, without its green); paused
   light (below), overlong red */
.bk-clock-time { font-family: 'DSEG7-Classic', ui-monospace, monospace; font-size: .95em; font-weight: 400;
	letter-spacing: .06em; white-space: nowrap; color: #EEF3F8; background: #1E2A38; padding: .25rem .5rem;
	border-radius: 5px; display: inline-block; line-height: 1.2; }
/* a paused clock's display lighter, as switched off */
.bk-clock[data-state="paused"] .bk-clock-time { color: #5B6878; background: #DCE3EB; }
.bk-clock-overlong .bk-clock-time { color: #FF8A80; }
/* the stop dialog: what the clock is for, then its two figures side by side in a quiet box */
.bk-stop-what { margin-bottom: 1rem; font-weight: 600; }
/* the ticket's number right after the title, on its last line */
.bk-stop-what > .bk-pill { margin-left: .4rem; vertical-align: .1em; }
.bk-stop-subject { margin-top: .25rem; font-weight: 400; font-size: .9rem; }
.bk-stop-figures { display: grid; grid-template-columns: 1fr 1fr; gap: .75rem; }
.bk-stop-figure { display: flex; flex-direction: column; align-items: flex-start; gap: .4rem; padding: .75rem 1rem;
	border-radius: 8px; background: var(--tblr-bg-surface-secondary); }
.bk-stop-label { font-size: .72rem; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; color: var(--tblr-secondary); }
.bk-stop-figure .bk-clock-time { font-size: 1.35rem; }
.bk-stop-rounded { font-size: 1.6rem; line-height: 1.2; }
.bk-clock-btn.btn { width: 1.45rem; height: 1.45rem; min-width: 0; min-height: 0; padding: 0; font-size: .8rem;
	border-radius: 4px; color: var(--tblr-secondary); }
.app .bk-clock-btn.btn { border-radius: 4px; }
.bk-clock-btn.btn .ti { font-size: .85rem; margin: 0; }
.bk-clock-btn.btn.btn-secondary { color: #fff; }
.bk-clock .btn-list { --tblr-list-gap: .25rem; gap: .25rem; }
/* the title line: the note (or the ticket's subject) and the ticket's pill right after it, wrapping only when the
   line is full */
.bk-clock-title { display: flex; flex-wrap: wrap; align-items: baseline; gap: .15rem .4rem; margin-top: .4rem; }
.bk-clock-title > .bk-pill { flex: none; }
.bk-clock-note { display: block; min-width: 0; padding: 0; border: 0; background: none; color: inherit;
	font-weight: 600; text-align: left; line-height: 1.35; cursor: pointer; }
.bk-clock-note:hover { color: var(--tblr-primary); }
.bk-clock-note:focus-visible { outline: 2px solid var(--tblr-primary); outline-offset: 2px; border-radius: 2px; }
/* shown only while in use: at least one clock or collected time */
.bk-clocks { margin-bottom: 1rem; background: var(--tblr-bg-surface); border: 1px solid var(--tblr-border-color);
	border-radius: var(--tblr-border-radius); overflow: hidden; }
.bk-clocks:has(#booking-clocks[data-clock-count="0"]) { display: none; }
.bk-clocks .bk-clock { padding: .5rem .85rem; }
/* the clock start button bottom left, the + bottom right (phone: 3.5rem, action blue, above the safe area) */
.app-booking .bk-fab-clock { right: auto; left: max(1rem, calc((100% - 32rem) / 2 + 1rem)); }
.app-booking .bk-fab { width: 3.5rem; height: 3.5rem; background: var(--tblr-primary); border-color: var(--tblr-primary);
	color: #fff; bottom: calc(1rem + env(safe-area-inset-bottom)); }
/* the collected <details>: own marker (icons) at every width, chevron turns when open */
.bk-clock-summary { cursor: pointer; list-style: none; }
.bk-clock-summary::-webkit-details-marker { display: none; }
.bk-clock-collected[open] > .bk-clock-summary .bk-clock-chevron { transform: rotate(180deg); }
.bk-clock-collected .bk-clock-summary .bk-clock-chevron { transition: transform .15s; }
/* the collected row's "Buchen" as a plain small button at every width */
.bk-clock-collected .btn-primary.btn-sm { border-radius: 4px; }
.bk-clock-collected .btn-list .btn-primary { background: var(--tblr-bg-surface); color: var(--tblr-body-color);
	border: 1px solid var(--tblr-border-color); }
/* phone (below 1100px, or a window lower than 500px): the clocks as a narrow strip above the day, one row per clock,
   the collected times folded into a <details> line "N collected · H:MM". A wide layout overrides this in its own
   min-width block. */
@media (max-width: 1099.98px), (max-height: 499.98px) {
  .app-booking .bk-clocks { margin: 0 -1rem 1rem; border-left: 0; border-right: 0; border-radius: 0; }
  .app-booking .bk-clocks .list-group-item { border-left: 0; border-right: 0; }
  .bk-clock-summary { border-top: 1px solid var(--tblr-border-color); }
  .bk-clock-collected > .list-group { border-top: 1px solid var(--tblr-border-color); }
  /* stop dialog as bottom sheet */
  #clockModal .modal-dialog:has(> [data-bk-sheet]) { position: fixed; left: 0; right: 0; bottom: 0; margin: 0;
	max-width: none; min-height: 0; display: block; }
  [data-bk-sheet].modal-content { border: 0; border-radius: 1rem 1rem 0 0;
	padding-bottom: env(safe-area-inset-bottom); box-shadow: 0 -6px 24px rgba(0, 0, 0, .18); }
  .bk-sheet-grip { width: 2.4rem; height: .25rem; border-radius: 999px; background: #D0D5DB; margin: .6rem auto 0; }
  [data-bk-sheet] .modal-header { border-bottom: 0; padding-bottom: 0; }
  [data-bk-sheet] .modal-footer { border-top: 0; flex-direction: column; align-items: stretch; flex-wrap: nowrap; gap: .5rem; }
  [data-bk-sheet] .modal-footer .btn { width: 100%; min-height: 2.6rem; }
  [data-bk-sheet] .modal-footer > * { margin: 0; }
  [data-bk-sheet] .modal-footer form { display: block; }
  [data-bk-sheet] .bk-sheet-book { order: 1; }
  [data-bk-sheet] .bk-sheet-collect { order: 2; }
  [data-bk-sheet] .bk-sheet-collect .btn { background: var(--tblr-bg-surface); color: var(--tblr-body-color);
	border: 1px solid var(--tblr-border-color); }
  [data-bk-sheet] .bk-sheet-keep { order: 3; }
  [data-bk-sheet] .modal-footer > [data-clock-discard] { order: 4; }
}
/* The rail layouts of the app (from 768px; below it everything above stays the phone's, its bar included): the
   navigation rail on the left (5.25rem) and no blue bar (the rail navigates, each page has its own head, and the
   installed app's window brings its own title bar), the column without its phone width. On the booking page the
   columns day | distribution and "Zuletzt gebucht" (from 768px, the clocks as the phone's strip on top of the day),
   from 1100px with the clock column (18rem, only while in use) before them. Only in a window at least 500px high: a
   phone in landscape keeps the phone layout. The parts only these layouts show are hidden elsewhere. */
.app-rail, .app-pane, .app-page-head, .bk-col-label, .bk-app-dist, .bk-nav-sum, .bk-nav-mode, .app-col-handle, .bk-fabs-clocks { display: none; }
@media (max-width: 767.98px), (max-height: 499.98px) {
  /* the hidden distribution card must not give "Zuletzt gebucht" the side column's separator line */
  .app-booking .bk-side .bk-app-dist + .card { margin-top: 0; padding-top: 0; border-top: 0; }
  /* the round buttons a little closer to the bottom, still above the home indicator */
  .app-booking .bk-fab { bottom: calc(.4rem + env(safe-area-inset-bottom)); }
}
@media (min-width: 768px) and (min-height: 500px) {
  /* no bar on the pages with the rail; only an iPad's status bar (app started from the home screen) keeps its room */
  :root:has(body.app > .app-rail) { --app-bar-h: env(safe-area-inset-top, 0px); }
  body.app:has(> .app-rail) .app-bar { display: none; }
  body.app:has(> .app-rail) .app-column { padding-top: var(--app-bar-h); }
  /* a desktop needs no touch-sized text: the website's root size */
  html:has(body.app) { font-size: 16px; }
  body.app:has(> .app-rail) .app-column { max-width: none; }
  /* the rail and the content beside it keep clear of a notch at the side (a device turned on its side) */
  body.app:has(> .app-rail) .app-scroll { margin-left: calc(var(--app-rail-w, 5.25rem) + env(safe-area-inset-left)); }
  body.app:not(.app-booking):has(> .app-rail) .app-scroll { padding-right: env(safe-area-inset-right); }
  /* the rail */
  .app-rail { position: fixed; z-index: 1015; top: var(--app-bar-h); left: 0; bottom: 0;
	width: calc(var(--app-rail-w, 5.25rem) + env(safe-area-inset-left)); display: flex;
	flex-direction: column; padding: .5rem 0 0 env(safe-area-inset-left); overflow-y: auto; background: var(--tblr-bg-surface);
	border-right: 1px solid color-mix(in srgb, var(--tblr-body-color) 18%, transparent); }
  .app-rail-item { position: relative; display: flex; flex-direction: column; align-items: center; gap: .15rem;
	padding: .5rem 0; color: var(--tblr-secondary); font-size: .7rem; text-decoration: none; }
  .app-rail-item .ti { width: 2.6rem; height: 1.9rem; display: flex; align-items: center; justify-content: center;
	border-radius: 999px; font-size: 1.35rem; }
  .app-rail-item:hover { color: var(--tblr-body-color); }
  .app-rail-item.active { color: #4286C3; font-weight: 600; }
  .app-rail-item.active .ti { background: color-mix(in srgb, #4286C3 12%, transparent); }
  .app-rail-badge { position: absolute; top: .2rem; right: .45rem; padding: 0 .3rem; border-radius: 999px;
	background: #E55039; color: #fff; font-size: .62rem; font-weight: 700; line-height: 1.45; }
  .app-rail-bottom { margin-top: auto; display: flex; flex-direction: column; align-items: center; gap: .6rem;
	padding-bottom: .75rem; }
  /* stamping: status dot, since, today's time, a small button; a first click arms it (app.js) */
  .app-rail-stamp { width: 100%; display: flex; flex-direction: column; align-items: center; gap: .2rem;
	padding: .85rem .4rem 1rem; border-top: 1px solid var(--tblr-border-color); border-bottom: 1px solid var(--tblr-border-color); }
  .app-rail-stamp .app-stamp-dot { width: .55rem; height: .55rem; margin-bottom: .4rem; }
  .app-rail-since { font-size: .9rem; font-weight: 600; }
  .app-rail-worked { margin-bottom: .7rem; font-size: .74rem; color: var(--tblr-secondary); }
  .app-rail-stamp form { margin: 0; }
  .app .app-rail-stamp .app-rail-stamp-btn.btn { --c: #D1382A; width: 4.25rem; min-width: 0; min-height: 0;
	padding: .4rem .2rem .35rem; display: flex; flex-direction: column; align-items: center; gap: .1rem;
	border: 1px solid color-mix(in srgb, var(--c) 35%, transparent); border-radius: 8px; background: var(--tblr-bg-surface);
	color: var(--c); font-size: .72rem; font-weight: 600; line-height: 1.2; white-space: nowrap; }
  .app .app-rail-stamp .app-rail-stamp-btn.btn.is-come { --c: #4F7A3D; }
  .app .app-rail-stamp .app-rail-stamp-btn.btn .ti { margin: 0; font-size: 1.15rem; }
  /* hover only tints; the solid fill is the armed state's ("Wirklich?") */
  .app .app-rail-stamp .app-rail-stamp-btn.btn:hover { background: color-mix(in srgb, var(--c) 12%, var(--tblr-bg-surface));
	border-color: color-mix(in srgb, var(--c) 50%, transparent); color: var(--c); }
  .app .app-rail-stamp .app-rail-stamp-btn.btn.is-armed,
  .app .app-rail-stamp .app-rail-stamp-btn.btn.is-armed:hover { background: var(--c); border-color: var(--c); color: #fff; }
  .app .app-rail-stamp .app-rail-stamp-btn.btn.is-armed { box-shadow: 0 0 0 3px color-mix(in srgb, var(--c) 25%, transparent); }
  .app-rail-me .app-bar-avatar { width: 2.2rem; height: 2.2rem; }
  .app-rail-me .app-bar-avatar .avatar { --tblr-avatar-size: 2.2rem; box-shadow: none; }
  /* the other app pages: their content in a readable width beside the rail */
  body.app:not(.app-booking) .app-scroll > main { width: 100%; max-width: 52rem; margin-inline: auto; }
  /* the page's own head instead of the bar: the way back (where the page has one), the title, the page's controls */
  body.app:has(> .app-rail) .app-page-head { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem .75rem;
	margin-bottom: 1rem; }
  .app-page-title { flex: 1 1 auto; min-width: 0; margin: 0; font-size: 1.25rem; font-weight: 700; line-height: 1.3;
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .app .app-page-head .btn-icon { flex: none; }
  .app-page-head .btn .ti { margin-right: .35rem; }
  /* its icon buttons (back, order) round as the pane's, their icons as large */
  .app .app-page-head .btn-icon { width: 2.5rem; height: 2.5rem; min-width: 0; min-height: 0; padding: 0; border-radius: 50%; }
  .app-page-head .btn-icon .ti { margin: 0; font-size: 1.3rem; }
  /* the ticket page: the head is the top of the ticket's white head, back arrow and "Im Tracker öffnen" in it */
  .app-ticket .app-page-head { margin: -1rem -1rem 0; padding: .75rem 1rem .25rem; background: var(--tblr-bg-surface); }
  .app-ticket .app-page-head + #ticket-view .bk-ticket-head { margin-top: 0; padding-top: .5rem; }
  /* the distribution page: on white like the week below it */
  .app-distribution .app-page-head { margin: 0; padding: 1rem 1rem 0; background: var(--tblr-bg-surface); }

  /* the booking page: the hints on top, then day | handle | side, as high as the screen, each column scrolling on its
     own; the side column takes the width its handle gives it (--app-col-side, app.js), the day column the rest */
  .app-booking .app-scroll:has(> main > .row) { overflow: hidden; }
  .app-booking .app-main:has(> .row) { --app-col-clocks: 18rem; --app-col-side: 24rem; display: grid; height: 100%;
	min-height: 0; padding: 0; grid-template-rows: auto minmax(0, 1fr);
	grid-template-columns: [day] minmax(0, 1fr) [h-side] 6px [side] var(--app-col-side); }
  .app-booking .app-main > .bk-hints { grid-column: 1 / -1; grid-row: 1; }
  .app-booking .bk-hints > .alert { margin: 1rem 1.25rem 0; }
  .app-booking .app-main > .row { display: contents; }
  .app-booking .app-main > .row > * { margin: 0; }
  .app-booking .app-main > .row > .col-lg-7 { grid-column: day; grid-row: 2; min-width: 0; max-width: none; width: auto;
	display: flex; flex-direction: column; padding: 0 1.25rem; overflow-y: auto; container-type: inline-size; }
  .app-booking .app-main > .row > .bk-side { grid-column: side; grid-row: 2; width: auto; max-width: none;
	padding: 1.25rem calc(1rem + env(safe-area-inset-right)) 2rem 1rem; overflow-y: auto; }
  /* the handles: a fine line between the columns, stronger on hover, focus and while dragging */
  .app-col-handle[data-app-col-resize="clocks"] { grid-column: h-clocks; grid-row: 2; }
  .app-col-handle[data-app-col-resize="side"] { grid-column: h-side; grid-row: 2; }
  .app-col-handle { display: block; position: relative; cursor: col-resize; touch-action: none; outline: none; }
  .app-col-handle::after { content: ""; position: absolute; top: 0; bottom: 0; left: calc(50% - .5px); width: 1px;
	background: color-mix(in srgb, var(--tblr-body-color) 14%, transparent); transition: background-color .12s, width .12s, left .12s; }
  .app-col-handle:hover::after, .app-col-handle:focus-visible::after, .app-col-handle.is-dragging::after {
	left: calc(50% - 1.5px); width: 3px; background: color-mix(in srgb, #4286C3 70%, transparent); }
  html.app-col-resizing, html.app-col-resizing * { cursor: col-resize !important; user-select: none; }
  /* the day column's paging line stays on top while the day scrolls */
  .app-booking [data-app-col-rest] .bk-nav-card { position: sticky; top: 0; z-index: 4; padding-top: 1rem; margin-bottom: .5rem;
	background: #F1F5FA; }
  [data-bs-theme="dark"] .app-booking [data-app-col-rest] .bk-nav-card { background: #14181D; }
  /* the round buttons, 2.9rem, at the bottom of the day column while it scrolls: the clock start left of the + */
  .app-booking .bk-fabs { position: sticky; bottom: 0; z-index: 4; display: flex; justify-content: flex-end; gap: .75rem;
	margin-top: auto; padding: 1rem 0 calc(1.25rem + env(safe-area-inset-bottom)); pointer-events: none; }
  .app-booking .bk-fabs .bk-fab { position: static; width: 2.9rem; height: 2.9rem; pointer-events: auto;
	box-shadow: 0 6px 16px rgba(20, 60, 120, .3); }
  .app-booking .bk-fabs .bk-fab .ti { font-size: 1.4rem; }
  /* the clock start on the left, the + on the right, as on the phone */
  .app-booking [data-app-col-rest] .bk-fabs .bk-fab-clock { margin-right: auto; }
  /* a decider's hidden choice of a person: a double tap on the day column's date, the bar's title being gone (app.js) */
  body[data-app-person] [data-range-label] { user-select: none; -webkit-user-select: none; touch-action: manipulation; }
  /* "Verteilung" leads to its page with the earlier weeks: a quiet link, the heading's look with a chevron */
  .app-booking .bk-app-dist-link { display: inline-flex; align-items: center; gap: .15rem; color: inherit; text-decoration: none; }
  .app-booking .bk-app-dist-link:hover { color: var(--tblr-primary); }
  .app-booking .bk-app-dist-link .ti { font-size: .85rem; opacity: .7; }
  /* the clock column's own clock start only where that column exists (from 1100px) */
  .app-booking .bk-clocks .bk-fabs-clocks { display: none; }
  /* the day column's line: paging, the date, what is booked (and running), week/day on the right; the ring is the
     right column's distribution here */
  .app-booking .bk-nav-head-app .bk-donut-jump { display: none; }
  .app-booking .bk-nav-head-app .bk-nav { gap: .4rem !important; }
  .app-booking .bk-nav-label { font-size: 1.1rem; }
  .bk-nav-sum { display: inline; min-width: 0; margin-left: .6rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .bk-nav-running { display: none; }
  /* a container query measures the content box: the column is 44rem wide at 41.5rem inside its padding */
  @container (min-width: 41.5rem) { .bk-nav-running { display: inline; } }
  .app-booking .bk-nav-head-app .btn.btn-icon { flex: none; }
  /* a narrow day column: the sums on a line of their own below the paging */
  @container (max-width: 32rem) {
	.app-booking .bk-nav-head-app .bk-nav { flex-wrap: wrap; }
	.bk-nav-sum { order: 10; flex-basis: 100%; margin: .15rem 0 0 .25rem; }
  }
  .bk-nav-mode { display: inline-flex; flex: none; margin-left: auto; padding: .15rem; gap: 0; border: 0; border-radius: 999px;
	background: #E6EAF0; }
  [data-bs-theme="dark"] .bk-nav-mode { background: #2A323B; }
  .app .bk-nav-mode.nav-segmented .nav-link { min-height: 0; margin: 0; padding: .2rem .8rem; border: 0; border-radius: 999px;
	font-size: .8rem; font-weight: 600; color: var(--tblr-secondary); background: transparent; box-shadow: none; }
  .app .bk-nav-mode.nav-segmented .nav-link.active { background: var(--tblr-bg-surface); color: var(--tblr-body-color);
	box-shadow: 0 1px 2px rgba(0, 0, 0, .08); }
  /* the day's own head repeats the line above it in the day view */
  .app-booking #booking-overview[data-mode="day"] .bk-day-head { display: none !important; }
  /* the right column: the distribution (week's donut, target, attendance, booked), then "Zuletzt gebucht" */
  .app-booking .bk-side .bk-app-dist { display: flex; background: transparent; border: 0; box-shadow: none; }
  .app-booking .bk-side .bk-app-dist > .card-header { padding: 0 0 .5rem; border: 0; background: transparent; min-height: 0; }
  .app-booking .bk-side .bk-app-dist > .card-body { padding: 0; }
  .app-booking .bk-side .bk-app-dist .bk-dist { flex-wrap: nowrap; gap: .9rem; }
  .app-booking .bk-side .bk-app-dist .bk-donut { width: 7.5rem; height: 7.5rem; }
  .app-booking .bk-side .bk-app-dist .bk-donut-total { font-size: 1.15rem; }
  .app-booking .bk-side .bk-app-dist .bk-dist-legend { flex: 1 1 0; gap: .3rem; font-size: .8rem; }
  .app-booking .bk-side .bk-app-dist .bk-dist-row { gap: .3rem; }
  .app-booking .bk-side .bk-app-dist .bk-dist-facts { gap: .3rem; font-size: .85rem; }
  .app-booking .bk-side .bk-app-dist .bk-dist-facts { margin-top: .75rem; padding-top: .6rem; border-top: 1px solid var(--tblr-border-color); }
  /* the earlier weeks below the facts, set off by a line like them */
  .app-booking .bk-side .bk-app-dist .bk-weeks { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--tblr-border-color); }
  .app-booking .bk-side #booking-recent { background: transparent; border: 0; box-shadow: none; }
  /* the same thin line as above Soll/Anwesend/Gebucht separates "Zuletzt gebucht" from the distribution */
  .app-booking .bk-side #booking-app-distribution + #booking-recent { margin-top: .25rem; border-top: 1px solid var(--tblr-border-color); border-radius: 0; }
  .app-booking .bk-side #booking-recent > .card-header { padding: .75rem 0 .5rem; background: transparent; border: 0; min-height: 0; }
  .app-booking .bk-side .bk-recent-list { margin-inline: 0; }

  /* the ticket lists (Tickets, Suche, Support): the list | handle | the selected ticket, as high as the screen, each
     scrolling on its own; the list takes the width its handle gives it (--app-col-list, 22rem here, 26rem from
     1100px; app.js), the ticket the rest (at least 24rem) */
  body.app:has(> .app-rail) .app-scroll:has(> .app-split) { overflow: hidden; }
  body.app:has(> .app-rail) .app-scroll > main.app-split { --app-col-list: 22rem; display: grid; width: 100%;
	max-width: none; height: 100%; min-height: 0; margin: 0; padding: 0; grid-template-rows: minmax(0, 1fr);
	grid-template-columns: [list] var(--app-col-list) [h-list] 6px [pane] minmax(0, 1fr); }
  .app-split > .app-list { grid-column: list; grid-row: 1; min-width: 0; overflow-y: auto;
	padding: 1rem 1rem calc(1rem + env(safe-area-inset-bottom)); }
  /* a narrow list: the support groups' switch scrolls sideways instead of widening the column */
  .app-split > .app-list .bk-seg { max-width: 100%; overflow-x: auto; scrollbar-width: none; }
  .app-col-handle[data-app-col-resize="list"] { grid-column: h-list; grid-row: 1; }
  .app-split > .app-pane { display: block; grid-column: pane; grid-row: 1; min-width: 0; overflow-y: auto;
	padding: 0 calc(1rem + env(safe-area-inset-right)) calc(1rem + env(safe-area-inset-bottom)) 1rem; background: #F4F7FB; }
  [data-bs-theme="dark"] .app-split > .app-pane { background: #14181D; }
  /* loading another ticket: the old one dimmed and out of reach (app.js sets is-loading, aria-busy and inert) */
  .app-split > .app-pane.is-loading { opacity: .6; pointer-events: none; transition: opacity .15s .1s; }
  /* the selected row: tinted in the rail's blue, no bar */
  .app-split .bk-ticket-row[aria-current="true"] { z-index: 2; background: color-mix(in srgb, #4286C3 18%, var(--tblr-bg-surface)); }
  /* the booking page: an entry's ticket in place of the right column while app.js marks it open, at its own width
     (--app-col-pane, its handle where the side column's was); the entries of that ticket marked as in the lists */
  .app-booking .app-col-handle[data-app-col-resize="pane"] { display: none; }
  .app-booking .app-main:has(> #appTicketPane[data-app-pane-open]) {
	grid-template-columns: [day] minmax(0, 1fr) [h-side] 6px [side] var(--app-col-pane, 32rem); }
  .app-booking .app-main:has(> #appTicketPane[data-app-pane-open]) > .row > .bk-side,
  .app-booking .app-main:has(> #appTicketPane[data-app-pane-open]) > .app-col-handle[data-app-col-resize="side"] { display: none; }
  .app-booking .app-main > #appTicketPane[data-app-pane-open] { display: block; grid-column: side; grid-row: 2; min-width: 0;
	overflow-y: auto; padding: 0 calc(1rem + env(safe-area-inset-right)) calc(1rem + env(safe-area-inset-bottom)) 1rem;
	background: #F4F7FB; }
  .app-booking .app-main:has(> #appTicketPane[data-app-pane-open]) > .app-col-handle[data-app-col-resize="pane"] {
	display: block; grid-column: h-side; grid-row: 2; }
  .app-booking .bk-entry[aria-current="true"] { z-index: 2; background: color-mix(in srgb, #4286C3 18%, var(--tblr-bg-surface)); }
  /* two marked entries in a row: their line in a darker blue, the grey one vanishes on the tint */
  .app-booking .bk-entry[aria-current="true"]:has(+ .bk-entry[aria-current="true"]),
  .app-split .bk-ticket-row[aria-current="true"]:has(+ .bk-ticket-row[aria-current="true"]) {
	border-bottom-color: color-mix(in srgb, #4286C3 40%, var(--tblr-bg-surface)); }
  .app-booking .app-main > .app-pane.is-loading { opacity: .6; pointer-events: none; transition: opacity .15s .1s; }
  [data-bs-theme="dark"] .app-booking .app-main > .app-pane { background: #14181D; }
  /* the pane's head: the ticket's title and small round buttons ("Im Tracker öffnen", "Buchen", their labels as
     tooltips; on the booking page the ✕ last), on white and on top while the ticket scrolls */
  .app-pane-head { position: sticky; top: 0; z-index: 5; display: flex; align-items: flex-start; gap: .5rem .75rem;
	margin: 0 -1rem; padding: .85rem 1rem .5rem; background: var(--tblr-bg-surface);
	border-bottom: 1px solid var(--tblr-border-color); }
  .app-pane-title { flex: 1 1 auto; min-width: 0; margin: 0; font-size: 1.15rem; font-weight: 700; line-height: 1.3;
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; overflow-wrap: anywhere; }
  .app-pane-actions { display: flex; flex: none; gap: .35rem; margin-left: auto; }
  .app .app-pane-actions .btn, .app .app-pane-head > .btn[data-app-pane-close] { flex: none; width: 2.5rem; height: 2.5rem;
	min-width: 0; min-height: 0; padding: 0; border-radius: 50%; justify-content: center; }
  .app-pane-actions .btn .ti, .app-pane-head > [data-app-pane-close] .ti { margin: 0; font-size: 1.3rem; }
  .app-pane-actions .btn > span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%);
	white-space: nowrap; }
  /* the ticket below the head as on its page: the head's white goes on into the ticket's, whose subject the title
     already shows; its "Nochmal buchen" is the head's "Buchen" */
  .app-pane-head + #ticket-view .bk-ticket-head { margin-top: 0; padding-top: 1rem; }
  .app-pane .bk-ticket-subject { display: none; }
  .app-pane .bk-ticket-actions { display: none; }
  /* the own entries end the pane: white down to its bottom edge, no line and no grey strip below them */
  .app-pane .bk-ticket-own { border-bottom: 0; margin-bottom: calc(-1rem - env(safe-area-inset-bottom));
	padding-bottom: calc(1rem + env(safe-area-inset-bottom)); }
  /* nothing selected: a quiet hint in the middle */
  .app-pane-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .5rem;
	height: 100%; min-height: 12rem; color: var(--tblr-secondary); text-align: center; }
  .app-pane-empty .ti { font-size: 2.5rem; opacity: .5; }
  .app-pane-empty[data-app-pane-failed] .ti { color: var(--tblr-warning); opacity: .8; }
}
/* 768–1099px (tablets in portrait, narrow windows): day | side (16–24rem, 18 by default), the clocks as the phone's
   strip on top of the day column, folded collected times included */
@media (min-width: 768px) and (max-width: 1099.98px) and (min-height: 500px) {
  .app-booking .app-main:has(> .row) { --app-col-side: 22rem; grid-template-rows: auto auto minmax(0, 1fr); }
  .app-booking .app-main > .row > .col-lg-7 { grid-row: 3; }
  .app-booking .app-main > .row > .bk-side, .app-col-handle[data-app-col-resize="side"] { grid-row: 2 / 4; }
  .app-booking .app-main > #appTicketPane[data-app-pane-open],
  .app-booking .app-main:has(> #appTicketPane[data-app-pane-open]) > .app-col-handle[data-app-col-resize="pane"] { grid-row: 2 / 4; }
  .app-col-handle[data-app-col-resize="clocks"] { display: none; }
  /* the strip edge to edge in the day column, a line below it; many clocks scroll inside it */
  .app-booking .app-main > .bk-clocks { grid-column: day; grid-row: 2; min-width: 0; max-height: 40vh; margin: 0;
	overflow-y: auto; border-width: 0 0 1px; }
  /* the stop sheet at the bottom, but not across a whole tablet */
  #clockModal .modal-dialog:has(> [data-bk-sheet]) { max-width: 32rem; margin-inline: auto; }
}
/* from 1100px (with the rail, so also at least 500px high): the rail wide, with labels beside the icons and the
   person's clocks below them on every page (the booking page's clock strip moves there, app.js) */
.app-rail-clocks, .app-rail-status { display: none; }
@media (min-width: 1100px) and (min-height: 500px) {
  /* the ticket lists: a wider list by default */
  body.app:has(> .app-rail) .app-scroll > main.app-split { --app-col-list: 26rem; }
  :root:has(body.app > .app-rail) { --app-rail-w: 15rem; }
  .app-rail { padding-top: .75rem; }
  .app-rail-item { flex-direction: row; justify-content: flex-start; gap: .6rem; margin: 0 .6rem; padding: .3rem .4rem;
	border-radius: 8px; font-size: .9rem; }
  .app-rail-item .ti { width: 2.2rem; height: 2rem; flex: none; }
  .app-rail-item.active { background: color-mix(in srgb, #4286C3 10%, transparent); }
  .app-rail-item.active .ti { background: transparent; }
  .app-rail-badge { position: static; margin-left: auto; font-size: .7rem; padding: .05rem .4rem; }
  /* the clocks: a section of their own, scrolling when there are many; the stamp and the avatar stay at the bottom */
  .app-rail-clocks { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin-top: 1rem;
	padding: .9rem .75rem .5rem; border-top: 1px solid var(--tblr-border-color); overflow-y: auto; }
  /* "Uhr starten" at the bottom of the clocks' room, centred, in sight while they scroll */
  .app-rail-clock-start { position: sticky; bottom: 0; align-self: center; margin-top: auto; border-radius: 999px;
	background: var(--tblr-bg-surface); }
  .app-rail-clock-start .ti { margin-right: .35rem; font-size: 1.1rem; }
  /* the bottom: the status in words with today's time below it, then the avatar and beside it the stamp button
     (the stamp's parts placed in the bottom's grid) */
  .app-rail-bottom { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; column-gap: .6rem;
	row-gap: .05rem; padding: .75rem .9rem; border-top: 1px solid var(--tblr-border-color); }
  .app-rail-stamp { display: contents; }
  .app-rail-stamp .app-stamp-dot { grid-column: 1; grid-row: 1 / 3; justify-self: center; margin: 0; }
  .app-rail-since { display: none; }
  .app-rail-status { display: block; grid-column: 2; grid-row: 1; font-size: .82rem; font-weight: 600; line-height: 1.25;
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .app-rail-worked { grid-column: 2; grid-row: 2; margin: 0; line-height: 1.25; }
  .app-rail-stamp form { grid-column: 2; grid-row: 3; margin-top: .6rem; }
  .app-rail-me { grid-column: 1; grid-row: 3; margin-top: .6rem; }
  .app .app-rail-stamp .app-rail-stamp-btn.btn { width: 100%; flex-direction: row; justify-content: center; gap: .35rem;
	padding: .4rem .75rem; border-radius: 999px; font-size: .85rem; }
  /* the booking page: no clock column or strip of its own any more, and the day column's clock start is the rail's */
  .app-booking .app-main > .bk-clocks, .app-col-handle[data-app-col-resize="clocks"] { display: none !important; }
  .app-booking [data-app-col-rest] .bk-fab-clock { display: none !important; }
  .bk-col-label { display: block; margin: 0 0 .6rem; font-size: .72rem; font-weight: 600; text-transform: uppercase;
	letter-spacing: .05em; color: color-mix(in srgb, var(--tblr-body-color) 80%, transparent); }
  .app-rail-clocks .list-group-flush > .bk-clock { margin-bottom: .5rem; padding: .5rem .6rem;
	border: 1px solid var(--tblr-border-color); border-radius: 6px; }
  .app-rail-clocks .bk-clock-note { max-width: 100%; }
  /* the collected box says what its times are for already */
  .app-rail-clocks [data-clock-to-book] { display: none; }
  /* a clock in the narrow rail: time and buttons on the first line, the title below across the whole width, at most
     two lines (the full text in the edit dialog and as tooltip) */
  .app-rail-clocks .bk-clock > .d-flex { display: grid !important; grid-template-columns: minmax(0, 1fr) auto; align-items: center;
	gap: .35rem .5rem !important; }
  .app-rail-clocks .bk-clock > .d-flex > .flex-fill { display: contents; }
  .app-rail-clocks .bk-clock > .d-flex > .flex-fill > :not(:first-child) { grid-column: 1 / -1; }
  .app-rail-clocks .bk-clock-title { margin-top: 0; }
  .app-rail-clocks .bk-clock > .d-flex > .btn-list { grid-column: 2; grid-row: 1; margin: 0; }
  .app-rail-clocks .bk-clock > .d-flex > .btn-list > * { margin-bottom: 0; }
  .app-rail-clocks .bk-clock-note, .app-rail-clocks [data-clock-subject] { display: -webkit-box; -webkit-line-clamp: 2;
	-webkit-box-orient: vertical; overflow: hidden; overflow-wrap: break-word; word-break: normal; hyphens: auto; }
  /* the buttons no higher than the time display, so the title follows it closely */
  .app .app-rail-clocks .bk-clock-btn { width: 1.7rem; height: 1.7rem; min-width: 0; min-height: 0; padding: 0; border-radius: 50%; }
  .app-rail-clocks .bk-clock-btn .ti { font-size: 1rem; }
  .app .app-rail-clocks .bk-clock .btn-list .btn:not(.bk-clock-btn) { height: 1.7rem; min-height: 0; padding-block: 0; }
  .app-rail-clocks .list-group-flush > .bk-clock[data-state="running"] { border-color: color-mix(in srgb, #4286C3 55%, transparent); }
  /* the collected times: their "N gesammelt · H:MM" line and rows as one box below the clocks */
  .app-rail-clocks .bk-clock-collected { margin: .25rem 0 .5rem; border: 1px solid var(--tblr-border-color); border-radius: 6px;
	background: var(--tblr-bg-surface-secondary); overflow: hidden; }
  .app-rail-clocks .bk-clock-collected > .list-group { border-top: 1px solid var(--tblr-border-color); }
  .app-rail-clocks .bk-clock-collected .list-group-flush > .bk-clock { margin: 0; border: 0; border-radius: 0; background: transparent; }
  .app-rail-clocks .bk-clock-collected .list-group-flush > .bk-clock + .bk-clock { border-top: 1px solid var(--tblr-border-color); }
  /* the stop dialog: wide enough for its footer on one line (its markup asks for wrapping, the phone's sheet stacks) */
  #clockModal .modal-dialog:has(> [data-bk-sheet]) { max-width: 38rem; }
  [data-bk-sheet] .modal-footer { flex-wrap: nowrap !important; }
  [data-bk-sheet] .modal-footer .btn { white-space: nowrap; }
  /* wide: "Verwerfen" quiet on the left, the two ways to keep the time on the right; letting it run is the ✕ */
  [data-bk-sheet] .modal-footer > [data-clock-discard] { order: -1; margin-right: auto; }
  [data-bk-sheet] .bk-sheet-keep { display: none; }
}
/* the rail layouts: icons in buttons as large as the buttons ask for; the small buttons beside "Zuletzt gebucht" round
   like the others */
@media (min-width: 768px) and (min-height: 500px) {
  .app [data-bk-page] .ti { font-size: 1.2rem; }
  .app .bk-day-add .ti { font-size: 1.15rem; }
  .app .bk-entry-edit .ti { font-size: 1.1rem; }
  .app .bk-side .bk-clock-btn { width: 2rem; height: 2rem; min-width: 0; min-height: 0; padding: 0; border-radius: 50%; }
  .app .bk-side .bk-clock-btn .ti { font-size: 1.1rem; }
}
/* the app's day without entries: Tabler's empty state inside the day card, with room around it */
.bk-day-empty { padding: 2.5rem 1rem 2.75rem; }
.bk-day-empty .empty-icon { margin-bottom: 1rem; }
.bk-day-empty .empty-icon .ti { font-size: 3rem; line-height: 1; color: var(--tblr-secondary); opacity: .6; }
.bk-day-empty .empty-action .btn .ti { margin-right: .35rem; }
@media (min-width: 1100px) and (min-height: 500px) { .bk-day-empty { padding: 4.5rem 1.5rem 5rem; } }
/* "Zuletzt gebucht" in the app: the day after the ticket number, two small buttons on the right */
.bk-recent-btns { display: flex; gap: .25rem; flex: none; }
.bk-recent-btns form { display: contents; }
.bk-recent-when { color: var(--tblr-secondary); white-space: nowrap; }
.app-distribution .app-main { flex: 1; padding: 0 0 env(safe-area-inset-bottom); }
/* the distribution page's sections edge to edge like the ticket page's: white and the page's grey in turn, a fine line
   between them */
body.app.app-distribution { background: #F4F7FB; }
[data-bs-theme="dark"] body.app.app-distribution { background: #14181D; }
.app-distribution .bk-side { padding-inline: 0; }
.app-distribution .bk-side > .card { margin: 0; padding: .5rem 1rem; border-radius: 0; }
.app-distribution .bk-side > .card:nth-of-type(odd) { background: var(--tblr-bg-surface); }
/* the viewed week on top as the page's title: centred, larger and in the text colour */
.app-distribution .bk-side .card-header { justify-content: center; padding-top: 1.25rem; padding-bottom: 0; }
.app-distribution .bk-side .card-header + .card-body { padding-top: .75rem; }
.app .app-distribution .bk-side [data-distribution-week].card-title, .app-distribution .bk-side [data-distribution-week].card-title {
	font-size: 1.1rem; font-weight: 700; text-transform: none; letter-spacing: 0; color: var(--tblr-body-color); }
.app-distribution .bk-side > .card + .card { margin-top: 0; padding-top: .5rem;
	border-top: 1px solid color-mix(in srgb, var(--tblr-body-color) 22%, transparent); }

/* App: ticket search. A large round field like the Ticket Finder's; the assignee keeps to the right of the project. */
.app .app-search-field { border-radius: 999px; min-height: 44px; font-size: 1rem; }
.app .app-search .input-icon-addon { padding-left: .9rem; }
.app .app-search .input-icon .form-control:not(:first-child) { padding-left: 2.6rem; }
/* the assignee keeps their full name where it fits; the project name gives way first */
.app .app-search-assignee { flex: none; max-width: 65%; }

/* Keyboard shortcuts (app.js): the marked clock that Space, Shift+↑/↓ and Enter act on, shown with more than one clock;
   the help's entry in the user menu and its booking group only where they apply. */
.app-menu-shortcuts { min-width: 12rem; }
.app-menu-shortcuts kbd { font-size: .7rem; margin-inline-start: auto; }
[data-shortcuts-group]:last-child > dl { margin-bottom: 0 !important; }
.app-shortcuts-group { margin: 0 0 .35rem; font-size: .72rem; font-weight: 600; text-transform: uppercase; letter-spacing: .05em;
  color: var(--tblr-secondary); }
body:not(.app-booking) [data-shortcuts-group="booking"] { display: none; }
@media not ((min-width: 768px) and (min-height: 500px)) { .app-menu-shortcuts { display: none !important; } }
@media (min-width: 768px) and (min-height: 500px) {
  #booking-clocks[data-clock-marked] .bk-clock.is-current { box-shadow: inset 0 0 0 2px color-mix(in srgb, #4286C3 55%, transparent); }
  .app-rail-clocks #booking-clocks[data-clock-marked] .list-group-flush > .bk-clock.is-current { border-color: #4286C3; box-shadow: inset 0 0 0 1px #4286C3; }
}
