/* Ticketsystem – shared design system for booking flow and back office.
   Operators override --brand / --accent / --font via their theme (EM-02). */

:root {
  --brand: #1d5c4b;
  --brand-ink: #ffffff;
  --accent: #b7791f;
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;

  --bg: #f5f6f4;
  --surface: #ffffff;
  --surface-2: #f8f9f8;
  --ink: #1c2126;
  --ink-2: #4a525b;
  --muted: #656d76;
  --line: #e1e4e3;
  --line-strong: #c9cecc;
  --focus: #2563eb;

  --ok: #1f7a4d;   --ok-bg: #e6f4ec;
  --warn: #8a5a00; --warn-bg: #fdf3dc;
  --bad: #b42318;  --bad-bg: #fdecea;
  --info: #1d4ed8; --info-bg: #e8effd;
  --neutral-bg: #eef0ef;

  --seat-free: #ffffff;
  --seat-free-line: #8b9690;
  --seat-mine: var(--brand);
  --seat-held: #f2c94c;
  --seat-occupied: #c3c8c6;
  --seat-blocked: #6b737c;

  --radius: 10px;
  --radius-sm: 6px;
  --shadow: 0 1px 2px rgba(16, 24, 20, .06), 0 2px 8px rgba(16, 24, 20, .05);
  --shadow-lg: 0 10px 30px rgba(16, 24, 20, .14);
}

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font: 15px/1.5 var(--font); font-feature-settings: "tnum" 1;
}
img, svg { max-width: 100%; }
/* Staging and other non-live installations (settings.ENVIRONMENT): a calm pill with a dot and "Testsystem" in the back office's bottom
   panel, on other pages in the bottom right corner; the full text is the tooltip */
.env-badge { display: inline-flex; align-items: center; gap: 7px; padding: 3px 11px; border-radius: 999px;
  font-size: .8rem; font-weight: 500; line-height: 1.4; color: #633806; background: #faeeda; border: 1px solid #ef9f27;
  white-space: nowrap; cursor: help; }
.env-badge-dot { width: 7px; height: 7px; border-radius: 50%; background: #ba7517; flex: none;
  animation: env-pulse 2s ease-in-out infinite; }
@keyframes env-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .env-badge-dot { animation: none; } }
.env-badge-corner { position: fixed; right: 12px; bottom: 12px; z-index: 2000; box-shadow: var(--shadow); }
@media (max-width: 600px) {  /* phones: the dot alone, bottom left – the buttons ("Choose", "Next") are on the right */
  .env-badge-corner { right: auto; left: 12px; padding: 7px; }
  .env-badge-corner .env-badge-text { display: none; }
}
a { color: var(--brand); text-underline-offset: 2px; }
a:hover { text-decoration-thickness: 2px; }
h1, h2, h3, h4 { line-height: 1.2; margin: 0 0 .5em; letter-spacing: -.01em; }
h1 { font-size: 1.75rem; }
h2 { font-size: 1.3rem; }
h3 { font-size: 1.08rem; }
p { margin: 0 0 .8em; }
hr { border: 0; border-top: 1px solid var(--line); margin: 1.25rem 0; }
small, .small { font-size: .86rem; }
.muted { color: var(--muted); }
.mono { font-family: var(--mono); }
.money-symbol { color: var(--accent); }  /* the € of an amount in bold (ts.money_bold) */
.nowrap { white-space: nowrap; }
.right { text-align: right; }
.center { text-align: center; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
a.sr-only:focus { position: fixed; top: 8px; left: 8px; z-index: 1000; width: auto; height: auto; padding: 10px 16px; clip: auto;  /* the skip link: seen once it has the keyboard */
  background: var(--surface); color: var(--ink); border-radius: var(--radius-sm); box-shadow: 0 4px 16px rgba(0, 0, 0, .2); }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: 4px; }
.icon { vertical-align: -3px; flex: none; }

/* ---------- Layout helpers ---------- */
.container { max-width: 1120px; margin: 0 auto; padding: 0 16px; }
.narrow { max-width: 760px; }
.stack > * + * { margin-top: 1rem; }
.row { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.row.between { justify-content: space-between; }
.row.end { justify-content: flex-end; }
.grow { flex: 1 1 auto; }
/* an amount with its unit beside it, e.g. the cancellation fee: [ 100 ] [ % of the amount ▾ ] */
.fee-input { display: flex; gap: 6px; align-items: center; }
.fee-input > span { flex: 1 1 64px; min-width: 0; }
.fee-input > span[hidden] { display: none; }
.fee-input select { flex: 0 1 auto; width: auto; min-width: 0; }
.grid { display: grid; gap: 16px; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
.split { display: grid; gap: 20px; grid-template-columns: minmax(0, 1fr) var(--split-side, 340px); align-items: start; }
.split-seats { --split-side: 227px; }
@media (max-width: 900px) { .split { grid-template-columns: minmax(0, 1fr); } }
/* The next action stays in reach: where the summary moves below the form, the button (and the total) sit in a bar
   at the bottom of the screen. On wide screens the summary column sticks instead and the bar is just the button. */
.pay-bar-total { display: none; }
@media (max-width: 900px) {
  body:has(.pay-bar) { padding-bottom: 88px; }
  html:has(.pay-bar) { scroll-padding-bottom: 96px; }  /* a field reached with the keyboard stays above the bar */
  .pay-bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 30; display: flex; align-items: center; gap: 14px;
    margin: 0; padding: 10px 16px calc(10px + env(safe-area-inset-bottom)); background: var(--surface);
    border-top: 1px solid var(--line); box-shadow: 0 -2px 10px rgba(16, 24, 20, .12); }
  .pay-bar .btn { flex: 1; width: auto; min-width: 0; white-space: normal; }  /* a long label wraps, never off the screen */
  .pay-bar-total { display: flex; flex-direction: column; line-height: 1.2; white-space: nowrap; font-size: 1.05rem; }
  .pay-bar-total small { color: var(--muted); font-size: .75rem; }
  .pay-bar-note { display: none; }
  body:has(.pay-bar) .env-badge-corner { bottom: 90px; }  /* the test badge above the bar */
  /* one column: the summary no longer sticks – a sticky column is a layer of its own that would keep the bar
     (fixed) below other layers such as the back office's bottom bar */
  .sticky:has(.pay-bar) { position: static; }
  /* box office: the bar sits on the back office's bottom bar (name, notifications, feedback) instead of over it */
  .bo .pay-bar { bottom: var(--bo-bar-h, 45px); }
  .bo:has(.pay-bar) .bo-content { padding-bottom: 110px; }
}

/* ---------- Cards ---------- */
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); }
.card-body { padding: 20px; }
.card-head { padding: 14px 20px; border-bottom: 1px solid var(--line); display: flex; align-items: center; gap: 10px; justify-content: space-between; flex-wrap: wrap; }
.card-head h2, .card-head h3 { margin: 0; }
.card-foot { padding: 14px 20px; border-top: 1px solid var(--line); background: var(--surface-2); border-radius: 0 0 var(--radius) var(--radius); }
.sticky { position: sticky; top: 16px; }
/* Settings → Ticket: settings on the left, live preview on the right (below each other on small screens) */
.ticket-designer { display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 420px); gap: 16px; align-items: start; }
@media (max-width: 1100px) { .ticket-designer { grid-template-columns: minmax(0, 1fr); } }
.ticket-preview .card-head select { width: auto; }
.ticket-preview-frame { position: relative; background: var(--surface-2); border-radius: 8px; padding: 10px; min-height: 160px; transition: opacity .15s; }
/* the block hovered in the list, outlined on the preview */
.preview-mark { position: absolute; border: 2px solid var(--accent, #b7791f); background: rgba(183, 121, 31, .14);
  border-radius: 4px; pointer-events: none; box-shadow: 0 0 0 3px rgba(183, 121, 31, .18); transition: all .12s ease-out; }
.ticket-blocks tbody tr:hover > td { background: var(--surface-2); }
.ticket-preview-frame.is-loading { opacity: .55; }
.ticket-preview-frame img { display: block; max-width: 100%; max-height: 72vh; margin: 0 auto; background: #fff;
  box-shadow: 0 1px 4px rgba(16, 24, 20, .18); }
.ticket-blocks td, .ticket-blocks th { vertical-align: middle; }
.ticket-blocks select { min-width: 120px; }
/* Column headings can be dragged to another place (backoffice.js) */
th.col-draggable { cursor: grab; }
th.col-dragging { opacity: .4; }
th.col-drop-before { box-shadow: inset 3px 0 0 var(--brand, #1d5c4b); }
th.col-drop-after { box-shadow: inset -3px 0 0 var(--brand, #1d5c4b); }
/* the handle at a heading's right edge: drag to change the column's width (columns.js) */
.col-resize { position: absolute; top: 0; bottom: 0; right: 0; width: 12px; display: flex; align-items: center; justify-content: center; cursor: col-resize; touch-action: none; user-select: none; color: var(--line-strong); }
.col-resize::before { content: ""; height: 14px; border-left: 1.5px solid currentColor; }
th.col-last > .col-resize { display: none; }
th > .col-resize:hover, .col-resizing th > .col-resize:active { color: var(--brand, #1d5c4b); }
table.data.cols-resizable th { padding-right: 16px; }
table.data.cols-resizable th.sortable { padding-right: 28px; }
table.data.cols-resizable th .sort-mark { right: 12px; }
/* widths set by hand: the text wraps within them, what cannot wrap is cut off; tooltips and menus may stick out */
table.data.cols-sized { table-layout: fixed; }
table.data.cols-sized th, table.data.cols-sized td { overflow: hidden; overflow-wrap: anywhere; text-overflow: ellipsis; }
table.data.cols-sized th:has(.tip), table.data.cols-sized td:has(.tip, details) { overflow: visible; }
/* Right-click menu of the lists (columns.js) */
.ctx-menu { position: fixed; z-index: 1000; min-width: 190px; padding: 4px; background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm); box-shadow: 0 8px 24px rgba(0, 0, 0, .16); }
.ctx-menu button { display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 12px; border: 0; border-radius: 6px; background: none;
  color: var(--ink); font: inherit; text-align: left; cursor: pointer; }
.ctx-menu button:hover, .ctx-menu button:focus-visible { background: var(--surface-2); outline: none; }
.ctx-menu button svg { flex: none; color: var(--ink-2); }
.ctx-menu-split { display: grid; grid-template-columns: 1fr auto 1fr; margin-bottom: 2px; }  /* two buttons in one row, a line between them */
.ctx-menu-split button { white-space: nowrap; }
.ctx-menu-split button:last-child { justify-content: center; }
.ctx-menu-split span { width: 1px; margin: 6px 2px; background: var(--line); }
/* Train types: the icon picker (backoffice-routes.js) */
.icon-choice { display: flex; align-items: center; gap: 10px; }
.icon-choice .icon-upload { white-space: nowrap; }
.icon-picker-btn { display: inline-flex; align-items: center; gap: 12px; min-width: 110px; min-height: 42px; padding: 6px 12px;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); cursor: pointer; }
.icon-picker-btn::after { content: ""; margin-left: auto; border: 5px solid transparent; border-top-color: var(--ink-2); border-bottom: 0; }
.icon-picker-btn:focus-visible { outline: none; border-color: var(--focus); box-shadow: 0 0 0 3px rgba(37, 99, 235, .18); }
.icon-picker-value { display: inline-flex; align-items: center; min-height: 28px; }
.icon-picker-value img, .icon-picker-menu img { height: 23px; width: auto; }
.icon-picker-menu { position: fixed; z-index: 1000; display: flex; gap: 4px; padding: 6px; background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm); box-shadow: 0 8px 24px rgba(0, 0, 0, .16); }
.icon-picker-menu[hidden] { display: none; }
.icon-picker-menu button { display: inline-flex; align-items: center; justify-content: center; min-width: 58px; min-height: 48px; padding: 6px 8px;
  border: 2px solid transparent; border-radius: 6px; background: none; cursor: pointer; }
.icon-picker-menu button:hover, .icon-picker-menu button:focus-visible { background: var(--surface-2); outline: none; }
.icon-picker-menu button[aria-selected="true"] { border-color: var(--brand); }
.icon-upload { position: relative; }
.icon-upload input[type=file] { position: absolute; inset: 0; width: 100%; opacity: 0; cursor: pointer; }
.icon-upload:focus-within { border-color: var(--focus); box-shadow: 0 0 0 3px rgba(37, 99, 235, .18); }
/* Configure columns: the columns as a list */
.col-config-list { list-style: none; margin: 12px 0 16px; padding: 0; display: grid; gap: 6px; }
.col-config-item { display: flex; align-items: center; gap: 10px; padding: 6px 8px; border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); background: var(--surface); cursor: grab; }
.col-config-item label { flex: 1; cursor: pointer; }
.col-config-item input[type="checkbox"] { width: 18px; height: 18px; }
.col-config-item.is-hidden label { color: var(--ink-2); text-decoration: line-through; }
.col-config-item.col-dragging { opacity: .4; }
.col-config-item .drag-handle { color: var(--ink-2); }
tr[data-row-href] { cursor: pointer; }
/* hovered rows: the organisation's accent colour at 10 % (grey where color-mix is unknown) */
tr[data-row-href]:hover > td { background: #ebefed; background: color-mix(in srgb, var(--accent) 10%, transparent); }
.bo .sticky { top: calc(var(--bo-top-h, 0px) + 16px); }  /* below the back office's sticky page header */

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 42px; padding: 0 16px; border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink);
  font: 600 .95rem/1 var(--font); text-decoration: none; cursor: pointer; white-space: nowrap;
  transition: background .12s, border-color .12s, box-shadow .12s;
}
.btn:hover { border-color: var(--ink-2); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; }
.btn-primary { background: var(--brand); border-color: var(--brand); color: var(--brand-ink); }
.btn.btn-saved, .btn.btn-saved:hover { background: var(--ok); border-color: var(--ok); color: #fff; transition: background .2s, border-color .2s; }
.btn-primary:hover { filter: brightness(1.08); border-color: var(--brand); }
.btn-publish { min-width: 160px; }  /* "Publish" and the green "Published" with its check: one size */
/* "Save" while there is something to save (backoffice.js); not "Saved" */
.btn.btn-unsaved { animation: save-pulse 2s ease-out infinite; }
@keyframes save-pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--brand) 60%, transparent); }
  70%, 100% { box-shadow: 0 0 0 10px color-mix(in srgb, var(--brand) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) { .btn.btn-unsaved { animation: none; } }
.btn-danger { color: var(--bad); border-color: #e6b4ae; }
.btn-danger:hover { background: var(--bad-bg); border-color: var(--bad); }
.btn-ghost { border-color: transparent; background: transparent; }
.btn-ghost:hover { background: var(--neutral-bg); border-color: transparent; }
.btn-sm { min-height: 32px; padding: 0 10px; font-size: .86rem; }
.btn-lg { min-height: 50px; padding: 0 22px; font-size: 1.02rem; }
.btn-block { width: 100%; }
/* a checkbox that looks like a button: two icons, the second one (a check) when on */
.filter-toggle { position: relative; margin-bottom: 0; }  /* a label, but in line with the fields beside it */
.filter-toggle svg + svg, .filter-toggle:has(:checked) svg:first-of-type { display: none; }
.filter-toggle:has(:checked) svg + svg { display: block; }
.filter-toggle:has(:checked), .filter-toggle:has(:checked):hover { background: var(--ok-bg); border-color: var(--ok); color: var(--ok); }
.filter-toggle:has(:focus-visible) { outline: 3px solid var(--brand); outline-offset: 2px; }
.btn.is-busy { position: relative; color: transparent !important; }
.btn.is-busy::after { content: ""; position: absolute; width: 18px; height: 18px; border-radius: 50%; border: 2px solid currentColor; border-color: var(--brand-ink) transparent var(--brand-ink) transparent; animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.linkish { background: none; border: 0; padding: 0; color: var(--brand); font: inherit; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }

/* ---------- Forms ---------- */
label { font-weight: 600; font-size: .92rem; display: block; margin-bottom: 4px; }
.field { margin-bottom: 14px; }
.field .help { color: var(--muted); font-size: .84rem; margin-top: 4px; font-weight: 400; }
.field .errorlist, .errorlist { color: var(--bad); font-size: .86rem; margin: 4px 0 0; padding: 0; list-style: none; }
input:not([type]), input[type=text], input[type=email], input[type=password], input[type=number], input[type=tel],
input[type=url], input[type=date], input[type=datetime-local], input[type=time], input[type=search], select, textarea {
  width: 100%; min-height: 42px; padding: 8px 11px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink); font: inherit;
}
textarea { min-height: 90px; resize: vertical; }
input[type=color] { width: 56px; height: 42px; padding: 3px; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--focus); box-shadow: 0 0 0 3px rgba(37, 99, 235, .18); }
input[type=checkbox], input[type=radio] { width: 18px; height: 18px; accent-color: var(--brand); vertical-align: -3px; }
.check { display: flex; gap: 10px; align-items: flex-start; font-weight: 400; }
.check input { margin-top: 2px; }
.option-children { display: grid; gap: 12px; margin: 12px 0 0 8px; padding-left: 18px; border-left: 2px solid var(--line); }  /* what belongs to the switch above */
.form-grid { display: grid; gap: 0 16px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.form-grid .full { grid-column: 1 / -1; }
/* Fields beside each other share their rows (label / input / help), so the inputs line up even when one label
   wraps onto two lines; the label sits directly above its input. */
/* One text in two languages: DE/EN switch above the field (backoffice/_i18n_field.html) */
.i18n-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 8px; }
.i18n-head label { margin-bottom: 4px; }
.i18n-switch { display: inline-flex; gap: 2px; padding: 2px; margin-bottom: 4px; background: var(--neutral-bg);
  border: 1px solid var(--line); border-radius: 8px; flex: 0 0 auto; }
.i18n-switch button { display: inline-flex; align-items: center; gap: 5px; padding: 3px 7px; border: 0; border-radius: 6px;
  background: none; font: inherit; font-size: .75rem; font-weight: 600; color: var(--muted); cursor: pointer; position: relative; }
.i18n-switch button[aria-pressed="true"] { background: var(--surface); color: var(--ink); box-shadow: 0 1px 2px rgb(0 0 0 / .12); }
table[data-i18n-field] th:has(.i18n-switch) { min-width: 220px; text-transform: none; }
.i18n-switch .flag { border-radius: 2px; box-shadow: 0 0 0 1px rgb(0 0 0 / .12); }
.i18n-switch button[data-filled]::after { content: ""; position: absolute; top: 2px; right: 2px; width: 5px; height: 5px;
  border-radius: 50%; background: var(--ok); }
.surcharge-row { margin-bottom: 6px; }
.surcharge-label { min-width: 120px; font-weight: 500; }
/* a field that does not apply right now (e.g. capacity while the wagons give a seat map) */
input.is-locked, input:disabled { background: var(--neutral-bg); color: var(--muted); cursor: not-allowed; }
/* German date fields with a calendar (static/js/datetime.js) */
.dt-input { position: relative; display: flex; align-items: center; gap: 4px; }
.dt-input input { flex: 1 1 auto; min-width: 0; }
.report-date-field { width: 150px; max-width: 100%; }
.report-date-control { display: flex; align-items: flex-start; gap: 8px; max-width: 100%; }
.toolbar[data-report-dates] { align-items: flex-start; }
.toolbar[data-report-dates] > label, .report-date-control > label { padding-top: 10px; }
.report-date-field input[aria-invalid="true"] { border-color: var(--bad); background: var(--bad-bg); }
.report-date-field input[aria-invalid="true"]:focus { box-shadow: 0 0 0 3px rgb(180 35 24 / .18); }
.dt-pop { position: absolute; top: calc(100% + 6px); left: 0; z-index: 40; width: 292px; padding: 12px; background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm); box-shadow: 0 8px 24px rgb(0 0 0 / .14);
  max-width: calc(100vw - 24px); }
.dt-pop-right { left: auto; right: 0; }
.dt-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.dt-title { text-transform: capitalize; }
.dt-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; text-align: center; }
.dt-wd { font-size: .75rem; color: var(--muted); padding: 2px 0 4px; }
.dt-day { border: 0; background: none; border-radius: 6px; padding: 6px 0; font: inherit; cursor: pointer; color: var(--ink); }
.dt-day:hover, .dt-day:focus-visible { background: var(--neutral-bg); }
.dt-day.today { box-shadow: inset 0 0 0 1px var(--line-strong); }
.dt-day.selected { background: var(--brand); color: #fff; font-weight: 700; }
.dt-time { display: flex; align-items: center; gap: 6px; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }
.dt-time select { width: auto; }
.dt-time .small { margin-right: auto; }
.dt-foot { display: flex; justify-content: flex-end; gap: 6px; margin-top: 10px; }
.dt-foot .btn:first-child { margin-right: auto; }
.form-aligned > .field { display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: 0;
  grid-template-columns: minmax(0, 1fr); min-width: 0; }  /* stays in its column, e.g. the logo with a long file name */
.form-aligned > .field > label { align-self: end; }
/* A form in sections (backoffice/_form.html, form.sections) */
.form-section + .form-section { margin-top: 8px; padding-top: 18px; border-top: 1px solid var(--line); }
.form-section-title { display: flex; align-items: center; gap: 8px; margin: 0 0 12px; font-size: 1rem; }
.form-section-title svg { color: var(--muted); }
.form-section-note { margin: -8px 0 12px; }
/* Options side by side in small groups, each under a heading like a form's section (e.g. Bookings & payments → Settings) */
.option-groups { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 8px 32px; }
.form-grid.form-thirds { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 760px) { .form-grid.form-thirds { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 480px) { .form-grid.form-thirds { grid-template-columns: minmax(0, 1fr); } }
.form-grid.form-address { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 2fr) minmax(0, 2fr); }
@media (max-width: 760px) { .form-grid.form-address { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 480px) { .form-grid.form-address { grid-template-columns: minmax(0, 1fr); } }
.form-aligned > .field > .check { align-self: center; }
/* A switch beside a field's label (backoffice/_form.html, form.label_switches): off greys out and locks the field */
.label-switch { display: flex; align-items: center; gap: 10px; align-self: end; margin-bottom: 6px; }
.label-switch > label:first-child { margin: 0; }
.switch { position: relative; display: inline-flex; flex: none; cursor: pointer; }
.switch input[type=checkbox] { appearance: none; width: 36px; height: 20px; margin: 0; border-radius: 999px;
  background: var(--line-strong); cursor: pointer; transition: background .15s; vertical-align: 0; }
.switch input[type=checkbox]:checked { background: var(--brand); }
.switch input[type=checkbox]:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.switch-knob { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 2px rgb(0 0 0 / .25); pointer-events: none; transition: transform .15s; }
.switch input:checked + .switch-knob { transform: translateX(16px); }
.field-control.is-off { opacity: .5; }
/* An on/off setting drawn as a switch (CheckboxInput(attrs={"role": "switch"})): the knob is part of the background */
input[type=checkbox][role=switch] { appearance: none; flex: none; width: 36px; height: 20px; margin: 0; border-radius: 999px;
  background: radial-gradient(circle at 10px 50%, #fff 7px, transparent 8px) var(--line-strong); cursor: pointer;
  transition: background-position .15s, background-color .15s; vertical-align: -5px; }
input[type=checkbox][role=switch]:checked { background-color: var(--brand); background-position: 16px 0; }
input[type=checkbox][role=switch]:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
/* Settings → Payment methods: the switches online and at the box office, side by side */
.method-switches { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 0 16px; }
.method-switches fieldset { display: grid; align-content: start; gap: 12px; padding-bottom: 14px; }
fieldset { border: 1px solid var(--line); border-radius: var(--radius); padding: 14px 18px 4px; margin: 0 0 16px; }
legend { font-weight: 700; padding: 0 6px; }
.choice { display: flex; gap: 12px; align-items: center; border: 1px solid var(--line-strong); border-radius: var(--radius-sm); padding: 12px 14px; margin-bottom: 8px; cursor: pointer; font-weight: 500; background: var(--surface); }
.choice select { min-width: 0; max-width: 60%; }
.route-table select[name="coach_layout"] { min-width: 220px; }
.choice:has(input:checked) { border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand); background: color-mix(in srgb, var(--brand) 5%, var(--surface)); }
.choice-disabled { cursor: not-allowed; color: var(--muted); background: var(--surface-2); }
.field-attached { margin-top: 12px; }
.drag-handle { cursor: grab; font-size: 1.1rem; color: var(--muted); }
[data-sort-row].row-inactive input[type=text] { color: var(--muted); background: var(--surface-2); }
[data-sort-row].dragging { opacity: .45; background: var(--neutral-bg); }
.route-table input[type=number] { max-width: 120px; }
/* Strecke → Preise: show the columns of the chosen price model */
.fare-table input[inputmode=decimal] { min-width: 84px; text-align: right; }
.fare-table[data-model=""] .col-amount, .fare-table[data-model=""] .col-section,
.fare-table[data-model="flat"] .col-section, .fare-table[data-model="per_section"] .col-section,
.fare-table[data-model="sections"] .col-amount, .fare-table[data-model="stops"] .col-amount,
.fare-table[data-model="stops"] .col-section, .fare-table[data-model="stops"] .col-ret-percent,
.fare-table[data-model="stops"] .col-ret-amount { display: none; }
/* Reduction on the return trip: one column per kind, only the chosen kind is shown (and only with route prices) */
.fare-table[data-model=""] .col-ret-percent, .fare-table[data-model=""] .col-ret-amount,
.fare-table[data-return=""] .col-ret-percent, .fare-table[data-return=""] .col-ret-amount,
.fare-table[data-return="percent"] .col-ret-amount, .fare-table[data-return="amount"] .col-ret-percent { display: none; }
.fare-table .label-per { display: none; }
.fare-table[data-model="per_section"] .label-per { display: inline; }
.fare-table[data-model="per_section"] .label-flat { display: none; }
.file-current { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; padding: 6px 6px 6px 8px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface-2); }
.file-thumb { height: 40px; max-width: 120px; object-fit: contain; border-radius: 4px; background: #fff; }
.file-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .9rem; }
.file-delete { color: var(--bad); }
.file-delete:hover { background: var(--bad-bg); }
.input-group { display: flex; gap: 8px; }
.input-group > input { flex: 1; }
.locked-field > input[readonly] { color: var(--muted); background: var(--surface-2); cursor: not-allowed; }

/* Quantity stepper */
.stepper { display: inline-flex; align-items: center; border: 1px solid var(--line-strong); border-radius: 999px; overflow: hidden; background: var(--surface); }
.stepper button { width: 40px; height: 40px; border: 0; background: transparent; font-size: 1.25rem; cursor: pointer; color: var(--brand); }
.stepper button:hover { background: var(--neutral-bg); }
.stepper button:disabled { color: var(--line-strong); cursor: default; background: transparent; }
.stepper input { width: 46px; min-height: 40px; border: 0; text-align: center; font-weight: 700; padding: 0; -moz-appearance: textfield; }
.stepper input::-webkit-inner-spin-button { -webkit-appearance: none; }
.stepper input:focus { box-shadow: none; }

/* ---------- Alerts, badges ---------- */
.alert { padding: 12px 14px; border-radius: var(--radius-sm); border: 1px solid; display: flex; gap: 10px; align-items: flex-start; margin-bottom: 14px; }
.alert-ok { background: var(--ok-bg); border-color: #b7dfc7; color: #144d31; }
.alert-warn { background: var(--warn-bg); border-color: #f0d79c; color: #5e3e00; }
.alert-bad { background: var(--bad-bg); border-color: #f2b8b2; color: #7a1a12; }
.alert-info { background: var(--info-bg); border-color: #c3d4f8; color: #183a8c; }
.badge { display: inline-flex; align-items: center; gap: 4px; padding: 2px 9px; border-radius: 999px; font-size: .78rem; font-weight: 650; white-space: nowrap; }
.badge-ok { background: var(--ok-bg); color: var(--ok); }
.badge-warn { background: var(--warn-bg); color: var(--warn); }
.badge-bad { background: var(--bad-bg); color: var(--bad); }
.badge-info { background: var(--info-bg); color: var(--info); }
.badge-neutral { background: var(--neutral-bg); color: var(--ink-2); }
/* in a list as wide as "Abgeschlossen" at most; a longer label wraps onto a second line rather than being cut off */
table.data .badge { display: inline-block; max-width: 9.5em; white-space: normal; overflow-wrap: break-word; line-height: 1.3; border-radius: .8em; vertical-align: bottom; }
table.data .badge.badge-full { max-width: none; }  /* a short label of its own: always whole */

/* ---------- Tables ---------- */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table.data { width: 100%; border-collapse: collapse; font-size: .92rem; }
table.data th, table.data td { padding: 9px 10px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
table.data th { font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); font-weight: 650; background: var(--surface-2); vertical-align: bottom; position: sticky; top: 0; }
table.data thead th { z-index: 2; }  /* moved down over the rows while the page scrolls (backoffice.js) */
table.data thead th:has(.tip) { z-index: 3; }  /* its tooltip stays above the headings beside it */
.bo .table-wrap.table-fits { overflow-x: visible; }  /* fits its width: the header sticks to the page, smoothly */
.bo .table-wrap.table-fits > table.data thead th { top: var(--bo-top-h, 0px); }
[data-scroll-box] .table-wrap.table-fits > table.data thead th { top: 0; }  /* a panel or dialog scrolls itself */
table.data.head-stuck thead th { box-shadow: 0 2px 4px rgba(16, 24, 20, .08); }
table.data th a { color: inherit; text-decoration: none; }
table.data a.row-link { color: inherit; text-decoration: none; }  /* the row's own link, for the keyboard: a click means the whole row */
table.data th a:hover { color: var(--ink); }
/* sortable headings keep room for the arrow, so sorting does not move the table */
table.data th.sortable { padding-right: 22px; }
table.data th .sort-mark { position: absolute; right: 6px; bottom: 11px; line-height: 0; color: var(--ink); }
/* every second record slightly darker (backoffice.js sets is-stripe; expanded sub-rows share their parent's shade);
   the hover stays stronger than the stripe */
table.data tr.is-stripe > td { background: #f3f5f4; }
table.data tbody tr:hover > td { background: #ebefed; background: color-mix(in srgb, var(--accent) 10%, transparent); }
table.data td.num, table.data th.num { text-align: right; font-variant-numeric: tabular-nums; }
table.data tr.sub td { font-size: .88rem; }
table.data tr.sub td:first-child { padding-left: 28px; }
table.data tfoot td { font-weight: 700; border-top: 2px solid var(--line-strong); }
table.kv { border-collapse: collapse; width: 100%; }
table.kv th, table.kv td { padding: 6px 0; vertical-align: top; text-align: left; }
table.kv th { color: var(--muted); font-weight: 500; width: 40%; padding-right: 12px; }
.empty { padding: 36px 20px; text-align: center; color: var(--muted); }

/* ---------- How full ---------- */
/* How full, as a ring with the percentage in it (backoffice/_ring.html) */
.ring { position: relative; display: inline-flex; flex: none; width: 42px; height: 42px; }
.ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.ring circle { fill: none; stroke-width: 4; }
.ring-track { stroke: var(--neutral-bg); }
.ring-fill { stroke: var(--brand); }
.ring.warn .ring-fill { stroke: var(--accent); }
.ring.full .ring-fill { stroke: var(--bad); }
.ring b { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 10.5px; font-weight: 650; font-variant-numeric: tabular-nums; letter-spacing: -.02em; white-space: nowrap; }
.ring-lg { width: 64px; height: 64px; }
.ring-lg b { font-size: 15px; }
.ring-cell { display: flex; align-items: center; gap: 10px; }

/* ---------- KPI tiles ---------- */
.kpi { padding: 16px 18px; }
/* Overview: widgets in a 4-column grid, in reading order, gaps filled (backoffice/dashboard_widgets.py) */
.dash-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-flow: row dense; grid-auto-rows: minmax(96px, auto); gap: 18px; }
.dash-w { position: relative; min-width: 0; display: flex; flex-direction: column; }
.dash-w > .card { flex: 1; margin: 0; min-width: 0; }
.dash-w-1 { grid-column: span 1; } .dash-w-2 { grid-column: span 2; } .dash-w-3 { grid-column: span 3; } .dash-w-4 { grid-column: span 4; }
.dash-h-2 { grid-row: span 2; } .dash-h-3 { grid-row: span 3; }
@media (max-width: 1100px) { .dash-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .dash-w-3, .dash-w-4 { grid-column: span 2; } }
@media (max-width: 640px) { .dash-grid { grid-template-columns: minmax(0, 1fr); } .dash-w { grid-column: span 1; grid-row: auto; } }
.dash-w .summary-line { flex-wrap: wrap; column-gap: 12px; }  /* a narrow widget: the amount and badge go below */
.dash-w .summary-line > span { min-width: 0; overflow-wrap: anywhere; }
/* tooltips at a widget's right edge open leftwards, so they do not widen the page */
.dash-w .card-head .tip::after, .dash-bars span:nth-last-child(-n+8)::after { left: auto; right: 0; transform: none; }
.dash-bars span:nth-child(-n+8)::after { left: 0; transform: none; }
.dash-bars { display: flex; align-items: flex-end; gap: 2px; height: 90px; }
.dash-bars span { flex: 1; min-height: 2px; background: color-mix(in srgb, var(--brand) 70%, var(--surface)); border-radius: 2px 2px 0 0; }
/* the shared note: a sticky note that takes the height the widget has */
.dash-note { display: flex; flex-direction: column; }
.dash-note .card-body { flex: 1; display: flex; flex-direction: column; gap: 10px; }
.dash-note-paper { position: relative; flex: 1; display: flex; flex-direction: column; background: var(--ok-bg); border: 1px solid #b7dfc7; border-radius: var(--radius-sm); }
.dash-note-paper:focus-within { border-color: var(--focus); box-shadow: 0 0 0 3px rgba(37, 99, 235, .18); }
.dash-note-paper textarea, .dash-note-paper textarea:focus, .dash-note-paper textarea:disabled { flex: 1; width: 100%; padding: 12px 40px 4px 14px; background: none; border: 0; box-shadow: none; color: var(--ink); opacity: 1; resize: none; }
.dash-note-paper .dash-note-erase { position: absolute; top: 8px; right: 8px; display: inline-flex; padding: 4px; border: 0; border-radius: 5px; background: none; color: var(--muted); cursor: pointer; }
.dash-note-erase:hover { background: rgba(0, 0, 0, .06); color: var(--bad); }
.dash-note-erase:focus-visible { outline: 2px solid var(--focus); }
.dash-note-foot { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 2px 12px; min-height: 1.4em; padding: 2px 14px 8px; }
.dash-note-foot [data-note-changed] { margin-left: auto; }
.dash-note-theirs { margin-top: 8px; max-height: 160px; overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; }
.dash-note-choice { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
/* edit mode: the widgets are shown but not used; a bar with handle and size buttons on top */
.dash-grid.is-editing .dash-w { outline: 1.5px dashed var(--line-strong); outline-offset: 3px; border-radius: var(--radius); }
.dash-grid.is-editing .dash-w > :not(.dash-tools) { pointer-events: none; user-select: none; }
.dash-tools { display: flex; align-items: center; gap: 6px; padding: 4px 6px; margin-bottom: 6px; background: var(--surface-2); border: 1px solid var(--line); border-radius: 8px; font-size: .82rem; cursor: grab; }
.dash-handle { color: var(--muted); }
.dash-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dash-buttons { display: flex; gap: 2px; flex: none; }
.dash-buttons button { border: 0; background: none; padding: 2px 6px; border-radius: 5px; cursor: pointer; color: var(--ink-2); font: inherit; line-height: 1.2; display: inline-flex; align-items: center; }
.dash-buttons button:hover { background: var(--line); }
.dash-buttons button:focus-visible { outline: 2px solid var(--focus); }
.dash-w.is-dragging { opacity: .4; }
.dash-grid.is-editing { min-height: 120px; }
.dash-panel-add { display: none; }
/* The widgets not on the overview, in frosted glass at the bottom; it stays in the flow, so scrolling to the end shows
   everything above it. Each one is a small picture of itself (dashboard.js), its text scaled to the card. */
.dash-panel { position: sticky; bottom: var(--bo-bar-h, 44px); z-index: 8; display: flex; flex-direction: column; gap: 10px; max-height: 40vh; margin-top: 20px; padding: 14px 16px; overflow-y: auto; background: rgb(16 24 20 / .5); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px); border-radius: var(--radius) var(--radius) 0 0; box-shadow: var(--shadow-lg); animation: dash-panel-in .3s ease-out; }
@keyframes dash-panel-in { from { transform: translateY(100%); } }
@media (prefers-reduced-motion: reduce) { .dash-panel { animation: none; } }
.dash-panel.is-shrunk { max-height: 56px; overflow: hidden; }
.dash-panel.is-shrunk .dash-panel-widgets { visibility: hidden; }
.dash-panel-title, .dash-panel-none { align-self: flex-start; margin: 0; padding: 3px 10px; border-radius: 6px; background: rgb(16 24 20 / .6); color: #fff; font-size: .9rem; font-weight: 650; }
.dash-panel-none { font-weight: 500; }
.dash-panel-widgets { display: flex; flex-wrap: wrap; gap: 12px; }
.dash-panel-widgets:empty { display: none; }
.dash-panel .dash-w { --preview: 260px; --scale: .8; flex: none; width: 230px; height: 210px; overflow: hidden; background: var(--surface); border-radius: var(--radius); cursor: grab; }
.dash-panel .dash-w.is-dragging { opacity: .4; }
.dash-panel .dash-w-2 { --preview: 420px; --scale: .5; }
.dash-panel .dash-w-3 { --preview: 600px; --scale: .35; }
.dash-panel .dash-w-4 { --preview: 700px; --scale: .3; }
.dash-panel .dash-w > :not(.dash-tools) { position: absolute; top: 10px; left: 10px; width: var(--preview); margin: 0; transform: scale(var(--scale)); transform-origin: 0 0; pointer-events: none; user-select: none; }
.dash-panel .dash-tools { position: absolute; left: 0; right: 0; bottom: 0; z-index: 1; flex-wrap: wrap; margin: 0; padding: 8px 10px; border: 0; border-top: 1px solid var(--line); border-radius: 0; }
.dash-panel .dash-handle, .dash-panel .dash-buttons { display: none; }
.dash-panel .dash-label { flex: 0 0 100%; }
.dash-panel .dash-panel-add { display: inline-flex; flex: 1; justify-content: center; }
.kpi .label { color: var(--muted); font-size: .82rem; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; }
.kpi .value { font-size: 1.6rem; font-weight: 750; margin-top: 4px; letter-spacing: -.02em; }
.kpi .sub { color: var(--muted); font-size: .85rem; }
a.kpi-link { display: block; color: inherit; text-decoration: none; transition: border-color .12s, box-shadow .12s; }
a.kpi-link:hover { border-color: var(--brand); box-shadow: var(--shadow-lg); }
/* in the colour of its section (the tint of that section's pages, backoffice.css), from white at the top left, with the
   section's icon large and faint, cut by the upper edge (kpi_tile): a ticket upright, the euro tilted */
.kpi-bookings { --kpi-tint: #7fe3c440; --kpi-mark: #1a9470; }
.kpi-tint { position: relative; overflow: hidden; }
.kpi-tint::before { content: ""; position: absolute; inset: 0; background: linear-gradient(135deg, transparent 35%, var(--kpi-tint, transparent)); pointer-events: none; }
.kpi-tint > :not(.kpi-mark) { position: relative; }
.kpi-mark { position: absolute; top: -40px; right: 6px; width: 112px; height: 112px; color: var(--kpi-mark); opacity: .2; pointer-events: none; }
.kpi-mark-ticket { transform: rotate(72deg); }
.kpi-mark-euro { top: -24px; right: -10px; transform: rotate(-18deg); }
.kpi-mark svg { display: block; width: 100%; height: 100%; stroke-width: 1.3; }

/* ---------- Tabs ---------- */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); margin-bottom: 18px; overflow-x: auto; }
.tabs a { padding: 10px 14px; text-decoration: none; color: var(--ink-2); font-weight: 600; border-bottom: 2px solid transparent; white-space: nowrap; }
.tabs a[aria-current="page"], .tabs a.active { color: var(--brand); border-bottom-color: var(--brand); }
.voucher-events.is-off { opacity: .5; }
/* segmented control: one of a few options, e.g. the kind of voucher */
.segmented { display: inline-flex; flex-wrap: wrap; gap: 2px; padding: 3px; background: var(--surface-2); border: 1px solid var(--line); border-radius: 10px; }
.segmented button { border: 1px solid transparent; background: none; border-radius: 8px; padding: 7px 14px; font: inherit; font-weight: 600; color: var(--muted); cursor: pointer; }
.segmented button:hover { color: var(--ink); }
.segmented button[aria-checked="true"] { background: var(--surface); border-color: var(--line-strong); color: var(--brand); }
.segmented button:focus-visible { outline: 3px solid var(--focus); outline-offset: 1px; }
/* the same as links that switch between views of a page (audit log: System | Bookings) */
.segmented a { border: 1px solid transparent; border-radius: 8px; padding: 7px 14px; font-weight: 600; color: var(--muted); text-decoration: none; }
.segmented a:hover { color: var(--ink); }
.segmented a[aria-current="page"] { background: var(--surface); border-color: var(--line-strong); color: var(--brand); }
.segmented a:focus-visible { outline: 3px solid var(--focus); outline-offset: 1px; }
.tabs button { padding: 10px 14px; background: none; border: 0; border-bottom: 2px solid transparent; color: var(--ink-2); font: inherit; font-weight: 600; white-space: nowrap; cursor: pointer; }
.tabs button[aria-selected="true"] { color: var(--brand); border-bottom-color: var(--brand); }

