/* ==========================================================================
   Administration front end - the same design language as the reporting.

   The file is ordered by area; the headings below name them one after another.
   Inside an area everything stands in the order in which it came about - that is
   deliberate: at equal specificity the order decides, and re-sorting inside an
   area would change that.

   The rules for narrow windows (@media) stand gathered at the end, so that they
   override the basic rules and not the other way round.
   ========================================================================== */


/* -------------------------------------------------------------------- Basics */

:root {
  --brand: #57a900;
  --brand-dark: #4a9100;
  --brand-light: #f0f8e6;

  --bg: #f4f6f9;
  --surface: #ffffff;
  --surface-alt: #fafbfc;
  --border: #e3e8ee;
  --border-strong: #cdd5df;

  --text: #1f2933;
  --text-muted: #6b7785;

  --good: #2f9e44;
  --good-bg: #e7f7ec;
  --bad: #c92a2a;
  --bad-bg: #fdeaea;
  /* Neither good nor bad but open - something is waiting for somebody. */
  --warning: #b26a00;
  --warning-bg: #fff4e0;

  /*
   * A find, not a verdict - it draws the eye without saying whether something is right.
   *
   * Not called --accent: an open dropdown reads var(--accent, #333) for its border and relies on
   * that fallback, so defining --accent here would recolour it in passing.
   */
  --highlight: #3b5bdb;
  --highlight-bg: #edf2ff;

  /* Row tints, lighter than the pills that sit on them so a pill keeps its shape. */
  --good-row: #ebfbee;
  --bad-row: #fff5f5;

  /* Navigation as in the warehouse tool (Bootstrap 4 navbar-dark bg-dark / navbar-light bg-light) */
  --nav-bg: #343a40;
  --nav-link: rgba(255, 255, 255, .5);
  --nav-link-hover: rgba(255, 255, 255, .75);
  --nav-link-active: #fff;
  --sub-nav-bg: #f3f3f3;
  --sub-nav-link: rgba(0, 0, 0, .5);
  --sub-nav-link-hover: rgba(0, 0, 0, .7);
  --sub-nav-link-active: rgba(0, 0, 0, .9);

  --radius: 8px;
  --radius-sm: 5px;
  --shadow-sm: 0 1px 2px rgba(20, 30, 45, .06), 0 1px 3px rgba(20, 30, 45, .05);
  --shadow-md: 0 2px 6px rgba(20, 30, 45, .07), 0 6px 16px rgba(20, 30, 45, .06);
  --nav-height: 50px;
  --sub-nav-height: 46px;
}

*, *::before, *::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  /* The reporting CSS still keeps room here for its old bar - no longer needed. */
  padding: 0;
  background: var(--bg);
  color: var(--text);
  /* Font sizes as in the warehouse tool: its Bootstrap sets nothing on the body,
     so 16px and the default sans-serif apply. */
  font-family: sans-serif;
  font-size: 16px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  margin: 0;
  font-weight: 600;
}

h1 {
  font-size: 28px;
}

h2 {
  font-size: 21px;
}

a {
  color: var(--brand-dark);
  text-decoration: none;
}

a:hover {
  color: var(--brand);
}

body.no-sub-navigation .page {
  padding-top: 62px;
}

/*
 * Embedded page without navigation of its own - that stands in the frame above, so the room for
 * the fixed bars is not needed here.
 */
body.embed-page .page {
  padding-top: 22px;
  padding-bottom: 28px;
}

/* ==========================================================================
   Time tracking
   --------------------------------------------------------------------------
   Taken over from public/assets/css_sass/components/_timeTracking.scss of the
   standalone tool. The rules are carried over from SCSS into ordinary CSS, the
   colours stand as values instead of variables - the front end here builds no
   SCSS. The class names have stayed the same, so that the further pages can be
   pulled along without renaming.
   ========================================================================== */

:root {
  --ze-success: #28a745;
  --ze-success-bg: rgba(40, 166, 69, .2);
  --ze-blue: #007bff;
  --ze-blue-bg: rgba(0, 105, 217, .2);
  --ze-error: #dc3545;
  --ze-orange: #ff841a;
  --ze-grey: #c7c7c7;
  --ze-light-grey: #f3f3f3;
  --ze-dark-grey: #797979;
}

/* ---------------------------------------------------------------- Page frame */

.page {
  font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
  max-width: 1180px;
  margin: 0 auto;
  /* Room for the two fixed bars - like #mainBody in the warehouse tool. */
  padding: 112px 24px 64px;
}

/*
 * For pages with tables: more room than the reading width of .page, but not the whole window
 * width. That way wide tables like the one in item/itemPrices.php fit without the eye having to
 * travel right across the page on a large screen.
 */
.page.page-table {
  max-width: 1500px;
  padding-left: 28px;
  padding-right: 28px;
}

/* For permanent displays: use nearly the full window width. */
.page.page-wide {
  max-width: none;
  padding-left: 32px;
  padding-right: 32px;
}

/*
 * For pages that reach the bottom of the window themselves and scroll within it: the padding at
 * the bottom falls away, or a strip would hang below and the page would get a second scrollbar
 * with nothing in it.
 */
.page.page-fill {
  padding-bottom: 0;
}

.page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 22px;
}

.page-subtitle {
  margin: 4px 0 0;
  color: var(--text-muted);
}

.page-actions {
  display: flex;
  gap: 8px;
}

/* Without a page head the button row stands alone - then it needs the spacing itself. */
.page > .page-actions {
  flex-wrap: wrap;
  margin-bottom: 22px;
}

.section-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 14px;
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 1px;
  text-transform: uppercase;
}

/*
 * A section heading has no spacing above - following on content it would otherwise sit right
 * against it. Concerns the overviews that show several blocks below one another (wholesale feeds,
 * statistics, own tasks).
 */
.table-scroll + .section-head,
.card + .section-head,
.alert + .section-head,
.card-row + .section-head {
  margin-top: 30px;
}

/*
 * The same case the other way round: a table is often followed by another block - an explanation,
 * a hint, a form. `.table-scroll` brings no spacing along and `.card` only one below, so the two
 * were stuck together.
 */
.table-scroll + .card,
.table-scroll + .card-hint,
.table-scroll + .alert {
  margin-top: 22px;
}

.section-head::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

.empty-state {
  text-align: center;
  color: var(--text-muted);
}

.empty-state h1,
.empty-state h2 {
  margin-bottom: 8px;
  color: var(--text);
}

/*
 * Built and styled like the module start pages in the warehouse tool
 * (.modules-container and .button.button-adapter out of its base/_base.scss).
 */
.modules-container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 1rem;
}

/* Some air between two groups, so the heading belongs to what follows it. */
.modules-container + .section-head {
  margin-top: 28px;
}

.modules-container .button-adapter {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 4rem;
  margin: 0;
  padding: 0 1rem;
  border: 1px solid #000;
  background-color: #f3f3f3;
  color: #000;
  font-weight: bold;
  text-align: center;
  text-decoration: none;
}

.modules-container .button-adapter:hover,
.modules-container .button-adapter:focus {
  background-color: #797979;
  color: #fff;
  text-decoration: none;
}

/* Overall tile: wider and more detailed than the channel tiles. */

/* The shop key beside the section heading - quieter than that heading. */
.section-head-hint {
  margin-left: 8px;
  color: var(--text-muted);
  font-size: 13px;
  font-weight: 400;
}

.alert {
  margin-bottom: 20px;
  padding: 12px 16px;
  border: 1px solid;
  border-left-width: 4px;
  border-radius: var(--radius-sm);
}

.alert-success {
  background: var(--good-bg);
  border-color: var(--good);
  color: #1e7a33;
}

.alert-error {
  background: var(--bad-bg);
  border-color: var(--bad);
  color: #8c1c1c;
}

/*
 * "There is nothing here" is not a success message - the tool has a quiet line for that
 * (div.info), not the green box.
 */
.empty-hint {
  padding: 14px 0;
  color: var(--text-muted);
  text-align: center;
}

/* --- Short notices at the bottom right ---------------------------------- */

/*
 * For pages that do not reload. They lie above everything but take no clicks - otherwise a
 * message would cover the button beneath it.
 */
.admin-messages {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 10002;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-end;
  pointer-events: none;
}

.admin-message {
  max-width: min(420px, calc(100vw - 40px));
  padding: 10px 16px;
  border: 1px solid var(--border);
  border-left-width: 4px;
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-md);
  font-size: .92rem;
  animation: adminMessageIn .2s ease-out;
}

.admin-message-success {
  border-left-color: var(--good);
}

.admin-message-error {
  border-left-color: var(--bad);
}

.admin-message.is-leaving {
  opacity: 0;
  transition: opacity .3s ease-in;
}

/* What lies outside the period stays empty - but the grid stands. */
.time-tracking-calendar .calendar-day.empty {
  background: repeating-linear-gradient(45deg, #fafafa, #fafafa 6px, #f2f2f2 6px, #f2f2f2 12px);
}

/*
 * Icons in buttons and tiles: a word space before them, or they stick to the label. The mask
 * takes its colour from currentColor - on coloured buttons it therefore matches by itself.
 */
.button .nav-icon,
.button-adapter .nav-icon {
  margin-right: .35rem;
}

/* In the administration the tiles stand below one another - there the icon carries the row. */
.modules-container .button-adapter .nav-icon {
  vertical-align: -4px;
}

/* ----------------------------------------------------------- Cards and tiles */

.card {
  margin-bottom: 22px;
  padding: 20px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

/*
 * Two cards side by side - filter and file upload in the ELBA tool, for instance. Below 320px per
 * card the row breaks by itself, so on narrow screens they stand below one another again.
 */
.card-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 0 22px;
}

/* So the button rows of both cards sit at the same height, even with content of differing height. */
.card-row > .card {
  display: flex;
  flex-direction: column;
}

.card-row > .card .form-actions {
  margin-top: auto;
}

/*
 * A flex column so the tiles of a row can be of equal height: the grid stretches the card, and
 * what may grow inside (the scrolling list) fills the rest.
 */
.metric-card {
  display: flex;
  flex-direction: column;
  padding: 16px 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

/* Catches the eye as soon as something has been left lying. */
.metric-card.has-backlog {
  border-left-color: #d98324;
}

/*
 * In the overview the cards of a row are of equal height - the height is set by "Alle Kanaele".
 * The list may fill the room that creates, or an empty strip was left below it: measured 52 px at
 * 1920 and up to 141 px at 1440 pixels of window width. It still scrolls, only now at the bottom
 * edge of the card (flex: 1 and min-height: 0 sit on .metric-scroll-list).
 */
.metric-grid.overall > .metric-card .metric-scroll-list {
  /*
   * flex-basis 0 instead of auto: that way the list does not count towards the natural height of
   * the card. The row height is still set by "Alle Kanaele", and the list gets exactly the rest.
   * With basis auto it would demand its full content height and pull the card out to over
   * 5,000 px.
   */
  flex: 1 1 0;
  /*
   * A lower bound so the list does not disappear when the card stands alone in its row and there
   * is no neighbouring height - then it falls back to the same 320 px as everywhere else.
   */
  min-height: 320px;
  max-height: none;
}

/*
 * In the wide overview label and value stood at the two ends of the card - with half the window
 * width between them. Two pairs per row put the value right beside its label and halve the height
 * along the way. If the card is too narrow for that, it stays single-column.
 *
 * What is asked is the card itself, not the window: since it shares the row with two further
 * tiles, the window width says nothing about the room inside the card. At 1440px of window width
 * the goods value ran out of its column with the old window query.
 */
.metric-card-overall {
  container-type: inline-size;
}

.metric-card-overall .metric-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  margin-top: 16px;
}

/*
 * The block is meant for the end of a form and therefore has spacing only above. If it stands
 * above content for once - "Automatisches OK" above the open incoming payments, say - the table
 * would otherwise stick to the buttons.
 */
.form-actions + .table-scroll,
.form-actions + .card-hint,
.form-actions + .data-table {
  margin-top: 18px;
}

.card-hint {
  margin: 0 0 10px;
  color: var(--text-muted);
  font-size: 13px;
}

/*
 * The selection column of the tables - a tick column at the very left.
 *
 * Narrow, centred and without wrapping: it carries a checkbox and nothing else, and without a
 * fixed width it takes as much room as the heading beside it.
 */
table.data-table td.column-select,
table.data-table th.column-select {
  width: 34px;
  text-align: center;
  white-space: nowrap;
}

/*
 * The preview of a mail in the mailTester.
 *
 * White ground, independent of the administration's theme: that way it looks like it does in a
 * mailbox and not like a part of this page.
 */
.mail-preview {
  width: 100%;
  height: 640px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: #fff;
}

/* A message that goes out as plain text - the way a mailbox shows it. */
.mail-preview-text {
  margin: 0;
  padding: 16px;
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: #fff;
  color: #404040;
  font-family: ui-monospace, "SFMono-Regular", "Menlo", monospace;
  font-size: 13px;
  line-height: 20px;
  white-space: pre-wrap;
}

.item-card .card-title {
  margin-top: 0;
}

.time-tracking-status .card-buttons {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .4rem;
  margin-top: .8rem;
}

/* -------------------------------------------------------------------- Tables */

.table-scroll {
  width: 100%;
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

/*
 * Without horizontal scrolling: everything is there at once.
 *
 * The table itself always fits - what runs over the edge are only the controls of the action
 * column, which `white-space: nowrap` holds on one line. Here they may wrap, and then nothing
 * stays hidden.
 */
.table-scroll.table-wrap {
  overflow-x: visible;
}

/*
 * `width: 1%` allots the action column less than its controls need - they then run out of the
 * cell. Without this declaration it gets its natural width and the remaining columns share the
 * rest. It may still wrap, in case the window is very narrow.
 */
.table-scroll.table-wrap table.data-table td.column-action,
.table-scroll.table-wrap table.data-table th:last-child {
  width: auto;
  white-space: normal;
}

/* The controls themselves stay whole - wrapping happens only between them. */
.table-scroll.table-wrap table.data-table td.column-action > * {
  margin-bottom: 2px;
  white-space: nowrap;
}

table.data-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13px;
}

table.data-table th {
  position: sticky;
  top: 0;
  padding: 10px 14px;
  background: var(--surface-alt);
  border-bottom: 1px solid var(--border-strong);
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .4px;
  text-transform: uppercase;
  text-align: left;
  white-space: nowrap;
}

table.data-table td {
  padding: 9px 14px;
  border-top: 1px solid var(--border);
  vertical-align: middle;
}

table.data-table tbody tr:hover td {
  background: rgba(31, 41, 51, .035);
}

table.data-table td.column-action {
  width: 1%;
  white-space: nowrap;
  text-align: right;
}

/* Buttons out of forms should stand next to the links of the column, not below them. */
table.data-table td.column-action form {
  display: inline-block;
  /*
   * Only top and bottom to zero.
   *
   * `margin: 0` stood here, and that was more specific than the rule below which sets the spacing
   * between the controls - a form next to a button therefore stuck to it. It showed everywhere an
   * action column carries a link and a form: "Weiter"/"Verwerfen" in the drafts of the order
   * portal, for example.
   */
  margin-top: 0;
  margin-bottom: 0;
}

table.data-table td.column-action > * + * {
  margin-left: 6px;
}

/* Figures only read well below one another - equal digit width, right-aligned. */
table.data-table th.column-number,
table.data-table td.column-number {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Image table in the article detail. */
.column-check {
  width: 1%;
  text-align: center;
}

/*
 * Hints in data tables stand on lines of their own. In the order, marketplace identifiers and the
 * individual discounts would otherwise run together on a single line.
 */
.data-table .field-hint {
  display: block;
}

/*
 * Two-column tables in which the th labels the row instead of a column.
 *
 * .data-table is built for lists: there the th sits in the thead, sticks to the top when
 * scrolling (position: sticky) and carries a strong line below it, while the td has its line
 * above. As a row label that makes two different lines per row, which moreover do not meet as
 * soon as the value column is taller than the label.
 */
table.data-table.detail-table th {
  position: static;
  width: 34%;
  border-bottom: none;
  border-top: 1px solid var(--border);
  vertical-align: top;
  white-space: normal;
}

/* The first row needs no line - the card heading already stands above it. */
table.data-table.detail-table tbody tr:first-child th,
table.data-table.detail-table tbody tr:first-child td {
  border-top: none;
}

table.data-table.detail-table td {
  vertical-align: top;
}

table.data-table.detail-table tbody tr:hover th {
  background: var(--surface-alt);
}

/* The balances table: narrow number fields, so the names keep their room. */
table.data-table td .value-input {
  width: 9rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* The column with the checkboxes stays narrow and does not disturb the table's widths. */
.data-table .column-check {
  width: 2rem;
  text-align: center;
}

/* --- Task list: columns and actions ------------------------------------- */

/*
 * One column per note - one comes from the reporting side, the other from whoever is working on
 * it. The width is capped so a long text does not pull the whole table apart.
 */
.data-table .column-note {
  min-width: 12rem;
  max-width: 20rem;
}

.data-table .column-note .field-hint {
  white-space: normal;
}

/*
 * The actions on the right: select and buttons at the same height. The select brings its height
 * from .field-input, the small buttons their own - side by side that looked like two rows.
 *
 * Whether the column wraps is left to the house rule further up (table-wrap): with a narrow
 * window it should be allowed to, and the controls themselves stay whole while it does.
 */
.data-table .column-action > form,
.data-table .column-action > .button,
.data-table .column-action > button,
.data-table .column-action > select {
  display: inline-flex;
  align-items: center;
  vertical-align: top;
}

.data-table .column-action .button,
.data-table .column-action .field-input,
.data-table .column-action .field-select {
  height: 34px;
  padding-top: 0;
  padding-bottom: 0;
}

.data-table .column-action .field-inline {
  width: auto;
  min-width: 8.5rem;
}

/* A mail address needs more than the 8.5rem a select gets by with. */
.data-table .column-action .field-inline-wide {
  min-width: 17rem;
}

/*
 * Several controls in one action column - field, select, button.
 *
 * Outside the table the input may take the room that is left; here it may not. The cell is as
 * wide as its content (column-action sits on width: 1%), and a field that fills the rest makes
 * the group a different width in every row - then the button stands here in one and there in the
 * next, and the column is no longer in line.
 *
 * So every element gets a width of its own and the group moves to the right. All rows are built
 * the same way then, however long the mail address in them is.
 */
.data-table .column-action .field-with-button {
  justify-content: flex-end;
}

.data-table .column-action .field-with-button > .field-input,
.data-table .column-action .field-with-button > .field-select {
  flex: 0 0 auto;
}

/*
 * The button at the end is as wide as the widest one in its column.
 *
 * Otherwise the alignment hangs on the word: in the invitation list it reads "Einladen", for a
 * customer with an account "Erneut" - two characters less. The group is right-aligned, so that
 * one row slid right by exactly those two characters, and the input beside it started later than
 * in the rows above.
 *
 * The width is not a question of beauty: a column whose fields do not stand below one another
 * reads as two columns.
 */
.data-table .column-action .field-with-button > .button {
  min-width: 7rem;
  justify-content: center;
}


/* --------------------------------------------------------------------- Forms */

/* SQL and other input where the indentation counts. */
.field-input.field-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 1.5;
  white-space: pre;
  overflow-x: auto;
}

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px 20px;
}

.field {
  display: flex;
  flex-direction: column;
}

/*
 * `hidden` has to win: the rule above is more specific than the display:none the browser brings
 * along for [hidden]. Without this, "Hinterlegt" stood in the request overlay even when no proof
 * is on file at all - the same held for the two fields in the board overlay.
 */
.field[hidden] {
  display: none;
}

/*
 * Fields standing directly below one another need the spacing themselves - inside .form-grid it
 * comes from the gap, outside there was none at all. That concerned every form whose fields lie
 * straight in the card.
 */
.field + .field,
.field + .form-grid,
.form-grid + .field,
/* Two grids in succession were not covered - between them the spacing was missing entirely. */
.form-grid + .form-grid {
  margin-top: 16px;
}

/* In the grid the gap provides the spacing - otherwise it would stand twice. */
.form-grid > .field + .field {
  margin-top: 0;
}

.field-wide {
  grid-column: 1 / -1;
}

/* Whether a new row starts with this field. */
.field-new-line {
  grid-column: 1;
}

.field-label {
  margin-bottom: 5px;
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .6px;
  text-transform: uppercase;
}

.field-input,
.field-select,
.field-textarea {
  width: 100%;
  padding: 9px 11px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
}

.field-textarea {
  min-height: 92px;
  resize: vertical;
}

.field-input:focus,
.field-select:focus,
.field-textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(87, 169, 0, .15);
}

.field-hint {
  margin-top: 5px;
  color: var(--text-muted);
  font-size: 12px;
}

.field-check {
  display: flex;
  align-items: center;
  gap: 8px;
}

.field-check input {
  margin: 0;
  accent-color: var(--brand);
}

.field-check label {
  margin: 0;
  font-weight: 400;
  cursor: pointer;
}

/*
 * A filter bar above a list.
 *
 * Not to be done with .form-actions: that is the footer of a form and brings a dividing line
 * above it - over a filter that looks like a cut-off remnant.
 */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 14px 22px;
}

/* The general rule `.field + .field` does not apply here - side by side it is not needed. */
.filter-bar .field {
  margin-top: 0;
  min-width: 170px;
}

.filter-bar .filter-checks {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 20px;
  /* At the height of the input - align-items lines up the bottom edges. */
  height: 38px;
}

.filter-bar .filter-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  margin-left: auto;
}

/* The hint used to stand under the date field and pushed it out of the row. */
.filter-hint {
  margin: 12px 0 0;
  color: var(--text-muted);
  font-size: 12px;
}

.form-actions {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}

/*
 * When a form closes with its button row, another one often follows below - to request something,
 * to delete something. Without spacing its card sticks to the buttons; here it gets the same one
 * the cards have between them.
 *
 * Only the row immediately inside the form: the one in a card closes with that card's padding.
 */
form > .form-actions:last-child {
  margin-bottom: 22px;
}

.login-form .field-label {
  margin-top: 14px;
}

.login-form .field-label:first-child {
  margin-top: 0;
}

.login-form .field-hint {
  margin-top: 6px;
}

/* An input with a button beside it, e.g. date + "heute". */
.field-with-button {
  display: flex;
  align-items: center;
  gap: 8px;
}

.field-with-button .field-input {
  flex: 1 1 auto;
  min-width: 0;
}

.field-with-button .button {
  flex: 0 0 auto;
}

/*
 * Input and button stay together on the left, instead of the field taking the whole width and the
 * button sliding to the right edge.
 */
.field-with-button-left {
  justify-content: flex-start;
}

.field-with-button-left .field-input {
  flex: 0 1 320px;
}

/*
 * A value with its switch beside it - in an ordinary table cell.
 *
 * A <form> is a block element and otherwise drops below whatever stands before it: the badge on
 * top, the button underneath, and a line of air between them that means nothing. In the action
 * columns a rule of its own handles that; outside them this wrapper is needed.
 */
.value-with-action {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.value-with-action form {
  margin: 0;
}

/* A value that is only displayed - looks like a field but is not one. */
.field-static {
  padding: 9px 0;
  font-weight: 600;
  word-break: break-word;
}

.image-table .field-input {
  min-width: 0;
}

/*
 * An input standing directly below a list in the same card - without spacing it stuck to the
 * bottom edge of the table.
 */
.form-after-list {
  margin-top: 18px;
}

/* Many buttons of equal rank - they may wrap. */
.form-actions-wrap {
  flex-wrap: wrap;
}

/* Filter choices above a list - the ticks stand beside one another, not below. */
.filter-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
}

.filter-chips .field-check {
  margin: 0;
}

.embed-search .field-input {
  width: 100%;
  max-width: 420px;
  padding: 4px 9px;
  font-size: 13px;
}

/* Intermediate heading in forms - separates groups such as payment and shipping. */
.form-group-title {
  margin: 20px 0 10px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .8px;
  text-transform: uppercase;
}

.form-group-title:first-of-type {
  margin-top: 12px;
}

/* A multiple choice - in the tool this was a drop-down list with ticks. */
.checkbox-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 4px 16px;
  margin-top: 6px;
}

.checkbox-option {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  font-weight: 400;
}

/* The search stands above the list and should not feel as heavy as an editing form. */
.filter-card .form-actions {
  margin-top: 0;
}

/* Visible only to screen readers - the tick alone tells them nothing. */
.field-note-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.time-tracking-calendar .calendar-filter .field,
.time-tracking-department .department-filter .field {
  margin: 0;
}

/* The fields stand in one row - .field-select is otherwise as wide as its container. */
.todo-bulk .field-select {
  width: auto;
  min-width: 11rem;
}

/* --- Multiple choice as a fold-out field -------------------------------- */

.dropdown-checkbox {
  position: relative;
  min-width: 12rem;
}

/* Looks like a select and behaves like one - only with checkboxes inside. */
.dropdown-checkbox-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  width: 100%;
  padding: 9px 11px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  font-family: inherit;
  font-size: 14px;
  text-align: left;
}

.dropdown-checkbox-label::after {
  content: '▾';
  flex: none;
  color: var(--ze-dark-grey);
}

.dropdown-checkbox.is-open .dropdown-checkbox-label {
  border-color: var(--accent, #333);
}

/*
 * The list lies over the page instead of pushing it down - otherwise everything below would jump
 * as soon as somebody opens the field.
 */
.dropdown-checkbox-list {
  position: absolute;
  z-index: 20;
  top: calc(100% + 2px);
  right: 0;
  left: 0;
  display: none;
  max-height: 18rem;
  overflow-y: auto;
  padding: .35rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  box-shadow: var(--shadow-md);
}

.dropdown-checkbox.is-open .dropdown-checkbox-list {
  display: block;
}

.dropdown-checkbox-option {
  display: flex;
  align-items: center;
  gap: .45rem;
  padding: .3rem .4rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 14px;
}

.dropdown-checkbox-option:hover {
  background: var(--ze-light-grey);
}

.dropdown-checkbox-all {
  display: block;
  width: 100%;
  padding: .3rem .4rem;
  margin-bottom: .25rem;
  border: none;
  border-bottom: 1px solid var(--border);
  background: none;
  color: var(--ze-dark-grey);
  cursor: pointer;
  font-family: inherit;
  font-size: .82rem;
  text-align: left;
}

/* Without a script the list stays open - then it is at least usable. */
.no-js .dropdown-checkbox-list {
  display: block;
  position: static;
}

/* ------------------------------------------------- Buttons, badges, symbols */

.pill {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 99px;
  font-size: 11px;
  font-weight: 600;
}

.pill-good {
  background: var(--good-bg);
  color: var(--good);
}

.pill-muted {
  background: var(--surface-alt);
  color: var(--text-muted);
  border: 1px solid var(--border);
}

.pill-bad {
  background: var(--bad-bg);
  color: var(--bad);
}

/*
 * A state still being decided - an invitation nobody has accepted.
 *
 * Grey would mean "done, nothing further", and that is exactly what it is not: somebody is
 * waiting there. Between the green of the running account and the red of the blocked one, this
 * third colour was missing.
 */
.pill-warning {
  background: var(--warning-bg);
  color: var(--warning);
}

.button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 9px 18px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background-color .15s ease;
}

.button-primary {
  background: var(--brand);
  border-color: var(--brand-dark);
  color: #fff;
}

.button-primary:hover {
  background: var(--brand-dark);
  color: #fff;
}

.button-secondary {
  background: var(--surface);
  border-color: var(--border-strong);
  color: var(--text);
}

.button-secondary:hover {
  background: var(--surface-alt);
  color: var(--text);
}

.button-danger {
  background: var(--surface);
  border-color: var(--bad);
  color: var(--bad);
}

.button-danger:hover {
  background: var(--bad-bg);
  color: var(--bad);
}

.button-small {
  padding: 5px 12px;
  font-size: 13px;
}

/*
 * The warehouse tool uses Font Awesome. Two glyphs are enough here, embedded
 * as a mask - that way they take on the colour of the link without a whole
 * icon font library having to be loaded.
 */
.nav-icon {
  display: inline-block;
  width: 17px;
  height: 17px;
  vertical-align: -3px;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

.nav-icon-expand {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 3H5a2 2 0 0 0-2 2v3M16 3h3a2 2 0 0 1 2 2v3M8 21H5a2 2 0 0 1-2-2v-3M16 21h3a2 2 0 0 0 2-2v-3'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 3H5a2 2 0 0 0-2 2v3M16 3h3a2 2 0 0 1 2 2v3M8 21H5a2 2 0 0 1-2-2v-3M16 21h3a2 2 0 0 0 2-2v-3'/%3E%3C/svg%3E");
}

.nav-icon-sliders {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M3 6h18M3 12h18M3 18h18'/%3E%3Ccircle cx='9' cy='6' r='2.6' fill='%23fff'/%3E%3Ccircle cx='15' cy='12' r='2.6' fill='%23fff'/%3E%3Ccircle cx='8' cy='18' r='2.6' fill='%23fff'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M3 6h18M3 12h18M3 18h18'/%3E%3Ccircle cx='9' cy='6' r='2.6' fill='%23fff'/%3E%3Ccircle cx='15' cy='12' r='2.6' fill='%23fff'/%3E%3Ccircle cx='8' cy='18' r='2.6' fill='%23fff'/%3E%3C/svg%3E");
}

/* Checklist - the counter beside it names the unfinished tasks. */
.nav-icon-todo {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6h2l1.4 1.6L10 5M13 6.5h7M4 13h2l1.4 1.6L10 12M13 13.5h7M4 20h2l1.4 1.6L10 19M13 20.5h7'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6h2l1.4 1.6L10 5M13 6.5h7M4 13h2l1.4 1.6L10 12M13 13.5h7M4 20h2l1.4 1.6L10 19M13 20.5h7'/%3E%3C/svg%3E");
}

/*
 * The icons of the metric tiles and the hints. In the tool this was Font Awesome; here the same
 * motifs as a mask, so they take on the colour of their row.
 */
.nav-icon-balance {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4v16M8 20h8M4 7h16M12 4 6 8M12 4l6 4M3 8l-1 4a3 3 0 0 0 6 0L7 8M17 8l-1 4a3 3 0 0 0 6 0l-1-4'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4v16M8 20h8M4 7h16M12 4 6 8M12 4l6 4M3 8l-1 4a3 3 0 0 0 6 0L7 8M17 8l-1 4a3 3 0 0 0 6 0l-1-4'/%3E%3C/svg%3E");
}

.nav-icon-clock {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.5'/%3E%3Cpath d='M12 6.5V12l3.5 2.2'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.5'/%3E%3Cpath d='M12 6.5V12l3.5 2.2'/%3E%3C/svg%3E");
}

.nav-icon-umbrella {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 12a8.5 8.5 0 0 1 17 0z'/%3E%3Cpath d='M12 12v7.5a1.8 1.8 0 0 1-3.6 0'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 12a8.5 8.5 0 0 1 17 0z'/%3E%3Cpath d='M12 12v7.5a1.8 1.8 0 0 1-3.6 0'/%3E%3C/svg%3E");
}

.nav-icon-medical {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3h8l4 4v14H6z'/%3E%3Cpath d='M14 3v4h4'/%3E%3Cpath d='M12 11.5v5M9.5 14h5'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3h8l4 4v14H6z'/%3E%3Cpath d='M14 3v4h4'/%3E%3Cpath d='M12 11.5v5M9.5 14h5'/%3E%3C/svg%3E");
}

.nav-icon-users {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='8' r='3.2'/%3E%3Cpath d='M3.5 19c0-3 2.5-5 5.5-5s5.5 2 5.5 5'/%3E%3Cpath d='M16 5.5a3.2 3.2 0 0 1 0 5'/%3E%3Cpath d='M17.5 14.2c1.9.6 3 2.4 3 4.8'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='8' r='3.2'/%3E%3Cpath d='M3.5 19c0-3 2.5-5 5.5-5s5.5 2 5.5 5'/%3E%3Cpath d='M16 5.5a3.2 3.2 0 0 1 0 5'/%3E%3Cpath d='M17.5 14.2c1.9.6 3 2.4 3 4.8'/%3E%3C/svg%3E");
}

.nav-icon-calendar {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.5' y='5' width='17' height='15' rx='2'/%3E%3Cpath d='M3.5 9.5h17'/%3E%3Cpath d='M8 3.5v3'/%3E%3Cpath d='M16 3.5v3'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.5' y='5' width='17' height='15' rx='2'/%3E%3Cpath d='M3.5 9.5h17'/%3E%3Cpath d='M8 3.5v3'/%3E%3Cpath d='M16 3.5v3'/%3E%3C/svg%3E");
}

.nav-icon-sitemap {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='3' width='6' height='5' rx='1'/%3E%3Crect x='3' y='16' width='6' height='5' rx='1'/%3E%3Crect x='15' y='16' width='6' height='5' rx='1'/%3E%3Cpath d='M12 8v4'/%3E%3Cpath d='M6 16v-4h12v4'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='3' width='6' height='5' rx='1'/%3E%3Crect x='3' y='16' width='6' height='5' rx='1'/%3E%3Crect x='15' y='16' width='6' height='5' rx='1'/%3E%3Cpath d='M12 8v4'/%3E%3Cpath d='M6 16v-4h12v4'/%3E%3C/svg%3E");
}

.nav-icon-user-clock {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='7' r='3.2'/%3E%3Cpath d='M3.5 20c0-3 2.5-5 5.5-5h.6'/%3E%3Ccircle cx='17' cy='16.5' r='4'/%3E%3Cpath d='M17 14.7v1.8l1.3 1'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='9' cy='7' r='3.2'/%3E%3Cpath d='M3.5 20c0-3 2.5-5 5.5-5h.6'/%3E%3Ccircle cx='17' cy='16.5' r='4'/%3E%3Cpath d='M17 14.7v1.8l1.3 1'/%3E%3C/svg%3E");
}

.nav-icon-building {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='5' y='3' width='14' height='18' rx='1.5'/%3E%3Cpath d='M9 7h2'/%3E%3Cpath d='M13 7h2'/%3E%3Cpath d='M9 11h2'/%3E%3Cpath d='M13 11h2'/%3E%3Cpath d='M10.5 21v-4h3v4'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='5' y='3' width='14' height='18' rx='1.5'/%3E%3Cpath d='M9 7h2'/%3E%3Cpath d='M13 7h2'/%3E%3Cpath d='M9 11h2'/%3E%3Cpath d='M13 11h2'/%3E%3Cpath d='M10.5 21v-4h3v4'/%3E%3C/svg%3E");
}

.nav-icon-key {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='7.5' cy='15.5' r='3.5'/%3E%3Cpath d='M10 13 20 3'/%3E%3Cpath d='M17 6l2.5 2.5'/%3E%3Cpath d='M14.5 8.5 17 11'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='7.5' cy='15.5' r='3.5'/%3E%3Cpath d='M10 13 20 3'/%3E%3Cpath d='M17 6l2.5 2.5'/%3E%3Cpath d='M14.5 8.5 17 11'/%3E%3C/svg%3E");
}

.nav-icon-file-pdf {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 3H7a1.5 1.5 0 0 0-1.5 1.5v15A1.5 1.5 0 0 0 7 21h10a1.5 1.5 0 0 0 1.5-1.5V7.5z'/%3E%3Cpath d='M14 3v4.5h4.5'/%3E%3Cpath d='M8.5 16.5v-3.5h1.2a1.2 1.2 0 0 1 0 2.4H8.5'/%3E%3Cpath d='M13 13v3.5h1a1.75 1.75 0 0 0 0-3.5z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 3H7a1.5 1.5 0 0 0-1.5 1.5v15A1.5 1.5 0 0 0 7 21h10a1.5 1.5 0 0 0 1.5-1.5V7.5z'/%3E%3Cpath d='M14 3v4.5h4.5'/%3E%3Cpath d='M8.5 16.5v-3.5h1.2a1.2 1.2 0 0 1 0 2.4H8.5'/%3E%3Cpath d='M13 13v3.5h1a1.75 1.75 0 0 0 0-3.5z'/%3E%3C/svg%3E");
}

.nav-icon-file-signature {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 3H7a1.5 1.5 0 0 0-1.5 1.5v15A1.5 1.5 0 0 0 7 21h6'/%3E%3Cpath d='M14 3v4.5h4.5'/%3E%3Cpath d='m20.5 13.5-5.5 5.5-2.5.6.6-2.5 5.5-5.5z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 3H7a1.5 1.5 0 0 0-1.5 1.5v15A1.5 1.5 0 0 0 7 21h6'/%3E%3Cpath d='M14 3v4.5h4.5'/%3E%3Cpath d='m20.5 13.5-5.5 5.5-2.5.6.6-2.5 5.5-5.5z'/%3E%3C/svg%3E");
}

.nav-icon-floppy-disk {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 5.5A1 1 0 0 1 5.5 4.5h10L19.5 8.5v10a1 1 0 0 1-1 1h-13a1 1 0 0 1-1-1z'/%3E%3Cpath d='M8 4.5v4h6v-4'/%3E%3Crect x='8' y='13' width='8' height='6.5'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 5.5A1 1 0 0 1 5.5 4.5h10L19.5 8.5v10a1 1 0 0 1-1 1h-13a1 1 0 0 1-1-1z'/%3E%3Cpath d='M8 4.5v4h6v-4'/%3E%3Crect x='8' y='13' width='8' height='6.5'/%3E%3C/svg%3E");
}

.nav-icon-phone {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 4h3l1.5 4-2 1.5a11 11 0 0 0 5.5 5.5l1.5-2 4 1.5v3a1.5 1.5 0 0 1-1.6 1.5A15.5 15.5 0 0 1 5 6.1 1.5 1.5 0 0 1 6.5 4z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 4h3l1.5 4-2 1.5a11 11 0 0 0 5.5 5.5l1.5-2 4 1.5v3a1.5 1.5 0 0 1-1.6 1.5A15.5 15.5 0 0 1 5 6.1 1.5 1.5 0 0 1 6.5 4z'/%3E%3C/svg%3E");
}

.nav-icon-stop {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.5'/%3E%3Crect x='9' y='9' width='6' height='6' rx='1'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.5'/%3E%3Crect x='9' y='9' width='6' height='6' rx='1'/%3E%3C/svg%3E");
}

.nav-icon-house {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 11 12 4.5l8.5 6.5'/%3E%3Cpath d='M6 10v10h12V10'/%3E%3Cpath d='M9.5 15h5v3.5h-5z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 11 12 4.5l8.5 6.5'/%3E%3Cpath d='M6 10v10h12V10'/%3E%3Cpath d='M9.5 15h5v3.5h-5z'/%3E%3C/svg%3E");
}

.nav-icon-info {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.5'/%3E%3Cpath d='M12 11v5.5M12 7.6v.6'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.5'/%3E%3Cpath d='M12 11v5.5M12 7.6v.6'/%3E%3C/svg%3E");
}

.nav-icon-warning {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4 2.8 20h18.4z'/%3E%3Cpath d='M12 10v4.5M12 17.4v.6'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4 2.8 20h18.4z'/%3E%3Cpath d='M12 10v4.5M12 17.4v.6'/%3E%3C/svg%3E");
}

.nav-icon-pen {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h4L19.5 8.5a2.1 2.1 0 0 0-3-3L5 17v3z'/%3E%3Cpath d='M14.5 6.5l3 3'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h4L19.5 8.5a2.1 2.1 0 0 0-3-3L5 17v3z'/%3E%3Cpath d='M14.5 6.5l3 3'/%3E%3C/svg%3E");
}

.nav-icon-trash {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6.5h16M9.5 6.5V4h5v2.5'/%3E%3Cpath d='M6.5 6.5 7.5 20h9l1-13.5'/%3E%3Cpath d='M10.5 10v6M13.5 10v6'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6.5h16M9.5 6.5V4h5v2.5'/%3E%3Cpath d='M6.5 6.5 7.5 20h9l1-13.5'/%3E%3Cpath d='M10.5 10v6M13.5 10v6'/%3E%3C/svg%3E");
}

.nav-icon-plus {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round'%3E%3Cpath d='M12 5v14M5 12h14'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round'%3E%3Cpath d='M12 5v14M5 12h14'/%3E%3C/svg%3E");
}

.nav-icon-check {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5 10 17.5 19 7'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5 10 17.5 19 7'/%3E%3C/svg%3E");
}

.nav-icon-cross {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6 6 18'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6 6 18'/%3E%3C/svg%3E");
}

.nav-icon-minus {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round'%3E%3Cpath d='M6 12h12'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round'%3E%3Cpath d='M6 12h12'/%3E%3C/svg%3E");
}

.nav-icon-download {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3v12M7 11l5 5 5-5M4 20h16'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3v12M7 11l5 5 5-5M4 20h16'/%3E%3C/svg%3E");
}

.pill-open {
  background: var(--surface-alt);
  color: var(--text-muted);
  border: 1px solid var(--border);
}

.pill-done {
  background: var(--good-bg);
  color: var(--good);
}

.pill-failed {
  background: var(--bad-bg);
  color: var(--bad);
}

.metric-scroll-title > .pill {
  flex: none;
}

/*
 * Symbols of the time tracking. The tool used Font Awesome (fa-circle-play, fa-circle-pause,
 * fa-user-secret, fa-mobile, fa-desktop); here they stand as an SVG mask like the rest, so they
 * take on the colour of the link and no font library is needed.
 */
.nav-icon-play {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M10 8.5l6 3.5-6 3.5z' fill='%23000'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M10 8.5l6 3.5-6 3.5z' fill='%23000'/%3E%3C/svg%3E");
}

.nav-icon-pause {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M10 8.5v7M14 8.5v7' stroke-linecap='round'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M10 8.5v7M14 8.5v7' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* Somebody else's name: a person is working on another's behalf. */
.nav-icon-login-as {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8' r='3.5'/%3E%3Cpath d='M4.5 20a7.5 7.5 0 0 1 15 0'/%3E%3Cpath d='M3 11h18'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='8' r='3.5'/%3E%3Cpath d='M4.5 20a7.5 7.5 0 0 1 15 0'/%3E%3Cpath d='M3 11h18'/%3E%3C/svg%3E");
}

.nav-icon-mobile {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='7' y='2.5' width='10' height='19' rx='2'/%3E%3Cpath d='M11 18.5h2'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='7' y='2.5' width='10' height='19' rx='2'/%3E%3Cpath d='M11 18.5h2'/%3E%3C/svg%3E");
}

.nav-icon-desktop {
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='4' width='19' height='12' rx='2'/%3E%3Cpath d='M8 20h8M12 16v4'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='4' width='19' height='12' rx='2'/%3E%3Cpath d='M8 20h8M12 16v4'/%3E%3C/svg%3E");
}

/* Clocking in and out is the page's action - the button takes the full width. */
.time-tracking-status .status-card .button-large {
  width: 100%;
  margin-top: 1.5rem;
  padding: 1rem;
  justify-content: center;
  font-size: 1.4rem;
  font-weight: bold;
}

/*
 * Filled instead of merely outlined: in the tool this is the only large button on the page and
 * carries the colour of the action. The house's outline style stays for all other buttons.
 */
.time-tracking-status .status-card .button-large.button-danger {
  background: var(--ze-error);
  border-color: var(--ze-error);
  color: #fff;
}

.time-tracking-status .status-card .button-large.button-danger:hover {
  background: #bd2130;
  border-color: #bd2130;
  color: #fff;
}

.time-tracking-status .status-card .button-large.button-success {
  background: var(--ze-success);
  border-color: var(--ze-success);
  color: #fff;
}

.time-tracking-status .status-card .button-large.button-success:hover {
  background: #1e7e34;
  border-color: #1e7e34;
  color: #fff;
}

/* A button that only holds the space - the next day lies in the future. */
.button.is-disabled,
.button[disabled] {
  opacity: .55;
  cursor: default;
  pointer-events: none;
}

/* The buttons in the card may be smaller than usual - there are three of them in a tight space. */
.board-entry .entry-actions .button {
  padding: 3px 8px;
  font-size: 12px;
}

.board-entry .entry-actions .button.button-icon {
  padding: 3px 6px;
}

/* Buttons carrying only an icon - in the tool, edit and delete are exactly that. */
.button.button-icon {
  padding: 5px 8px;
  line-height: 1;
}

.button.button-icon .nav-icon {
  vertical-align: -3px;
}

/*
 * Yes/no in a table column: a tick or a cross says it faster than a word. The meaning stands
 * there as text as well - for the screen reader only, see .field-note-hidden.
 */
.state-icon {
  display: inline-block;
  width: 18px;
  height: 18px;
  vertical-align: -3px;
}

.state-icon.is-good {
  background-color: var(--good);
}

.state-icon.is-bad {
  background-color: var(--bad);
}

.state-icon.is-muted {
  background-color: var(--text-muted);
}

.todo-overlay-content .todo-icon-button .nav-icon {
  margin: 0;
  vertical-align: 0;
}

.todo-work-note > summary .nav-icon {
  width: 13px;
  height: 13px;
  vertical-align: -2px;
  margin-right: .2rem;
}

/* ------------------------------------------------------------------ Overlays */

/*
 * Overlays lie over the page until they are clicked away. The rules used to hang on
 * #downloads-overlay; since there is a second one (the image view of the article detail page)
 * they sit on the class the markup already carried anyway.
 */
.overlay {
  position: fixed;
  inset: 0;
  z-index: 10001;
  display: none;
  align-items: flex-start;
  justify-content: center;
  padding: calc(var(--nav-height) + 24px) 16px 16px;
  background: rgba(31, 41, 51, .45);
}

.overlay.is-open {
  display: flex;
}

.overlay .overlay-content {
  width: 100%;
  max-width: min(1200px, 96vw);
  max-height: 78vh;
  overflow-y: auto;
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}

/*
 * The image overlay - nine tenths of the window.
 *
 * Started at half, went by way of three quarters to here. That sufficed in the article
 * administration, where one wants to recognise an image; in the photo studio one decides by it
 * whether a backlabel is legible. Not the full width: the dark border all around says that a page
 * still lies beneath - without it, it looks like one of its own.
 */
#image-overlay .overlay-content {
  width: auto;
  max-width: 90vw;
  max-height: 90vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.report-overlay-content .overlay-head,
.request-overlay-content .overlay-head,
.todo-overlay-content .overlay-head,
.todo-form-overlay-content .overlay-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--border);
}

.report-overlay-content .overlay-head h2,
.request-overlay-content .overlay-head h2,
.todo-overlay-content .overlay-head h2,
.todo-form-overlay-content .overlay-head h2 {
  margin: 0;
  font-size: 1.1rem;
}

.report-overlay-content .overlay-body,
.request-overlay-content .overlay-body,
.todo-overlay-content .overlay-body,
.todo-form-overlay-content .overlay-body {
  padding: 18px 20px;
}

.report-overlay-content .overlay-foot,
.request-overlay-content .overlay-foot,
.todo-form-overlay-content .overlay-foot {
  display: flex;
  gap: 8px;
  padding: 14px 20px;
  border-top: 1px solid var(--border);
}

/*
 * The position of an image - in the same row as the types, right beside them.
 *
 * A narrow field with the label before it: the number has at most three digits, and a field over
 * half the width would be a promise of more.
 *
 * margin-left: auto stood here, which pushed it to the right end of the block. In a wide window
 * two hand widths then lay between the types and the position, and it looked as though it did not
 * belong. The spacing on the left sets it apart without pushing it away.
 */
.release-position {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: 12px;
  padding-left: 12px;
  border-left: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 13px;
}

/*
 * A number field with a button left and right.
 *
 * The arrows a number field brings along are small, different in every browser and impossible to
 * hit on a tablet. Whoever sorts twenty images needs a surface. They sit at the edges of the
 * field and share its border - see Admin.initSteppers().
 */
.stepper {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  overflow: hidden;
}

.stepper-button {
  width: 28px;
  padding: 0;
  border: 0;
  background: var(--surface-alt);
  color: var(--text);
  font-size: 15px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
}

.stepper-button:hover {
  background: var(--brand);
  color: #fff;
}

/* The field sits inside the group's border - one of its own would be a second. */
.stepper .release-position-input {
  width: 3.5rem;
  min-width: 3.5rem;
  height: 30px;
  border: 0;
  border-radius: 0;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* The browser's arrows are replaced - the same thing twice would be one too many. */
.stepper .release-position-input::-webkit-outer-spin-button,
.stepper .release-position-input::-webkit-inner-spin-button {
  margin: 0;
  -webkit-appearance: none;
}

.stepper .release-position-input {
  -moz-appearance: textfield;
  appearance: textfield;
}

/*
 * The report from the photo studio.
 *
 * A title, a text area, two buttons - narrow like the other form overlays. The base width of
 * 1200px belongs to the overlays that show a list.
 */
.overlay .report-overlay-content {
  max-width: min(38rem, 94vw);
}

/* --- Time-tracking requests in the overlay ------------------------------ */

.overlay .todo-overlay-content {
  max-width: min(52rem, 94vw);
}

.todo-overlay-content .overlay-head h2 .hint {
  margin-left: .4rem;
  color: var(--ze-dark-grey);
  font-size: .8rem;
  font-weight: normal;
}

/* --- Creating and editing a task in the overlay ------------------------- */

.overlay .todo-form-overlay-content {
  max-width: min(46rem, 94vw);
}

/* ----------------------------------------------------------- Embedded pages */

/* The frame fills the rest of the window, the top and sub-module navigation
   stay put. The embedded script itself stays unchanged. */
.embed-body {
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
  /* The fixed bars lie above it - this much room they need. */
  padding-top: calc(var(--nav-height) + var(--sub-nav-height));
}

.embed-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex: 0 0 auto;
  padding: 7px 24px;
  background: var(--surface-alt);
  border-bottom: 1px solid var(--border);
}

.embed-title {
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .5px;
  text-transform: uppercase;
}

.embed-link {
  color: var(--text-muted);
  font-size: 12px;
}

.embed-link:hover {
  color: var(--brand-dark);
}

/* Search field in the bar above the embedded page. */
.embed-search {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1 1 auto;
  min-width: 0;
}

.embed-frame {
  flex: 1 1 auto;
  width: 100%;
  min-height: 0;
  border: 0;
  background: var(--surface);
}

/* ------------------------------------------------------------------- Sign-in */

.brand-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--brand);
  box-shadow: 0 0 0 3px rgba(87, 169, 0, .25);
  display: inline-block;
}

.login-body {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 24px;
}

.login-panel {
  width: 100%;
  max-width: 380px;
  padding: 30px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}

.login-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 24px;
  font-size: 17px;
  font-weight: 600;
}

.login-form {
  display: flex;
  flex-direction: column;
}

.login-submit {
  justify-content: center;
  margin-top: 24px;
}

.login-error {
  margin-bottom: 18px;
  padding: 11px 14px;
  background: var(--bad-bg);
  border: 1px solid var(--bad);
  border-left-width: 4px;
  border-radius: var(--radius-sm);
  color: #8c1c1c;
  font-size: 13px;
}

.login-notice {
  margin-bottom: 18px;
  padding: 11px 14px;
  background: var(--good-bg);
  border: 1px solid var(--good);
  border-left-width: 4px;
  border-radius: var(--radius-sm);
  color: #1e7a33;
  font-size: 13px;
}

.login-intro {
  margin: 0 0 4px;
  color: var(--text-muted);
  font-size: 13px;
  line-height: 1.5;
}

.login-links {
  margin-top: 18px;
  text-align: center;
  font-size: 13px;
}

.login-form + .login-links {
  margin-top: 20px;
}

.login-links a {
  color: var(--text-muted);
  text-decoration: none;
}

.login-links a:hover {
  color: var(--brand-dark);
  text-decoration: underline;
}

/*
 * The name currently being worked under. It stays visible so nobody books in somebody else's
 * name by accident.
 */
.login-as-hint {
  color: var(--warning, #b26a00);
}

.login-as-name {
  margin-left: 4px;
  font-size: 12px;
  font-weight: 600;
}

/* --- Signing in as somebody else ---------------------------------------- */

/*
 * The hint stands on every page of the time tracking. Whoever overlooks it books in another's
 * name - which is why it catches the eye.
 */
.login-as-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
  padding: 10px 14px;
  border: 1px solid var(--ze-orange);
  border-radius: var(--radius);
  background: rgba(255, 119, 0, .15);
}

.login-as-banner form {
  margin: 0 0 0 auto;
}

.login-as-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 8px;
}

.login-as-list form {
  margin: 0;
}

.login-as-entry {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: var(--text);
}

.login-as-entry:hover {
  background: var(--surface-alt);
}

/* Who is currently being worked as - the entry stands out. */
.login-as-entry.acting {
  border-color: var(--ze-orange);
  background: rgba(255, 119, 0, .12);
}

.login-as-entry .avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 2rem;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  color: #fff;
  font-size: .8rem;
  font-weight: bold;
}

.login-as-entry .entry-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.login-as-entry .entry-text .name {
  font-weight: 600;
}

.login-as-entry .entry-text .detail {
  color: var(--text-muted);
  font-size: .85rem;
}

.login-as-entry .entry-state {
  margin-left: auto;
  color: var(--text-muted);
  font-size: .85rem;
}

/* ---------------------------------------------------------------- Monitoring */

.monitoring-status {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 18px;
  color: var(--text-muted);
  font-size: 13px;
}

.metric-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
  gap: 16px;
  margin-bottom: 28px;
}

.metric-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}

.metric-title {
  font-size: 16px;
  font-weight: 700;
}

.metric-subtitle,
.metric-hint {
  color: var(--text-muted);
  font-size: 11px;
}

.metric-value {
  font-size: 26px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}

.metric-value.second {
  margin-top: 16px;
}

.metric-unit {
  display: block;
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .5px;
  text-transform: uppercase;
}

.metric-delta {
  display: inline-block;
  margin-top: 4px;
  padding: 1px 8px;
  border-radius: 99px;
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.metric-delta.up {
  background: var(--good-bg);
  color: var(--good);
}

.metric-delta.down {
  background: var(--bad-bg);
  color: var(--bad);
}

.metric-delta.flat {
  background: var(--surface-alt);
  color: var(--text-muted);
}

.metric-reference {
  margin-top: 3px;
  color: var(--text-muted);
  font-size: 12px;
}

.metric-rows {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 12px;
  margin: 16px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-size: 13px;
}

.metric-rows dt {
  color: var(--text-muted);
}

.metric-rows dd {
  margin: 0;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.metric-backlog {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-size: 13px;
}

.metric-backlog-title {
  display: block;
  margin-bottom: 6px;
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .5px;
  text-transform: uppercase;
}

.metric-backlog-list {
  margin: 0;
  padding-left: 18px;
}

.metric-backlog-list li {
  margin-bottom: 2px;
}

/*
 * The overview: summary, shipping state and the list of orders not yet transferred stand three
 * abreast in the first row, the overdue delivery dates move below. Columns of equal width, so the
 * row feels calm.
 *
 * No align-items: start - the tiles of a row should be of equal height. The stretching is done by
 * the default value stretch, the tiles themselves are flex columns (see .metric-card).
 */
/* Four tiles in one row: summary, delivery dates, invoices, not in LISA. */
.metric-grid.overall {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

/*
 * A list inside a tile that may scroll, instead of pulling the card out lengthwise.
 *
 * flex: 1 lets it fill the room the equally tall tile leaves over; min-height: 0 is needed for
 * that, or a flex child grows beyond its content and does not scroll. The maximum height caps the
 * tile when it stands alone in its row.
 */
.metric-scroll-list {
  flex: 1 1 auto;
  min-height: 0;
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
  max-height: 320px;
  overflow-y: auto;
  border-top: 1px solid var(--border);
}

.metric-scroll-list li {
  border-bottom: 1px solid var(--border);
}

.metric-scroll-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 4px;
  color: inherit;
  text-decoration: none;
}

.metric-scroll-link:hover {
  background: var(--surface-alt);
}

.metric-scroll-main,
.metric-scroll-side {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

/*
 * Takes the room between the order number and the values on the right. Without flex the block
 * shrank to its content, and depending on card width a gap of several hundred pixels yawned in
 * the row. min-width: 0 (set above) lets the text be shortened instead.
 */
.metric-scroll-main {
  flex: 1 1 auto;
  overflow: hidden;
}

.metric-scroll-main strong {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.metric-scroll-side {
  align-items: flex-end;
  text-align: right;
  flex: 0 0 auto;
}

/*
 * Two cards side by side, of equal width.
 *
 * The free .metric-grid fills the row by available room - with four cards that puts sometimes one
 * and sometimes three in a line depending on the window width, and what belongs together is torn
 * apart. With two fixed columns pair stands under pair.
 */
.metric-grid.grid-two {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/*
 * Three cards of equal width - the ratings.
 *
 * Without this rule they fell to three columns at 1,400 px and to two at 1,200 px, and the third
 * then sat alone below the other two, stretched over half the page. Below 900 px the default
 * further down applies again, so one below the other.
 */
.metric-grid.grid-three {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media (max-width: 900px) {
  .metric-grid.grid-three {
    grid-template-columns: 1fr;
  }
}

/* Two cards of equal width - list and history of the image uploads side by side. */
.metric-grid.upload-grid-two {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/*
 * The cards of the order: two side by side, below one another on narrow windows.
 *
 * Without align-items both stretch to the height of the taller one - with "start" the shorter
 * one used to stand beside it as a stump.
 */
.metric-grid.order-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/*
 * Order number and marking side by side. .metric-scroll-main is a flex column, where every child
 * would get a row of its own - and the badge would stretch across the whole width.
 */
.metric-scroll-title {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

/* The number may be shortened, the badge beside it may not. */
.metric-scroll-title > strong {
  min-width: 0;
}

/*
 * A row with an extra button: the link to the order takes the room, the button stands to its
 * right. It sits beside the link and deliberately not inside it - nested links are not valid
 * HTML.
 */
.metric-scroll-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.metric-scroll-row > .metric-scroll-link {
  flex: 1 1 auto;
  min-width: 0;
}

.metric-scroll-shopify {
  flex: none;
  /* Kept tight: every pixel here is one the order row beside it goes without. */
  padding: 3px 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 4px);
  background: var(--surface-alt);
  color: var(--text-muted);
  font-size: 10px;
  font-weight: 600;
  white-space: nowrap;
  text-decoration: none;
}

.metric-scroll-shopify:hover {
  border-color: var(--brand);
  color: var(--brand-dark);
}

/* --- Shipping reports: change the state per row ------------------------- */

/*
 * `.field-input` gives every control `width: 100%`. In the action column, which takes its width
 * from its content, that drives select and column up against each other - measured 233 px instead
 * of the 120 px the longest entry needs, and the table got a horizontal scrollbar from it. Here
 * the content counts, not the cell.
 */
.shipment-status-select {
  width: auto;
  max-width: 100%;
}

/* ---------------------------------------------------------------- My exports */

/* A little air between heading and form. */
.export-form {
  margin-top: 18px;
}

.downloads-panel {
  padding: 18px 20px;
}

.downloads-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}

.downloads-title {
  font-size: 17px;
  font-weight: 600;
}

.downloads-head-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.downloads-empty {
  margin: 0;
  color: var(--text-muted);
}

.downloads-table-scroll {
  overflow-x: auto;
}

.downloads-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.downloads-table th {
  padding: 8px 10px;
  background: var(--surface-alt);
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
  text-align: left;
  text-transform: uppercase;
  white-space: nowrap;
}

.downloads-table td {
  padding: 9px 10px;
  border-top: 1px solid var(--border);
  vertical-align: middle;
  white-space: nowrap;
}

.downloads-table .downloads-file {
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* If the cell carries a note it may grow - otherwise the sentence falls off the table. */
.downloads-table .downloads-file:has(.downloads-note) {
  white-space: normal;
  overflow: visible;
}

/*
 * What a run did, under the file name.
 *
 * A line of its own and quieter than the name above it: it is an aside, not what one came for. The
 * cell cuts overlong names off with an ellipsis - this note must not be cut, so it gets its own
 * line and is allowed to wrap.
 */
.downloads-table .downloads-note {
  display: block;
  margin-top: 2px;
  color: var(--text-muted);
  font-size: 11px;
  white-space: normal;
}

/* The name may wrap - that keeps room on the right for the buttons. */
.downloads-table .downloads-name {
  max-width: 230px;
  white-space: normal;
}

.downloads-table td,
.downloads-table th {
  padding-right: 8px;
}

.downloads-actions {
  display: flex;
  gap: 6px;
  justify-content: flex-end;
}

/*
 * Feedback at the bottom right. It lies over the page but takes no clicks - one should be able to
 * go on working while it is still standing.
 */
.meldungskarte {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 10002;
  max-width: min(420px, calc(100vw - 40px));
  padding: 12px 16px;
  background: var(--surface);
  border-left: 4px solid var(--brand);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
}

.meldungskarte.is-open {
  opacity: 1;
  transform: translateY(0);
}

.meldungskarte.is-error {
  border-left-color: var(--bad);
}

/*
 * The foot of the line card: the changes on the left, the total on the right.
 *
 * Both used to stand one below the other, which put the button and the amount it recomputes half a
 * card height apart. In one row both stay in view.
 *
 * Aligned to the top and not centred: the total is three lines high, the button one - centred, the
 * button hung next to the tax line instead of next to the first one.
 */
.review-foot {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  margin-top: 28px;
  flex-wrap: wrap;
}

.review-foot > .review-actions {
  margin: 0;
}

/*
 * The total stands on the right - all of it, hint included.
 *
 * The gap of the row carries the block there, but only as long as the button beside it leaves
 * room. margin-left: auto holds it at the right edge even when it does not - and the list inside
 * lines up with the same edge as the amounts in it.
 */
.review-foot > .review-summary {
  margin: 0 0 0 auto;
  text-align: right;
}

.review-foot > .review-summary dl {
  margin-left: auto;
  min-width: 260px;
}

@media (max-width: 700px) {
  .review-foot {
    flex-direction: column;
  }

  .review-foot > .review-summary {
    width: 100%;
  }
}

/*
 * The unrecognised rows - collapsed, with the heading as the handle.
 *
 * They stand on top, because the first thing one wants to know is whether something is missing;
 * expanded they pushed the order screens further down on a large file. So only how many there are
 * stands there, and whoever wants to see them clicks.
 *
 * The pointer on the whole head and not only on the triangle: the heading is the handle, and a
 * handle one can only grasp at one corner does not look like one.
 */
.review-rejected > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  cursor: pointer;

  /*
   * Our own arrow sits on the right; the built-in one would sit on the left.
   *
   * On the left it falls in front of the heading and indents it - and the hand looks for it on
   * the right when the head takes the whole width. Both list-style and the Webkit marker have to
   * go: the browsers bring it along by two different routes.
   */
  list-style: none;
}

.review-rejected > summary::-webkit-details-marker {
  display: none;
}

.review-rejected > summary::after {
  content: '';
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--text-muted);
  border-bottom: 2px solid var(--text-muted);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 0.15s ease;
}

.review-rejected[open] > summary::after {
  transform: rotate(-135deg) translate(-2px, -2px);
}

.review-rejected > summary:hover::after,
.review-rejected > summary:focus-visible::after {
  border-color: var(--brand);
}

.review-rejected > summary:hover .card-title,
.review-rejected > summary:focus-visible .card-title {
  color: var(--brand);
}

/* Heading and hint stand in one column on the left, the arrow beside them on the right. */
.review-rejected > summary > div {
  margin-right: auto;
}

.review-rejected > summary .card-title {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
}

.review-rejected > summary .card-hint {
  margin: 4px 0 0;
}

/* Expanded, the content needs air from the head - otherwise the hint sticks to the heading. */
.review-rejected[open] > summary {
  margin-bottom: 14px;
}

/* -------------------------------------------------------- Order confirmation */

/*
 * The confirmation as a grid: details on the left, the total on the right and the closing below it.
 *
 * Details, total and buttons stood as three cards one below the other - between the address and
 * the button lay two card edges and a screen. What belongs to the decision belongs in one field
 * of view.
 *
 * The right column has a fixed width: it carries amounts, and those need no width that grows with
 * the window. The left takes what is left over.
 */
/*
 * The confirmation page's bottom part - two cards side by side.
 *
 * On the left what makes up the order, on the right what it costs and the way out. The cards drop
 * their own bottom margin here, the gap sets the distance - two spacings on top of one another
 * would pull the right column out of line with the left one.
 */
.confirm-grid {
  display: grid;
  /* Two to one - the right column holds figures and two buttons, not a fixed strip. */
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: 22px;
  align-items: start;
  margin-bottom: 22px;
}

.confirm-grid > .card {
  margin-bottom: 0;
}

/* Both cards the same height, however long the details run. */
.confirm-grid > .card {
  align-self: stretch;
}

/*
 * In its own card the total has the whole width. The auto margin is there for the review page,
 * where the figures stand under a wide table; here it would push them off their own card.
 */
.confirm-grid .review-summary dl {
  max-width: none;
  margin-left: 0;
}

/* Figures above, the way out below - with air between them, not a card edge. */
.confirm-grid > .confirm-close .review-summary {
  margin-bottom: 22px;
}

/*
 * Buttons and warning to the right, like the figures above them. The card's right edge is the line
 * everything in it lines up on; a button starting at the left would be the only thing out of it.
 */
.confirm-grid > .confirm-close .form-actions {
  justify-content: flex-end;
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
  flex-wrap: wrap;
}

/*
 * Nothing below the buttons any more.
 *
 * `form > .form-actions:last-child` adds 22px, so that a form closing with its button row does not
 * stick to whatever follows. By its own comment it is not meant for a row inside a card - that one
 * closes with the card's padding - but the selector cannot see the card. Since the warning moved
 * above the buttons they are the last child here and took the margin along with them.
 */
.confirm-grid > .confirm-close form > .form-actions:last-child {
  margin-bottom: 0;
}

/* The warning stands above the button and keeps its distance from it. */
.confirm-grid > .confirm-close .field-hint {
  margin: 0 0 12px;
  text-align: right;
}

/*
 * Narrow, the grid becomes one column, and the order is that of the markup: details first, then
 * total and button - one reads what is ordered, what it costs, and decides then.
 */
@media (max-width: 860px) {
  .confirm-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .confirm-grid > .card {
    grid-column: 1;
  }
}

/*
 * After sending - the page the order is confirmed on.
 *
 * Three figures at the top, underneath what happens next and, where it is asked for, the rating.
 * The metric cards of the house are laid out for a monitoring board and take 400px each; here they
 * hold an order number, a count and an amount, and three of those fit in a row on a laptop.
 */
.page-done .metric-grid {
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  margin-bottom: 22px;
}

/*
 * The two ways on, at the foot of the page.
 *
 * Without the line above them: form-actions draws one where it closes a form, and here there is no
 * form - the line would run under the cards and separate nothing.
 */
.done-actions {
  padding-top: 0;
  border-top: 0;
}

/*
 * Delivery, payment and note - three details that do not stand in the table.
 *
 * As a row and not as a list one below the other: they are skimmed, not read, and side by side one
 * sees with a single glance whether everything is right.
 */
.confirm-details {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 18px 24px;
  margin: 0;
}

.confirm-details dt {
  margin: 0 0 4px;
  color: var(--text-muted);
  font-size: 12px;
}

.confirm-details dd {
  margin: 0;
  line-height: 20px;
}

/* -------------------------------------------------------- Customer interface */

/*
 * The rhythm of the developer page.
 *
 * Headings carry no margin in this house, and the building blocks of this page - filter bar,
 * table, example block, field - bring none along either. On other pages a paragraph that has one
 * stands in between; here they butt against each other. So the spacing is written out here once
 * instead of arising from whatever happens to stand beside it.
 *
 * Limited to .page-developer: the same building blocks stand on many pages of the house, and what
 * looks right there cannot be checked from here.
 */
.page-developer .card > h2 {
  margin-bottom: 14px;
}

.page-developer .card > .filter-bar {
  margin-bottom: 14px;
}

/*
 * The figures of "Wie es laeuft".
 *
 * A moment in time is not a number: set bold at 26 pixels it burst the card, while the three
 * counters beside it live on exactly that. Hence a second size for the one case.
 */
.page-developer .card > .metric-grid {
  margin-bottom: 18px;
}

.page-developer .metric-value.is-text {
  font-size: 17px;
  font-weight: 600;
}

.page-developer .card > .table-scroll,
.page-developer .card > .data-table {
  margin-top: 0;
}

/* The head of a detail below the list - it otherwise sits on the table. */
.page-developer .card > h3 {
  margin: 22px 0 8px;
}

/* The field with the freshly generated key. */
.page-developer .card > .field {
  margin-top: 14px;
}

/* The hint below the button. */
.page-developer .card > .form-actions + .field-hint {
  margin-top: 10px;
}

/*
 * The freshly generated key - the only moment in which it is readable.
 *
 * Field and warning stand in one block because they belong together: the key to take away and
 * right below it the sentence that there is no second time. The border lifts it out of the card
 * without shouting - what stands here is important, but it is not an error.
 */
.page-developer .key-fresh {
  margin-bottom: 18px;
  padding: 16px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius);
  background: var(--surface);
}

.page-developer .key-fresh .field-label {
  display: block;
  margin-bottom: 6px;
}

.page-developer .key-fresh .field-code {
  width: 100%;
}

.page-developer .key-fresh-warning {
  margin: 10px 0 0;
  color: var(--text-muted);
  font-size: 12px;
  line-height: 18px;
}

/*
 * The key in force: itself first, large enough to read off, with its state beside it. The dates
 * stand as a hint line below - they answer a question one has afterwards.
 */
.page-developer .key-current {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.page-developer .key-current-prefix {
  font-family: ui-monospace, "SFMono-Regular", "Menlo", monospace;
  font-size: 15px;
  letter-spacing: 0.3px;
}

.page-developer .key-current + .field-hint {
  margin-top: 6px;
}

/* No key there yet - then the sentence carries the card until the button is pressed. */
.page-developer .key-none {
  margin: 0;
}

/*
 * The row whose detail is currently standing below.
 *
 * Without it one no longer knows after expanding which of fifty rows the block belongs to - the
 * jump there is short, and the list above keeps looking the same.
 */
.page-developer .data-table tr.is-open > td {
  background: var(--highlight-bg);
}

.page-developer .data-table tr.is-open > td:first-child {
  box-shadow: inset 3px 0 0 var(--brand);
}

.page-developer #request-detail[hidden] {
  display: none;
}

/*
 * The unfolded row.
 *
 * It pushes itself in as a row of its own under the one it belongs to - hence no border all
 * around but only padding inside: the table should not fall apart over it. The line on the left
 * ties it to the row above.
 */
.page-developer .request-detail-row > td {
  padding: 14px 12px 16px;
  background: var(--highlight-bg);
  box-shadow: inset 3px 0 0 var(--brand);
}

.page-developer .request-detail-row h3 {
  margin: 0 0 8px;
  font-size: 14px;
}

.page-developer .request-detail-row p {
  margin: 10px 0 0;
}


/*
 * One section of the interface description: heading, explanation, example.
 *
 * They used to stand one below the other without spacing - .mail-preview-text carries margin: 0,
 * because in the mail preview it stands alone in its card. Here six of them follow one another,
 * and without air in between the card reads as a single block.
 *
 * The spacing sits on the section and not on the example: that way it also applies where a list or
 * a table stands instead of an example.
 */
.api-section {
  margin-top: 24px;
}

.api-section:first-of-type {
  margin-top: 16px;
}

.api-section h3 {
  margin: 0 0 6px;
}

.api-section .field-hint {
  margin: 0 0 10px;
}

.api-section .data-table {
  margin-top: 4px;
}

/*
 * The way in: four steps in the order one takes them.
 *
 * The numbers are the point - so they stay visible and do not slide under the text of the previous
 * line.
 */
.api-steps {
  margin: 0;
  padding-left: 20px;
}

.api-steps li {
  margin-bottom: 6px;
  line-height: 20px;
}

.api-steps li:last-child {
  margin-bottom: 0;
}

/*
 * An input field inside a table cell.
 *
 * The fields of the house bring a bottom margin along so that they can stand one below the other.
 * In a cell that is a hole under the row, and with ten rows the table grows ten holes longer. The
 * width holds the column together: a price column as wide as the field permits pushes everything
 * beside it out of view.
 */
.field-in-table {
  margin-bottom: 0;
  max-width: 110px;
}

.field-in-table .field-input {
  padding-top: 5px;
  padding-bottom: 5px;
}

/*
 * Paging below a table.
 *
 * Back, where you are, forward. A list of page numbers would be three hundred links for a supplier
 * with fifteen thousand articles; whoever looks for an article searches for it, and whoever pages
 * goes one page further.
 *
 * The position in the middle, so that the two buttons stand at the edges and do not wander when
 * one of them is missing - on the first page there is no back.
 */
.table-paging {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 16px;
}

.table-paging .field-hint {
  margin: 0 auto;
}

/* -------------------------------------------------------------------- Manual */

/*
 * The manual of the two portals.
 *
 * A page of text and not a user interface: narrower than the rest, so the lines do not run over
 * half the width of a screen. Beyond about seventy-five characters the eye loses the next line on
 * the way back.
 */
.page-manual .manual {
  max-width: 760px;
}

.manual-head {
  margin-bottom: 28px;
}

.manual-print {
  margin-top: 12px;
}

/*
 * The table of contents.
 *
 * Two levels, the second indented and quieter. Without bullets - the numbers of the ordered list
 * are enough, and a bullet and a number side by side are two marks for one statement.
 */
.manual-toc {
  margin-bottom: 36px;
  padding: 18px 22px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-alt);
}

.manual-toc h2 {
  margin-bottom: 10px;
  font-size: 15px;
}

.manual-toc ol {
  margin: 0;
  padding-left: 20px;
}

.manual-toc ol ol {
  margin: 2px 0 6px;
  font-size: 13px;
  color: var(--text-muted);
}

.manual-toc a {
  color: inherit;
  text-decoration: none;
}

.manual-toc a:hover {
  text-decoration: underline;
}

/*
 * Chapter and section.
 *
 * The number stands in front of the heading and not inside it: that way it stays on its line when
 * a long heading wraps, and the heading below it does not slide under the number.
 */
.manual-chapter {
  margin-bottom: 40px;
  scroll-margin-top: 80px;
}

.manual-chapter > h2 {
  padding-bottom: 8px;
  border-bottom: 2px solid var(--border);
  font-size: 22px;
}

.manual-section {
  margin-top: 22px;
  scroll-margin-top: 80px;
}

.manual-section > h3 {
  margin-bottom: 6px;
  font-size: 16px;
}

.manual-number {
  display: inline-block;
  min-width: 2.4em;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.manual-lead {
  margin-top: 8px;
  color: var(--text-muted);
}

.manual p,
.manual ul,
.manual ol {
  margin: 8px 0;
  line-height: 1.6;
}

.manual ul,
.manual-steps {
  padding-left: 22px;
}

.manual li {
  margin-bottom: 4px;
}

/* Something one has to know before reading on - hence the line on the left. */
.manual-note {
  margin: 12px 0;
  padding: 10px 14px;
  border-left: 3px solid var(--brand);
  background: var(--surface-alt);
}

/*
 * A template line, unchanged.
 *
 * Fixed pitch, so that semicolon stands under semicolon - whoever types the line off then sees
 * where an empty column is meant.
 */
.manual-code {
  margin: 12px 0;
  padding: 12px 14px;
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface-alt);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  line-height: 1.7;
  white-space: pre;
}

.manual-table-scroll {
  margin: 12px 0;
  overflow-x: auto;
}

.manual-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}

.manual-table th,
.manual-table td {
  padding: 7px 10px;
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: top;
}

.manual-table th {
  font-weight: 700;
}

/*
 * Printing.
 *
 * The manual should be storable as a PDF without a file being built for it. What has no business
 * on paper falls away: the bar, the print button itself, the footer. The links of the table of
 * contents stay - in a PDF they are anchors.
 */
@media print {
  #top-nav-bar,
  .manual-print,
  .portal-foot,
  footer {
    display: none !important;
  }

  .page-manual .manual {
    max-width: none;
  }

  /* A chapter begins on a new page, the first one does not. */
  .manual-chapter {
    break-before: page;
  }

  .manual-chapter:first-of-type {
    break-before: auto;
  }

  /* A heading alone at the foot of a page is no heading. */
  .manual-chapter > h2,
  .manual-section > h3 {
    break-after: avoid;
  }

  .manual-note,
  .manual-code,
  .manual-table-scroll {
    break-inside: avoid;
  }

  .manual-toc {
    background: none;
  }
}

/* --------------------------------------------------------------- Photo studio */

/*
 * A remark in the course of an issue.
 *
 * Several of them stand one below the other - in the list inside a table cell, on the article page
 * inside a card. The line on the left keeps them apart without each needing a box of its own; the
 * last one carries no bottom margin, otherwise the cell would sit crooked.
 */
.issue-note {
  border-left: 2px solid var(--border);
  padding-left: 10px;
  margin-bottom: 10px;
}

.issue-note:last-child {
  margin-bottom: 0;
}

.issue-note .field-hint {
  margin-top: 2px;
}

/*
 * A settled issue on the article page.
 *
 * It stands there so that the second time round one reads why it did not go easily the first time
 * - but it is no longer a task, and should not look like one either. Hence paler than the open
 * case above it and without a border of its own: a second box next to the first would double the
 * weight of the matter.
 *
 * The line on the left separates several of them. The last one carries no bottom margin, otherwise
 * the card would sit crooked at the bottom.
 */
.issue-settled {
  opacity: .75;
  padding-bottom: 12px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--border);
}

.issue-settled:last-of-type {
  padding-bottom: 0;
  margin-bottom: 0;
  border-bottom: 0;
}

/* --- Releasing images ---------------------------------------------------- */

/*
 * One block per image: the view on the left, the type on the right. Large enough to tell front
 * from back - on a postage stamp that is impossible, and it is exactly the question here.
 */
.release-image {
  display: grid;
  grid-template-columns: minmax(180px, 320px) 1fr;
  gap: 20px;
  margin-bottom: 16px;
  padding: 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: var(--radius);
}

/* What is open catches the eye; what already has a type is only there to look at. */
.release-image.is-open {
  border-left-color: var(--brand);
}

.release-image-view {
  display: flex;
  align-items: flex-start;
  justify-content: center;
}

.release-image-view img {
  max-width: 100%;
  max-height: 320px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-alt);
}

.release-image-side {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.release-image-head .field-hint {
  display: block;
  margin-top: 4px;
}

.release-types {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

/*
 * The type as a row of buttons. Radio fields lie beneath them: that way the page gets by without
 * a script, the keyboard operates it by itself, and the browser holds the choice together.
 */
.release-type input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.release-type span {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 9px 14px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 13px;
  cursor: pointer;
}

.release-type span:hover {
  border-color: var(--brand);
}

.release-type input:checked + span {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}

/* Visible where the keyboard points - without an outline the field would be invisible. */
.release-type input:focus-visible + span {
  outline: 2px solid var(--brand-dark);
  outline-offset: 2px;
}

@media (max-width: 720px) {
  .release-image {
    grid-template-columns: 1fr;
  }
}


.image-overlay-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
}

.image-overlay-name {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.image-overlay-body {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  overflow: auto;
}

/* What is left after the head bar and the padding - see .image-overlay-head. */
.image-overlay-body img {
  max-width: 100%;
  max-height: calc(90vh - 90px);
  object-fit: contain;
}

.image-thumb {
  display: block;
  width: 72px;
  height: 72px;
  object-fit: contain;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.image-table .image-name {
  font-weight: 600;
  word-break: break-word;
}

.image-position {
  width: 84px;
}

/* ------------------------------------------------------ Orders and finances */

.pii-state {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}

.pii-changed {
  color: var(--text-muted);
  font-size: 12px;
}

/* ==========================================================================
   Incoming payments: recognised order number and notice
   ========================================================================== */

/*
 * The order number recognised in the payment reference - see OrderReferenceHighlighter.
 *
 * Deliberately not green. Green on this screen means the amount matches the order, and the
 * recognised number says nothing of the kind - it only points at what was found. It wore the brand
 * green before, close enough to the green of a matching amount that the two read as one statement.
 */
mark.order-ref {
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--highlight-bg);
  color: var(--highlight);
  font-weight: 600;
  white-space: nowrap;
  cursor: help;
}

/*
 * Whether the amount matches is carried by the whole row, not only by the badge at its end, so the
 * exceptions can be seen without reading a single number.
 *
 * The tint sits on the row rather than on the cells: hovering paints a translucent grey onto the
 * cells, and that only composites into something readable if it has a colour underneath.
 */
table.data-table tbody tr.amount-match {
  background: var(--good-row);
}

table.data-table tbody tr.amount-mismatch {
  background: var(--bad-row);
}

/* ------------------------------------------------------------------ Articles */

/*
 * The channel prices stand collapsed on the article page - they are lengthy and not wanted on
 * every visit. <details> brings the opening and closing along, and needs no script for it.
 */
.price-details > .price-summary {
  display: flex;
  align-items: baseline;
  gap: 10px;
  cursor: pointer;
  list-style: none;
}

.price-details > .price-summary::-webkit-details-marker {
  display: none;
}

.price-details > .price-summary::before {
  content: '▸';
  color: var(--text-muted);
}

.price-details[open] > .price-summary::before {
  content: '▾';
}

.price-details[open] > .price-summary {
  margin-bottom: 6px;
}

.price-group + .price-group {
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}

.price-group-title {
  margin: 0 0 10px;
  font-size: 15px;
  font-weight: 600;
}

/* Article card of the channel prices: image on the left, details beside it. */
.item-card {
  display: flex;
  align-items: flex-start;
  gap: 16px;
}

.item-card-image {
  flex: 0 0 auto;
  width: 96px;
  height: 96px;
  object-fit: contain;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.item-card-image-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  color: var(--text-muted);
  font-size: 11px;
  text-align: center;
}

.item-card-text {
  min-width: 0;
}

/* ----------------------------------------------------- Time tracking: status */

/* --- Status page -------------------------------------------------------- */

.time-tracking-status {
  /* At a desk there is room - the requests per type need it. */
  max-width: 60rem;
  margin: 0 auto;
}

.time-tracking-status .status-header {
  display: grid;
  grid-template-columns: 1fr auto;
  /* The day navigation stretches to the height of the name column, so no gap is left on the right. */
  align-items: stretch;
  gap: .5rem;
  margin-bottom: 1rem;
}

.time-tracking-status .status-header .employee .name {
  font-size: 1.9rem;
  font-weight: bold;
  line-height: 1.2;
}

.time-tracking-status .date-navigation {
  display: flex;
  align-items: stretch;
  gap: .3rem;
}

.time-tracking-status .date-navigation .date {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 9rem;
  padding: 0 .5rem;
  border: 1px solid var(--ze-grey);
  border-radius: .3rem;
  background-color: var(--ze-light-grey);
  text-align: center;
}

.time-tracking-status .date-navigation .date.today {
  font-weight: bold;
}

.time-tracking-status .status-card {
  padding: 1.5rem;
  border: 1px solid var(--ze-grey);
  border-radius: .5rem;
  background-color: var(--ze-light-grey);
  text-align: center;
}

.time-tracking-status .status-card.active {
  border-color: var(--ze-success);
  background-color: var(--ze-success-bg);
}

.time-tracking-status .status-card .state {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  color: var(--ze-dark-grey);
}

.time-tracking-status .status-card .state .indicator {
  display: inline-block;
  width: .7rem;
  height: .7rem;
  border-radius: 50%;
  background-color: var(--ze-grey);
}

.time-tracking-status .status-card.active .state {
  color: var(--ze-success);
  font-weight: bold;
}

.time-tracking-status .status-card.active .state .indicator {
  background-color: var(--ze-success);
  animation: timeTrackingPulse 2s ease-in-out infinite;
}

.time-tracking-status .status-card .current {
  margin-top: .5rem;
  font-size: 3.5rem;
  font-weight: bold;
  line-height: 1.1;
  /* So the digits do not jump while counting up. */
  font-variant-numeric: tabular-nums;
}

.time-tracking-status .status-card .current-label {
  color: var(--ze-dark-grey);
}

.time-tracking-status .status-card .todo-select {
  margin-top: 1.5rem;
  text-align: left;
}

.time-tracking-status .status-card .todo-select label {
  margin-bottom: .2rem;
  font-weight: bold;
}

/* Notices above the card - absence, home office, a forgotten clock-out. */
.time-tracking-status .status-banner {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-bottom: .5rem;
  padding: .6rem 1rem;
  border-radius: .3rem;
  background-color: var(--ze-blue-bg);
}

.time-tracking-status .status-banner.freetime {
  background-color: rgba(255, 119, 0, .15);
}

.time-tracking-status .status-banner.stale {
  background-color: rgba(238, 255, 110, .3);
}

/* The task of the running booking stands below the clock. */
.time-tracking-status .status-card .todo-current {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  margin-top: 1rem;
  color: var(--ze-dark-grey);
}

.time-tracking-status .status-card .todo-select .no-todo {
  padding: .5rem;
  border-radius: .3rem;
  background-color: rgba(238, 255, 110, .3);
}

.time-tracking-status .worklog-list {
  margin-top: 1.5rem;
}

/* Progress and deviation of the status card - in the tool part of .status-card. */
.time-tracking-status .status-card .progress-bar-container {
  overflow: hidden;
  height: .6rem;
  margin: 1rem 0 .5rem;
  border-radius: .3rem;
  background-color: var(--ze-grey);
}

.time-tracking-status .status-card .progress-bar-container .progress-bar {
  height: 100%;
  background-color: var(--ze-blue);
  transition: width .5s linear;
}

.time-tracking-status .status-card .progress-bar-container .progress-bar.reached {
  background-color: var(--ze-success);
}

.time-tracking-status .status-card .difference {
  font-weight: bold;
}

.time-tracking-status .status-card .difference.positive {
  color: var(--ze-success);
}

.time-tracking-status .status-card .difference.negative {
  color: var(--ze-orange);
}

/* The bookings carry their button to the right of the heading. */
.time-tracking-status .worklog-list {
  margin-top: 1.5rem;
}

.time-tracking-status .worklog-list .sub-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: .3rem;
  font-size: 1.4rem;
  font-weight: bold;
}

/* Note about the breaks below the bookings. */
.time-tracking-status .break-info {
  margin-top: .3rem;
  color: var(--ze-dark-grey);
  font-size: .9rem;
}

/* The delete buttons stand as forms of their own below the table. */
.time-tracking-status .worklog-delete {
  display: inline-block;
  margin: .3rem .3rem 0 0;
}

/* The delete forms of the bookings carry only the data now - the button sits in the row. */
.time-tracking-status .worklog-delete {
  display: none;
}

/* --- Bookings: read first, then edit ------------------------------------ */

/*
 * Both versions stand in the markup, only ever one of them is visible. The fields are disabled on
 * top of that as long as nothing is being edited - hiding alone would still submit them.
 */
.worklog-list .worklog-edit {
  display: none;
}

.worklog-list.is-editing .worklog-edit {
  display: inline-block;
}

.worklog-list.is-editing .worklog-view {
  display: none;
}

/* The buttons of the bookings stand as a group to the right of the heading. */
.worklog-list .worklog-actions {
  display: flex;
  align-items: center;
  gap: .4rem;
}

/* ------------------------------------------------- Time tracking: overview */

/* --- Absence and holiday calendar --------------------------------------- */

.time-tracking-calendar .calendar-filter,
.time-tracking-department .department-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: .75rem;
  margin: 1rem 0;
  padding: .75rem;
  border: 1px solid #dee2e6;
  border-radius: .25rem;
  background: var(--ze-light-grey);
}

.time-tracking-calendar .calendar-filter-actions,
.time-tracking-department .department-filter-actions {
  display: flex;
  align-items: center;
  gap: .5rem;
}

/* --- Department overview ------------------------------------------------- */

.time-tracking-department .department-group {
  margin-bottom: 1.5rem;
  border: 1px solid #dee2e6;
  border-radius: .25rem;
}

.time-tracking-department .department-headline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .5rem .75rem;
  border-bottom: 1px solid #dee2e6;
  background: var(--ze-light-grey);
}

.time-tracking-department .department-name {
  display: flex;
  align-items: center;
  gap: .4rem;
  font-weight: bold;
}

.time-tracking-department .department-name .count {
  padding: 0 .4rem;
  border-radius: .6rem;
  background: var(--ze-grey);
  color: #fff;
  font-size: .75rem;
}

.time-tracking-department .department-figures {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
}

.time-tracking-department .department-figure label,
.time-tracking-department .user-card label {
  display: block;
  color: var(--ze-dark-grey);
  font-size: .75rem;
}

.time-tracking-department .department-users {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
  gap: .75rem;
  padding: .75rem;
}

.time-tracking-department .user-card {
  padding: .6rem;
  border: 1px solid #dee2e6;
  border-radius: .25rem;
  font-size: .85rem;
}

.time-tracking-department .user-card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: .4rem;
  margin-bottom: .5rem;
}

.time-tracking-department .user-card-head .name {
  font-weight: bold;
}

.time-tracking-department .user-card-head .working-hours {
  color: var(--ze-dark-grey);
  font-size: .75rem;
}

.time-tracking-department .user-card-balances,
.time-tracking-department .user-card-figures {
  display: grid;
  gap: .3rem .75rem;
  margin-bottom: .5rem;
}

.time-tracking-department .user-card-balances {
  grid-template-columns: repeat(3, 1fr);
  padding-bottom: .5rem;
  border-bottom: 1px solid #eee;
}

.time-tracking-department .user-card-figures {
  grid-template-columns: repeat(2, 1fr);
}

.time-tracking-department .user-card-week .week-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: .2rem;
  margin-bottom: .5rem;
}

.time-tracking-department .user-card-future {
  margin-bottom: .5rem;
}

.time-tracking-department .user-card-note .note-input {
  width: 100%;
  min-height: 3.5rem;
  margin-bottom: .35rem;
  font-size: .8rem;
  resize: vertical;
}

/* -------------------------------------------- Time tracking: year overview */

/* The metric tiles - .time-tracking-analysis-summary in the tool. */
.time-tracking-analysis-summary {
  display: grid;
  /* At a desk three tiles stand side by side, below that it becomes fewer. */
  grid-template-columns: repeat(3, 1fr);
  gap: .8rem;
  margin-top: 1.5rem;
  margin-bottom: 1.5rem;
}

.time-tracking-analysis-summary .summary-tile {
  padding: 1rem;
  border: 1px solid var(--ze-grey);
  border-left-width: .4rem;
  border-radius: .4rem;
  background-color: var(--ze-light-grey);
}

.time-tracking-analysis-summary .summary-tile .label {
  display: flex;
  align-items: center;
  gap: .4rem;
  color: var(--ze-dark-grey);
}

.time-tracking-analysis-summary .summary-tile .value {
  margin: .2rem 0;
  font-size: 2rem;
  font-weight: bold;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.time-tracking-analysis-summary .summary-tile .hint {
  color: var(--ze-dark-grey);
  font-size: .85rem;
}

.time-tracking-analysis-summary .summary-tile.positive {
  border-left-color: var(--ze-success);
}

.time-tracking-analysis-summary .summary-tile.positive .value {
  color: var(--ze-success);
}

.time-tracking-analysis-summary .summary-tile.negative {
  border-left-color: var(--ze-error);
}

.time-tracking-analysis-summary .summary-tile.negative .value {
  color: var(--ze-error);
}

.time-tracking-analysis-summary .summary-tile.neutral {
  border-left-color: var(--ze-blue);
}

/* Saturday and Sunday step back - there is rarely anything there anyway. */
.time-tracking-time-table .analysis-days tr.weekend td {
  color: var(--ze-dark-grey);
  background: #fbfbfb;
}

/* What is still to come has not happened yet. */
.time-tracking-time-table .analysis-days tr.future td {
  color: #a8a8a8;
}

/* A shortfall catches the eye - the tool holds it that way too. */
.time-tracking-time-table .analysis-days td.minus {
  background: rgba(255, 59, 59, .25);
}

/* ------------------------------------------------- Time tracking: requests */

/* The eight request types - in the tool this was a drop-down above the form. */
.request-type-links {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 14px;
}

/* --- Request in the overlay -------------------------------------------- */

.request-overlay-content {
  max-width: min(760px, 96vw);
}

/* The fields of the chosen type stand below the selection, not beside it. */
.request-overlay-content .request-fields {
  margin-top: 14px;
}

.request-overlay-content .request-fields[hidden] {
  display: none;
}

/* The proofs on file in the request overlay - one button each. */
.request-files {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 6px;
}

/* --------------------------------------------------- Time tracking: calendar */

/* The totals row stands above the table and is exactly as wide - as in the tool. */
.time-tracking-time-table .freetime-detail {
  width: 100%;
}

.time-tracking-calendar .calendar-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  margin-bottom: .5rem;
}

.time-tracking-calendar .calendar-title {
  font-weight: bold;
}

.time-tracking-calendar .calendar-legend {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  font-size: .85rem;
}

.time-tracking-calendar .calendar-legend-entry {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
}

/* One row per calendar week, beside it the six working days. */
.time-tracking-calendar .calendar-row {
  display: flex;
  align-items: stretch;
  margin-bottom: -1px;
}

.time-tracking-calendar .calendar-week-name {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 2.5rem;
  border: 1px solid #dee2e6;
  background: var(--ze-light-grey);
  font-size: .8rem;
  font-weight: bold;
}

.time-tracking-calendar .calendar-days {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  flex: 1;
  min-width: 0;
}

.time-tracking-calendar .calendar-week-day {
  padding: .3rem .5rem;
  border: 1px solid #dee2e6;
  margin-left: -1px;
  background: var(--ze-light-grey);
  font-size: .8rem;
  font-weight: bold;
}

.time-tracking-calendar .calendar-day {
  min-height: 4.5rem;
  padding: .3rem .4rem;
  border: 1px solid #dee2e6;
  margin-left: -1px;
}

.time-tracking-calendar .calendar-day.weekend,
.time-tracking-calendar .calendar-day.holiday {
  background: #fbfbfb;
}

.time-tracking-calendar .calendar-day.today {
  box-shadow: inset 0 0 0 2px var(--ze-orange);
}

.time-tracking-calendar .calendar-day-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .3rem;
  margin-bottom: .25rem;
  font-size: .78rem;
}

.time-tracking-calendar .calendar-day-head .day {
  color: var(--ze-dark-grey);
}

.time-tracking-calendar .calendar-day.today .calendar-day-head .day {
  color: inherit;
  font-weight: bold;
}

.time-tracking-calendar .calendar-day-head .holiday-name {
  overflow: hidden;
  color: var(--ze-error);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.time-tracking-calendar .calendar-day-head .count {
  flex: none;
  padding: 0 .3rem;
  border-radius: .6rem;
  background: var(--ze-grey);
  color: #fff;
  font-size: .7rem;
}

.time-tracking-calendar .calendar-day-entries {
  display: flex;
  flex-direction: column;
  gap: .15rem;
}

/*
 * The colour says the type, the word stands in the title. Unlike on the overview, every entry
 * carries a colour of its own here - in the calendar the type is the actual statement.
 */
.time-tracking-calendar .calendar-entry {
  display: block;
  overflow: hidden;
  padding: .1rem .3rem;
  border-radius: .2rem;
  font-size: .75rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.time-tracking-calendar .calendar-legend-entry .calendar-entry {
  width: .9rem;
  height: .9rem;
  padding: 0;
}

.time-tracking-calendar .calendar-entry.vacation { background: rgba(0, 123, 255, .18); }

.time-tracking-calendar .calendar-entry.timeCompensation { background: rgba(23, 162, 184, .18); }

.time-tracking-calendar .calendar-entry.sick { background: rgba(220, 53, 69, .18); }

.time-tracking-calendar .calendar-entry.nursing { background: rgba(220, 53, 69, .1); }

.time-tracking-calendar .calendar-entry.homeOffice { background: rgba(40, 166, 69, .18); }

/* -------------------------------------------------------------- Notice board */

/* Notice board: the areas as a tab bar, the switches on the right. */
.board-tabs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: 16px;
}

.board-tab-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-left: auto;
}

/*
 * The headings stand side by side at a fixed width, their entries below one another - as in the
 * tool. Fixed width, so the columns do not end up differently wide depending on their content.
 *
 * A row that scrolls sideways instead of wrapping: the columns of an area belong together, and a
 * wrapped column slips underneath another one and is easily overlooked. The room at the bottom
 * belongs to the scrollbar.
 */
.board-headlines {
  display: flex;
  flex-wrap: nowrap;
  align-items: stretch;
  gap: 12px;
  /*
   * The height is set by board.php to whatever is left of the window - that way the board reaches
   * the bottom edge instead of making the whole page scroll. The fallback value takes hold as
   * long as the script has not run yet.
   */
  height: var(--board-height, 70vh);
  overflow-x: auto;
  overflow-y: hidden;
  padding-bottom: 10px;
}

.board-headline {
  display: flex;
  flex: 0 0 20rem;
  flex-direction: column;
  gap: .4rem;
  max-width: 20rem;
  /* Every column reaches the bottom edge; only the entry list inside it scrolls. */
  max-height: 100%;
  padding: .6rem;
  border: 1px solid var(--ze-grey);
  border-radius: .4rem;
  background-color: var(--ze-light-grey);
}

/* The heading stays put while the entries below it run. */
.board-headline .headline-title {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: .3rem;
  margin: 0;
  font-size: .95rem;
  font-weight: bold;
}

.board-headline .headline-title .count {
  padding: .05rem .45rem;
  border-radius: 1rem;
  background-color: var(--ze-grey);
  font-size: .8rem;
  font-weight: normal;
}

.board-headline .headline-title .headline-actions {
  display: flex;
  gap: .2rem;
  margin-left: auto;
}

.board-headline .headline-title .headline-actions form {
  margin: 0;
}

.board-empty {
  margin: 0;
  color: var(--ze-dark-grey);
  font-size: .85rem;
}

.board-entries {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: .5rem;
  /*
   * min-height: 0 is the decisive part: without it a flex child grows to its content and
   * overflows instead of scrolling.
   */
  min-height: 0;
  overflow-y: auto;
  /* Room for the scrollbar, so it does not lie on the cards. */
  padding-right: 4px;
}

/* Every entry is a card of its own; the colour on the left names its type. */
.board-entry {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  padding: .45rem .55rem;
  border: 1px solid var(--ze-grey);
  border-left-width: .3rem;
  border-radius: .4rem;
  background-color: #fff;
}

.board-entry.board-entry-1 {
  border-left-color: var(--ze-blue);
}

.board-entry.board-entry-2 {
  border-left-color: var(--ze-orange);
}

.board-entry.board-entry-3 {
  border-left-color: var(--ze-success);
}

/* Whoever is signed up themselves should find the entry at a glance. */
.board-entry.registered {
  background-color: var(--ze-success-bg);
}

.board-entry .entry-head {
  display: flex;
  justify-content: space-between;
  gap: .5rem;
  color: var(--ze-dark-grey);
  font-size: .8rem;
}

.board-entry .entry-date {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.board-entry .entry-title {
  margin: 0;
  font-size: .95rem;
}

.board-entry .entry-description,
.board-entry .entry-info {
  margin: 0;
  font-size: .85rem;
  line-height: 1.35;
}

.board-entry .entry-info {
  display: flex;
  align-items: center;
  gap: .4rem;
  color: var(--ze-dark-grey);
}

.board-entry .entry-registrations {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .25rem;
  margin: 0;
}

/* One circle per sign-up, with the initials - the full name stands in the title. */
.board-entry .entry-registrations .avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.45rem;
  height: 1.45rem;
  border-radius: 50%;
  color: #fff;
  font-size: .65rem;
  font-weight: bold;
}

.board-entry .entry-registrations .avatar.own {
  box-shadow: 0 0 0 2px var(--text);
}

.board-entry .entry-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .3rem;
  margin-top: auto;
  padding-top: .3rem;
}

.board-entry .entry-actions form {
  margin: 0;
}

.board-entry .entry-deadline {
  width: 100%;
  color: var(--ze-dark-grey);
  font-size: .76rem;
}

/* The images of a board entry - thumbnail, name, delete. */
.board-entry .entry-images {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.board-entry .entry-images img {
  max-width: 100%;
  max-height: 9rem;
  border-radius: .3rem;
}

.board-image-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 6px;
}

.board-image-list .board-image {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.board-image-list .board-image img {
  width: 4rem;
  height: 4rem;
  object-fit: cover;
  border-radius: .3rem;
}

.board-image-list .board-image .name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.board-image-list .board-image form {
  margin-left: auto;
}

/* Those signed up, in the editing overlay - a click on the circle signs them off. */
.registration-avatars {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 6px;
}

.registration-avatars .avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: none;
  border-radius: 50%;
  color: #fff;
  font: inherit;
  font-size: .75rem;
  font-weight: bold;
}

.registration-avatars .avatar.removable {
  cursor: pointer;
}

.registration-avatars .avatar.removable:hover {
  box-shadow: 0 0 0 2px var(--bad);
}

/* The form carries only the data - it is submitted from the overlay. */
.board-registration-remove {
  display: none;
}

/* --------------------------------------------------------------------- Tasks */

/*
 * One row per task. The tool presented each as a tall block with a permanently open text area -
 * with twenty tasks that becomes a page one only scrolls through.
 */
.todo-overlay-content .todo-row {
  padding: .45rem .6rem;
  border-bottom: 1px solid #eee;
}

.todo-overlay-content .todo-row:last-child {
  border-bottom: none;
}

.todo-overlay-content .todo-new {
  margin-bottom: .6rem;
  border: 1px solid var(--border);
  border-radius: .25rem;
  background: var(--ze-light-grey);
}

/* Title, due date and buttons side by side; the title takes what is left over. */
.todo-overlay-content .todo-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .35rem;
}

.todo-overlay-content .todo-title {
  flex: 1 1 12rem;
  min-width: 8rem;
}

.todo-overlay-content .todo-deadline {
  flex: 0 0 9.5rem;
  width: 9.5rem;
}

/* The state as a dot - the same language as on the overview. */
.todo-overlay-content .todo-state {
  flex: none;
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  background: var(--ze-success);
}

.todo-overlay-content .todo-row.overdue .todo-state {
  background: var(--ze-error);
}

.todo-overlay-content .todo-row.finished .todo-state {
  background: var(--ze-grey);
}

/* What is done steps back but stays legible. */
.todo-overlay-content .todo-row.finished .todo-title {
  color: var(--ze-dark-grey);
  text-decoration: line-through;
}

/*
 * Only the icon in the button - the label stands in the title attribute.
 *
 * The three buttons sit in two different containers (save in the editing form, the other two
 * beside it). So the icons still sit on one line, all of them get the same height as an input,
 * and the icon is centred within it instead of hanging on the font baseline - `vertical-align`
 * otherwise depends on where the icon is drawn inside its image.
 */
.todo-overlay-content .todo-icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 14px font, 9px padding top and bottom, 1px border - like .field-input. */
  height: 40px;
  padding: 0 .6rem;
}

/*
 * Only the existing tasks: the editing form on the left, the two actions on the right. When
 * creating one there are no actions beside it - there, row and description would otherwise stay
 * side by side instead of below one another.
 */
.todo-overlay-content .todo-row:not(.todo-new) {
  display: flex;
  align-items: flex-start;
  gap: .35rem;
}

.todo-overlay-content .todo-row:not(.todo-new) > form:first-child {
  flex: 1;
  min-width: 0;
}

.todo-overlay-content .todo-row-actions {
  display: flex;
  flex: none;
  align-items: center;
  gap: .35rem;
}

/* The description lies collapsed below and opens only when there is something in it. */
.todo-overlay-content .todo-description {
  margin-top: .3rem;
}

.todo-overlay-content .todo-description summary {
  color: var(--ze-dark-grey);
  cursor: pointer;
  font-size: .78rem;
}

.todo-overlay-content .todo-description textarea {
  width: 100%;
  min-height: 3rem;
  margin-top: .25rem;
  font-size: .82rem;
  resize: vertical;
}

/* --- Bulk action in lists ----------------------------------------------- */

.todo-bulk {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin-bottom: .6rem;
  padding: .5rem .75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--ze-light-grey);
}

.todo-bulk-label {
  font-weight: bold;
}

.todo-bulk-count {
  color: var(--ze-dark-grey);
  font-size: .85rem;
}

/* --- Working note on the task ------------------------------------------- */

.todo-work-note {
  margin-top: .35rem;
}

.todo-work-note > summary {
  color: var(--ze-dark-grey);
  cursor: pointer;
  font-size: .78rem;
}

.todo-work-note textarea {
  width: 100%;
  min-height: 2.6rem;
  margin: .25rem 0;
  font-size: .82rem;
  resize: vertical;
}

/* Delete stands below the form, set apart - it is not a save. */
.todo-form-delete {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .6rem;
  padding: 14px 20px;
  border-top: 1px solid var(--border);
}

.todo-status-pill {
  margin-top: .3rem;
}

/* ------------------------------------------------------------- Module grants */

.module-block {
  margin-bottom: 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

.module-block-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  background: var(--surface-alt);
  border-bottom: 1px solid var(--border);
  font-weight: 600;
}

.module-block-body {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 8px 18px;
  padding: 14px 16px;
}

.module-block-body:empty {
  display: none;
}

/* ----------------------------------------------------------- Navigation bars */

/* Navigation: see navigation.css (taken over from the warehouse).
   Only additions that have no counterpart there stand here. */

/*
 * The warehouse reckons firmly with bars 50.4px tall - that is where its
 * "#sub-nav-bar { top: 50.4px }" and "padding-top: 7rem" on the content come
 * from. That height follows from its base font; here the base font is a
 * different one, so the height is set explicitly. With that the values taken
 * over are right again.
 */
#top-nav-bar,
#sub-nav-bar {
  height: 50.4px;
  padding-top: 0;
  padding-bottom: 0;
  /* In px instead of rem: on the reporting pages Bootstrap 3 sets html{font-size:10px}. */
  font-family: sans-serif;
  font-size: 16px;
  line-height: 1.15;
}

#top-nav-bar .navbar-brand,
#sub-nav-bar .navbar-brand {
  font-size: 20px;
}

/* Distinctly warmer than the Bootstrap dark grey (#343a40): a dark orange-brown,
   and to match it the highlight of the active page. */
#top-nav-bar.bg-dark {
  background-color: #4a3320 !important;
}

#top-nav-bar .nav-item .nav-link.active {
  background: #8a5a22;
}

/*
 * The order portal carries the colours of its own wordmark.
 *
 * Both front ends share this file and this bar - the customer and the member of staff see the
 * same house. The colour is the one difference, and it is the fastest one: whoever has both
 * windows open sees without reading which one they are in.
 *
 * Both values come from the gradient the word "grosshandel" is set in within the logo
 * (delicano-grosshandel.svg): #4B0D41 is its dark end, #880060 its light one. Not guessed but
 * read off - that way the bar stays in the tone of the brand, even when nobody remembers why
 * this particular violet.
 */
#top-nav-bar.nav-customer.bg-dark {
  background-color: #4B0D41 !important;
}

#top-nav-bar.nav-customer .nav-item .nav-link.active {
  background: #880060;
}

/*
 * The house colour of the order portal.
 *
 * Over in the administration it is green (--brand: #57a900). In the portal that was a foreign
 * body: the bar carries the violet from the wordmark "grosshandel", and beside it stood a green
 * button. Two brands on one page, and neither of them wins.
 *
 * So the same two values as in the bar stand here, as variables: everything that uses --brand -
 * buttons, progress bars, the outline around a focused field - follows along by itself. One rule
 * per kind of button would be the same change in thirty-one places.
 */
body.customer-portal {
  --brand: #880060;
  --brand-dark: #4B0D41;
  --brand-light: #f9edf5;
}

/*
 * The supplier portal, in a colour of its own.
 *
 * A third area on the same host name, and whoever has more than one open should see from the shade
 * which one they are standing in - the administration is green, the order portal violet. Here the
 * crimson out of the middle of the wordmark: the "delicando" lettering runs as a gradient from
 * violet to yellow-orange, and #DD0044 is the stop at offset 0.5 - see
 * delicano-grosshandel.svg.
 *
 * That the order portal takes its violet from the same gradient is not a clash but the point: both
 * are the house, and they are still told apart at a glance.
 *
 * The bar carries white writing (navbar-dark), so it takes a darker shade of the same colour. How
 * much darker is not a matter of taste: the entries one is not standing on are drawn in --nav-link,
 * half-transparent white, so what one reads there is fifty percent white blended with the bar
 * itself. The lighter the bar, the closer the two are - on a #A60033 bar the blend came out at
 * 2.7:1 and the entries went dim. #520018 puts them at 4.5:1, which is where the order portal
 * stands too (4.6:1), and lifts plain white to 15.3:1.
 *
 * The highlighted entry sits on that bar in the wordmark crimson and is told apart from it by
 * 3.0:1 - the order portal has 2.9:1. That is what says which page one is on, so it may not shrink.
 *
 * The same reckoning as with the order portal above: the two values stand as variables, so
 * everything that uses --brand follows along by itself - buttons, progress bars, the outline
 * around a focused field. The buttons keep the crimson out of the wordmark unchanged; only the
 * bar goes dark, exactly as the violet one does.
 */
#top-nav-bar.nav-supplier.bg-dark {
  background-color: #520018 !important;
}

#top-nav-bar.nav-supplier .nav-item .nav-link.active {
  background: #DD0044;
}

body.supplier-portal {
  --brand: #DD0044;
  --brand-dark: #520018;
  --brand-light: #fdecf1;
}

/*
 * The person beside the house.
 *
 * A supplier can have several contacts here, and both names stand in the bar: the house says whose
 * prices these are, the person says under whose login one is about. The second one steps back -
 * it answers a question one only asks now and then.
 */
.nav-person {
  opacity: .7;
}

/*
 * Somebody else's session - a member of staff looking into the portal as a customer.
 *
 * Only the notice, not the colour of the bar: that should stay what it is, so the portal looks
 * like the portal even with one of us inside it. The notice therefore carries the conspicuousness
 * alone - warm yellow on the violet, bold, with a symbol.
 */
.nav-acting-hint {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: #ffd48a !important;
  font-weight: 600;
}

/*
 * The bars have no vertical padding here (fixed height), or the highlight
 * would fill the whole bar. This way it sits freely within it - as in the
 * time tracking.
 */
#top-nav-bar .navbar-nav .nav-item {
  display: flex;
  align-items: center;
}

/*
 * The submodule list scrolls horizontally (rule from the warehouse). It gets
 * a height of its own here, so the thin scrollbar stays inside the bar and
 * does not stick out past its bottom edge. The spacing on the right makes
 * sure the last entry does not end up under the cogwheel.
 */
/*
 * Only the navigation rules were taken over from Bootstrap, not its reboot -
 * so the lists keep the browser's default margin (1em at the top) and the
 * entries sat 16px too low in both bars.
 */
#top-nav-bar .navbar-nav,
#sub-nav-bar .navbar-nav {
  margin-top: 0;
  margin-bottom: 0;
}

#sub-nav-bar .navbar-collapse {
  height: 100%;
  align-items: center;
}

/*
 * The list scrolls horizontally (rule from the warehouse). The thin scrollbar
 * takes height from the list while doing so - which made the entries sit
 * higher than the module name beside them. So it is hidden, as the upper bar
 * already does anyway; scrolling happens with the wheel or by swiping.
 */
#sub-nav-bar .navbar-nav.mr-auto {
  height: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

#sub-nav-bar .navbar-nav.mr-auto::-webkit-scrollbar {
  display: none;
}

/*
 * On the reporting pages Bootstrap 3 lies in the document as well; its
 * ".navbar-nav > li > a" is more specific than ".nav-link" of Bootstrap 4 and
 * inflates the entries to 15px of padding. So it is pinned down here - in px,
 * because Bootstrap 3 additionally sets html{font-size:10px}.
 */
#top-nav-bar .navbar-nav > .nav-item > .nav-link,
#sub-nav-bar .navbar-nav > .nav-item > .nav-link {
  padding-top: 8px;
  padding-bottom: 8px;
}

.navbar .badge {
  padding: 1px 7px;
  border-radius: 99px;
  background: var(--brand);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .5px;
  text-transform: uppercase;
  vertical-align: middle;
}

/* The full-screen button is a button - Bootstrap only styles links. */
#top-nav-bar button.nav-link,
#sub-nav-bar button.nav-link {
  background: none;
  border: none;
  cursor: pointer;
  font: inherit;
  color: rgba(255, 255, 255, .5);
}

#top-nav-bar button.nav-link:hover {
  color: rgba(255, 255, 255, .75);
}

/* Counter on the button - like .navigation-icon-count in the warehouse. */
#top-nav-bar .navigation-icon {
  position: relative;
  display: inline-flex;
  align-items: center;
}

/*
 * navigation.css brings
 * ".navbar .navigation-icon .navigation-icon-count { display: flex }" along
 * from the warehouse - and that beats a single-class rule. So the same depth
 * here, or the empty circle would stand there always.
 */
.navbar .navigation-icon .navigation-icon-count {
  position: absolute;
  top: 2px;
  right: -2px;
  display: none;
  min-width: 16px;
  width: auto;
  height: 16px;
  margin-left: 0;
  padding: 0 4px;
  border-radius: 99px;
  background: none;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}

/* Only with exports does the counter get colour and room. */
.navbar .navigation-icon .navigation-icon-count.active {
  display: flex;
  align-items: center;
  justify-content: center;
  background: #c9762b;
}

.navbar .navigation-icon .navigation-icon-count[hidden] {
  display: none;
}

/* --------------------------------------------------- Time tracking: terminal */

/* While the time tracking runs the symbol stands out - otherwise it stays quiet. */
#time-tracking-state.active {
  color: var(--brand);
}

/*
 * "We are here" on the icon - the same backing as on the entries of the bar.
 *
 * A class of its own and not `active`: on the icon that has always meant "a booking is running"
 * and colours it green. Both can hold at the same time, and then both should be visible.
 *
 * The rule of the entries does not take hold here - it demands `.nav-item .nav-link`, and the icon
 * stands outside the collapsible bar, without a list item around it.
 */
#top-nav-bar .nav-link.is-current {
  background: #8a5a22;
}

/*
 * Inside the module the icon is white - even while a booking is running.
 *
 * The green says "a booking is running" and is hard to read on the backed ground. That a booking
 * is running is said by the shape at this spot anyway: a triangle stands for running, two bars for
 * stopped. Two ids and one class - that beats the line with `.active` above without anything
 * having to change there.
 */
#top-nav-bar #time-tracking-state.is-current {
  color: #fff;
}

/* --- Station ------------------------------------------------------------ */

.time-tracking-terminal {
  max-width: 32rem;
  margin: 2rem auto;
}

.time-tracking-terminal .title {
  margin-bottom: 1rem;
  font-size: 1.6rem;
  font-weight: bold;
  text-align: center;
}

.time-tracking-terminal #time-tracking-terminal-form {
  display: grid;
  gap: .5rem;
  padding: 1rem;
  border: 1px solid var(--ze-grey);
  border-radius: .4rem;
  background: var(--ze-light-grey);
}

.time-tracking-terminal #time-tracking-terminal-form input {
  padding: .6rem;
  border: 1px solid var(--ze-grey);
  border-radius: .3rem;
  font-size: 1.4rem;
  text-align: center;
}

.time-tracking-terminal .terminal-result {
  margin-top: 1rem;
  padding: 1rem;
  border: 1px solid var(--ze-grey);
  border-left-width: .4rem;
  border-radius: .4rem;
  background: #fff;
}

.time-tracking-terminal .terminal-result .headline {
  font-size: 1.2rem;
  font-weight: bold;
}

.time-tracking-terminal .terminal-result .name {
  margin: .2rem 0 .6rem 0;
  font-size: 1.6rem;
  font-weight: bold;
}

.time-tracking-terminal .terminal-result .detail {
  display: flex;
  justify-content: space-between;
  gap: .5rem;
  padding: .15rem 0;
  border-bottom: 1px dotted var(--ze-light-grey);
}

.time-tracking-terminal .terminal-result .detail .label {
  color: var(--ze-dark-grey);
}

.time-tracking-terminal .terminal-result .detail .value {
  font-variant-numeric: tabular-nums;
}

.time-tracking-terminal .terminal-result.started {
  border-left-color: var(--ze-success);
}

.time-tracking-terminal .terminal-result.started .headline {
  color: var(--ze-success);
}

.time-tracking-terminal .terminal-result.stopped {
  border-left-color: var(--ze-blue);
}

.time-tracking-terminal .terminal-result.stopped .headline {
  color: var(--ze-blue);
}

.time-tracking-terminal .terminal-result.error {
  border-left-color: var(--ze-error);
}

.time-tracking-terminal .terminal-result.error .headline {
  color: var(--ze-error);
}

/*
 * The choice of task at the station (EX-1419).
 *
 * Nothing is booked while this stands there. The buttons are deliberately large and full width:
 * the station is a screen in the warehouse and is operated with gloves on, so there is nothing
 * small to hit and no list to open first.
 */
.time-tracking-terminal .terminal-result.choose {
  border-left-color: var(--ze-blue);
}

.time-tracking-terminal .terminal-result.choose .headline {
  color: var(--ze-blue);
}

.time-tracking-terminal .terminal-todo-choice {
  display: flex;
  flex-direction: column;
  gap: .6rem;
  margin-top: .4rem;
}

.time-tracking-terminal .terminal-todo-button {
  width: 100%;
  min-height: 4rem;
  padding: 1rem;
  font-size: 1.3rem;
  /* A long task name wraps rather than being cut off - the person has to read which is which. */
  white-space: normal;
  word-break: break-word;
}

.time-tracking-terminal .terminal-todo-cancel {
  width: 100%;
  min-height: 3rem;
  margin-top: .4rem;
}

/*
 * The station with the latest bookings beside it (EX-1370). The station keeps its width in the
 * middle column; the history is narrower and smaller, and moves below it on a narrow screen.
 */
.time-tracking-terminal-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 32rem) minmax(0, 1fr);
  gap: 2rem;
  align-items: start;
}

.time-tracking-terminal-layout .time-tracking-terminal {
  grid-column: 2;
  width: 100%;
}

.time-tracking-terminal-history {
  grid-column: 3;
  max-width: 18rem;
  margin-top: 2rem;
  font-size: .85rem;
}

.time-tracking-terminal-history .history-title {
  margin-bottom: .5rem;
  font-weight: bold;
  color: var(--ze-dark-grey);
}

.time-tracking-terminal-history .history-empty {
  margin: 0;
  color: var(--ze-dark-grey);
}

.time-tracking-terminal-history .history-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.time-tracking-terminal-history .history-entry {
  display: grid;
  grid-template-columns: auto auto 1fr;
  gap: .5rem;
  padding: .2rem 0 .2rem .4rem;
  border-left: .2rem solid var(--ze-grey);
  border-bottom: 1px dotted var(--ze-light-grey);
}

.time-tracking-terminal-history .history-entry.started {
  border-left-color: var(--ze-success);
}

.time-tracking-terminal-history .history-entry.stopped {
  border-left-color: var(--ze-blue);
}

.time-tracking-terminal-history .history-time {
  font-variant-numeric: tabular-nums;
  color: var(--ze-dark-grey);
}

.time-tracking-terminal-history .history-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 64rem) {
  .time-tracking-terminal-layout {
    grid-template-columns: minmax(0, 1fr);
  }

  .time-tracking-terminal-layout .time-tracking-terminal,
  .time-tracking-terminal-history {
    grid-column: 1;
    max-width: 32rem;
    margin-left: auto;
    margin-right: auto;
  }

  .time-tracking-terminal-history {
    width: 100%;
    margin-top: 0;
  }
}

/* --------------------------------------- Time tracking: overview (table) */

/*
 * The table of the tool. There the borders came from Bootstrap; here they are written out, so no
 * whole library has to be loaded along.
 */
.time-tracking-status .content-table {
  width: 100%;
  margin: 0;
  border-collapse: collapse;
}

.time-tracking-status .content-table tr th,
.time-tracking-status .content-table tr td {
  padding: .2rem .5rem;
  border: 1px solid #dee2e6;
  font-size: .9rem;
}

.time-tracking-status .content-table tr th {
  background: #f2f2f2;
  font-size: 1rem;
  text-align: left;
}

.time-tracking-status .content-table .text-right {
  text-align: right;
}

/* The running booking stands out in the list. */
.time-tracking-status .content-table tr.running td {
  background-color: var(--ze-success-bg);
}

.time-tracking-status .content-table tr.running .state-text {
  color: var(--ze-success);
  font-weight: bold;
}

.time-tracking-status .content-table .field-input,
.time-tracking-status .content-table .field-select {
  padding: .1rem .3rem;
  font-size: .9rem;
}

/* --- Overview: who is in the house today ------------------------------- */

.time-tracking-overview .overview-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  margin: 1rem 0 .5rem 0;
}

.time-tracking-overview .overview-summary .count {
  font-size: 1.6rem;
  font-weight: bold;
}

.time-tracking-overview .overview-summary .hint {
  margin-left: .5rem;
  color: var(--ze-dark-grey);
  font-size: .85rem;
}

.time-tracking-overview .overview-actions {
  display: flex;
  align-items: center;
  gap: .3rem;
}

/*
 * Opening is done with <details>. In the tool jQuery took care of that; this way it works without
 * a script and the browser remembers what is open.
 */
.time-tracking-overview .overview-department {
  margin-bottom: -1px;
  border: 1px solid #dee2e6;
}

/*
 * The department row and the staff rows share the same three columns - in the tool they stand in
 * a table, here every department opens for itself.
 */
.time-tracking-overview .overview-head-row,
.time-tracking-overview .department-row {
  display: grid;
  grid-template-columns: 41% 37% auto;
  align-items: center;
  gap: .5rem;
  padding: .4rem .5rem;
}

.time-tracking-overview .overview-head-row {
  border: 1px solid #dee2e6;
  background: var(--ze-light-grey);
  font-weight: bold;
}

.time-tracking-overview .department-row {
  background: var(--ze-light-grey);
  cursor: pointer;
}

.time-tracking-overview .department-row .department-name {
  font-weight: bold;
}

.time-tracking-overview .department-row .department-status {
  color: var(--ze-dark-grey);
  font-size: .85rem;
}

/* The figure carries the row, the rest is trimming. */
.time-tracking-overview .department-row .department-status strong {
  color: #333;
}

/*
 * One's own department stands out - that is where one looks first. A stripe at the side is enough
 * for it; a coloured-in row used to draw more attention than the list itself.
 */
.time-tracking-overview .own-department > .department-row {
  border-left: 3px solid var(--ze-orange);
}

.time-tracking-overview .own-row td {
  font-weight: bold;
}

/*
 * Whoever is currently running stands out in the name column already - there is no need to look
 * at the status column first. The stripe takes the same colour as the dot beside it, so the page
 * sticks to the one statement: green means reachable.
 */
.time-tracking-overview tr.is-present td:first-child {
  border-left: 3px solid var(--ze-success);
  background: rgba(40, 166, 69, .06);
  font-weight: 600;
}

/* The other way round, whoever is not there steps back - or the difference would be half visible. */
.time-tracking-overview .content-table tr:not(.is-present) td:first-child {
  color: var(--ze-dark-grey);
}

.time-tracking-overview .content-table {
  width: 100%;
  margin: 0;
  table-layout: fixed;
  border-collapse: collapse;
}

.time-tracking-overview .content-table td:first-child {
  width: 41%;
}

.time-tracking-overview .content-table td:nth-child(2) {
  width: 37%;
}

.time-tracking-overview .content-table tr th,
.time-tracking-overview .content-table tr td {
  padding: .2rem .5rem;
  border: 1px solid #dee2e6;
  font-size: .9rem;
  text-align: left;
}

.time-tracking-overview .content-table tr th {
  background: #f2f2f2;
  font-size: 1rem;
}

/*
 * The status: a dot and the word for it.
 *
 * The tool used filled Bootstrap badges here, one colour per kind of absence. With sixty members
 * of staff every row carried a coloured block, and the question this page is about - who is here
 * - drowned in it. Colour now carries only this one distinction, the reason is stated by the word.
 */
.time-tracking-overview .status {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  margin-right: .75rem;
  font-size: .85rem;
  white-space: nowrap;
}

.time-tracking-overview .status::before {
  content: "";
  width: .5rem;
  height: .5rem;
  flex: none;
  border-radius: 50%;
  background: var(--ze-grey);
}

/* In the house: a filled dot. */
.time-tracking-overview .status-present {
  font-weight: 600;
}

.time-tracking-overview .status-present::before {
  background: var(--ze-success);
}

/* Reachable but not in the house: the same dot, only hollow. */
.time-tracking-overview .status-remote::before {
  background: #fff;
  box-shadow: inset 0 0 0 2px var(--ze-success);
}

.time-tracking-overview .status-away {
  color: var(--ze-dark-grey);
}

.time-tracking-time-table .content-table {
  width: 100%;
  margin: 0 0 1rem 0;
  border-collapse: collapse;
}

.time-tracking-time-table .content-table tr th,
.time-tracking-time-table .content-table tr td {
  padding: .2rem .5rem;
  border: 1px solid #dee2e6;
  font-size: .85rem;
  text-align: left;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.time-tracking-time-table .content-table tr th {
  background: #f2f2f2;
  font-size: .9rem;
}

.time-tracking-status .content-table td.column-action {
  width: 1%;
  white-space: nowrap;
  text-align: right;
}

/* The three links in the head of the overview. */
.time-tracking-overview .overview-links {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
}

/* Without fields the rows are distinctly lower - the figures then stand in line. */
.worklog-list:not(.is-editing) .content-table td {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------ Loading and progress */

.steps {
  margin: 0 0 18px;
  padding-left: 20px;
  color: var(--text);
  font-size: 13px;
  line-height: 1.7;
}

.steps code {
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--surface-alt);
  font-size: 12px;
}

/* Progress bar like .progress-line in the warehouse tool. */
.progress-line {
  position: relative;
  min-width: 110px;
  height: 16px;
  overflow: hidden;
  border-radius: 99px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
}

.progress-line .active-progress {
  height: 100%;
  background: #c9762b;
  transition: width .3s ease;
}

.progress-line .progress-title {
  position: absolute;
  inset: 0;
  font-size: 10px;
  font-weight: 700;
  line-height: 14px;
  text-align: center;
}

/*
 * The veil while something is running - shown by Admin.initBusy.
 *
 * Above everything: 10001 are the overlays, 10002 the messages and the progress bar. If a request
 * runs out of the downloads list, the list should not look operable while it runs - and a message
 * from earlier does not belong above the veil.
 */
#loading {
  position: fixed;
  inset: 0;
  z-index: 10005;
  display: none;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 14px;
  background: rgba(244, 246, 249, .78);
}

#loading[style*="flex"],
#loading[style*="block"] {
  display: flex !important;
}

#loading .loading-spinner {
  width: 42px;
  height: 42px;
  border: 3px solid rgba(87, 169, 0, .22);
  border-top-color: var(--brand);
  border-radius: 50%;
  animation: admin-spin .8s linear infinite;
}

/* Whoever turned motion off gets the ring standing still - it says as much either way. */
@media (prefers-reduced-motion: reduce) {
  #loading .loading-spinner {
    animation: none;
  }
}

#loading .loading-text {
  color: var(--text-muted);
  font-size: 13px;
  font-weight: 500;
}

/* ------------------------------------------------------------ Image uploads */

/* History of the image uploads: month, bar, figure - one grid row per line. */
.upload-history {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 6px 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.upload-history li {
  display: contents;
}

.upload-history-label {
  color: var(--text-muted);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.upload-history-track {
  height: 14px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 7px;
  overflow: hidden;
}

.upload-history-bar {
  display: block;
  height: 100%;
  background: var(--brand);
  border-radius: 7px;
}

/* A month without an upload keeps its row but shows no bar. */
.upload-history-bar.is-empty {
  background: none;
}

.upload-history-count {
  min-width: 48px;
  text-align: right;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------- Reporting messages */

/* A message above a form - the same role as in the reporting. */
.report-alert {
  display: none;
  margin-bottom: 18px;
  padding: 12px 16px;
  border: 1px solid var(--bad);
  border-left-width: 4px;
  border-radius: var(--radius-sm);
  background: var(--bad-bg);
  color: #8c1c1c;
}

.report-alert.is-visible {
  display: block;
}

.report-alert-title {
  font-weight: 600;
}

.report-alert-detail {
  margin-top: 4px;
  font-size: 12px;
  word-break: break-word;
}

/*
 * Overlays of the time tracking. The tool brought five along; three were missing here - the
 * message dialogue, the error dialogue and the confirmation when copying. The loading veil is
 * called #loading here and is already present.
 */
.modal-overlay-container {
  max-width: 900px;
  margin: 40px auto;
  padding: 20px;
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

#copy-blink-container {
  position: fixed;
  z-index: 1200;
  padding: 6px 12px;
  background: var(--brand);
  border-radius: var(--radius-sm);
  color: #fff;
  font-size: 12px;
  pointer-events: none;
  opacity: 0;
}

/* -------------------------------------------------------- Shipping tiles */

/*
 * One section per provider group: the channel tiles on the left, the list of the most recently
 * received orders on the right. The list stands in a column of its own, so it stays beside the
 * tiles and does not wrap behind them.
 */
.segment {
  display: grid;
  /*
   * The list gets a fixed, frugal width - enough for order number, customer and amount - and the
   * tiles take all of the rest. That way the room for the metrics grows with the window, and the
   * list does not become needlessly wide.
   */
  grid-template-columns: minmax(0, 1fr) 420px;
  gap: 16px;
  margin-bottom: 28px;
}

/* Sections without a list keep the full width. */
.segment.segment-plain {
  grid-template-columns: minmax(0, 1fr);
}

/* The spacing comes from the section, not from the grid inside it. */
.segment > .metric-grid {
  margin-bottom: 0;
}

/*
 * The height follows the tiles beside it - the same mechanism as in the overview: flex-basis 0
 * keeps the list out of the natural card height, the grid stretches the card to the height of the
 * tile column, and the list fills the rest. The lower bound takes hold when the list stands alone
 * in its row.
 */
.segment > .metric-card-list .metric-scroll-list {
  flex: 1 1 0;
  min-height: 320px;
  max-height: none;
}

/* The shipping state - the question one has first on this page. */
.shipping-state {
  margin-bottom: 4px;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
}

.shipping-state.clear {
  background: var(--good-bg);
  color: #1e7a33;
}

.shipping-state.waiting {
  background: #fdf1e2;
  color: #8a5320;
}

.shipping-headline {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.shipping-count {
  font-size: 30px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.shipping-text {
  font-size: 14px;
  font-weight: 600;
}

.shipping-state .metric-rows {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid rgba(0, 0, 0, .1);
}

.shipping-state .metric-rows dt {
  color: inherit;
  opacity: .8;
}

.package-storno {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 190px;
}

.package-storno .field-textarea {
  min-height: 0;
}

/* ------------------------------------------------------------- Miscellaneous */

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

@container (min-width: 520px) {
  .metric-card-overall .metric-rows {
    grid-template-columns: max-content minmax(0, 1fr) max-content minmax(0, 1fr);
    column-gap: 10px;
  }

  .metric-card-overall .metric-rows dt::after {
    content: ':';
  }

  .metric-card-overall .metric-rows dd {
    /* The value follows on the label instead of wandering to the edge. */
    text-align: left;
    padding-right: 18px;
    font-weight: 600;
  }
}

/*
 * The image view stands centred and takes at most half the window - in both directions. The image
 * should be large enough to make something out, but not cover the page behind it.
 *
 * The padding of the base rule is taken back, or the spacing for the fixed head bar would push
 * the card out of the centre.
 */
#image-overlay {
  align-items: center;
  padding: 16px;
}

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

@keyframes timeTrackingPulse {
  0% { opacity: 1; }
  50% { opacity: .3; }
  100% { opacity: 1; }
}

/* --- Year overview ------------------------------------------------------ */

/*
 * The cells do not wrap (white-space: nowrap further down), so times and totals stay legible.
 * That gives the table a minimum width - on a narrow window it scrolls within itself here instead
 * of running out of the card.
 */
.time-tracking-time-table {
  margin-top: 1.5rem;
  overflow-x: auto;
}

@keyframes adminMessageIn {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

.time-tracking-calendar .hint,
.time-tracking-department .hint {
  margin-left: .5rem;
  color: var(--ze-dark-grey);
  font-size: .85rem;
  font-weight: normal;
}

.time-tracking-department .value {
  font-variant-numeric: tabular-nums;
}

.time-tracking-department .value.negative { color: var(--ze-error); }

.time-tracking-department .value.positive { color: var(--ze-success); }

.time-tracking-department .week-day {
  padding: .2rem 0;
  border: 1px solid #eee;
  border-radius: .2rem;
  text-align: center;
  font-size: .72rem;
}

.time-tracking-department .week-day.free {
  color: var(--ze-grey);
}

.time-tracking-department .week-day .name {
  display: block;
  color: var(--ze-dark-grey);
}

.time-tracking-department .future-freetime {
  display: flex;
  justify-content: space-between;
  gap: .5rem;
  font-size: .78rem;
}

.time-tracking-department .future-freetime .info {
  color: var(--ze-dark-grey);
}

/*
 * The row above the list of short passwords: on the left when it was last asked for, on the right
 * the button for it. Both stand inside the reloaded area, so the time is right.
 */
.otp-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  margin: 0 0 12px;
  color: var(--text-muted);
  font-size: 13px;
}

/*
 * The code is read off and typed onward - digit by digit. Fixed character width and a little air
 * between them, so 0 and 8 do not look alike.
 */
.otp-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 16px;
  letter-spacing: 1px;
  white-space: nowrap;
}

/* ------------------------------------------------------------ Narrow windows */

@media (max-width: 1200px) {
  .modules-container {
    grid-template-columns: 1fr;
    gap: .5rem;
  }
}

/*
 * Below this width too little would be left beside the 420px list for a tile (minimum width
 * 400 px plus spacing). From here on the list stands below the tiles.
 */
@media (max-width: 900px) {
  .segment {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 1700px) {
  .metric-grid.overall {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 900px) {
  .metric-grid.overall {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 600px) {
  .metric-card-overall .metric-split {
    grid-template-columns: 1fr;
  }
}

@media (prefers-reduced-motion: reduce) {
  #loading .loading-spinner {
    animation-duration: 2.4s;
  }
}

@media (max-width: 860px) {
  .embed-body {
    height: auto;
    overflow: visible;
  }

  .embed-frame {
    height: 70vh;
  }

  .embed-bar {
    padding: 7px 16px;
  }
}

@media (max-width: 991px) {
  /* Opened out, the bars need more room than the fixed height. */
  #top-nav-bar,
  #sub-nav-bar {
    height: auto;
    min-height: 50.4px;
    padding-top: .5rem;
    padding-bottom: .5rem;
  }

  #top-nav-bar {
    position: static;
  }

  #sub-nav-bar {
    position: static;
    top: auto;
  }

  .page,
  body.no-sub-navigation .page {
    padding-top: 26px;
    padding-left: 16px;
    padding-right: 16px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .meldungskarte {
    transition: none;
  }
}

@media (max-width: 900px) {
  .metric-grid.upload-grid-two {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 900px) {
  .metric-grid.order-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 768px) {
  .time-tracking-status {
    max-width: 40rem;
  }
}

@media (max-width: 768px) {
  .time-tracking-analysis-summary {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 480px) {
  .time-tracking-analysis-summary {
    grid-template-columns: 1fr;
  }
}



/*
 * The sign-in of the order portal - the same form as /_admin/login, with two additions.
 *
 * A heading: the administration front end has exactly one sign-in page, here there are three
 * (sign in, forgotten password, set password), and without a title they would look the same.
 *
 * And the language switch, which does not exist over there. It stands at the very bottom, because
 * nobody looking to sign in is searching for it.
 */
.login-title {
  margin: 0 0 18px;
  font-size: 17px;
  font-weight: 600;
}

.login-languages {
  margin-top: 22px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  text-align: center;
  font-size: 12px;
  color: var(--text-muted);
}

.login-languages a {
  color: var(--text-muted);
  text-decoration: none;
}

.login-languages a:hover {
  color: var(--brand-dark);
  text-decoration: underline;
}

.login-languages strong {
  color: var(--text);
}

.login-languages > * + * {
  margin-left: 10px;
}

/*
 * A page under only one bar.
 *
 * `page` keeps room at the top for both bars of the administration front end. The customer area
 * has only the upper one - four pages need no submodule bar - and without this correction its
 * content would begin with a hand's breadth of emptiness.
 */
.page.page-single-nav {
  padding-top: 74px;
}

/*
 * A response in the middle of the page.
 *
 * The administration front end has Admin.js draw its messages as a toast at the bottom right. The
 * customer area does not load that script - four pages need no toast mechanism - and a message
 * nobody sees is none. So it stands where the thing it reports happened.
 */
.page-notice,
.page-error {
  /*
   * A row with spacing, not text and button glued together. When a button stands beside it -
   * "Adresse anlegen", say - only the whitespace from the source separated it otherwise, and the
   * browser collapses that.
   */
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-left-width: 4px;
  border-radius: var(--radius-sm);
  font-size: 13px;
  line-height: 1.5;
}

.page-notice {
  background: var(--good-bg);
  border-color: var(--good);
  color: #1e7a33;
}

.page-error {
  background: var(--bad-bg);
  border-color: var(--bad);
  color: #8c1c1c;
}

/*
 * A progress bar in the veil.
 *
 * The house's veil shows a spinner and a sentence - right, as long as nobody knows how long it
 * will take. With the matching of an uploaded file one does know: the lines are counted. Then a
 * bar is the more honest answer, because it makes the difference between "working" and "stuck"
 * visible.
 */
#loading .loading-progress {
  width: min(280px, 60vw);
  height: 6px;
  border-radius: 99px;
  background: rgba(87, 169, 0, .18);
  overflow: hidden;
}

#loading .loading-progress-bar {
  height: 100%;
  border-radius: 99px;
  background: var(--brand);
  transition: width .25s ease-out;
}

/* When something stands still the spinner stops too - it would otherwise be a promise. */
#loading.is-failed .loading-spinner {
  animation: none;
  border-top-color: var(--bad);
}

#loading.is-failed .loading-progress-bar {
  background: var(--bad);
}

/*
 * The review view of an uploaded file.
 *
 * The price stays on one line. The column is narrow, "1.234,56 EUR" otherwise wraps after the
 * amount there, and a figure standing on two lines reads as two figures.
 */
.review-price {
  white-space: nowrap;
}

/* Less in stock than ordered - no refusal, but it should catch the eye. */
.review-stock-short {
  color: var(--warning);
  font-weight: 600;
}

/*
 * The thumbnail in the review view.
 *
 * The class had always stood in the markup but never in the CSS - the image lived on width and
 * height in the attribute alone. A portrait bottle shot was squeezed into a square by that.
 */
.review-image {
  width: 56px;
  height: 56px;
  object-fit: contain;
  border-radius: 4px;
  background: #fff;
}

/* The quantity field in the row - narrow, but wide enough for four-digit quantities. */
.review-quantity {
  width: 5.5em;
  min-width: 5.5em;
}

/*
 * The button below the table.
 *
 * Inside the card, with spacing above: the table ends with a line, and a button following
 * straight on it looks like one more row.
 */
.review-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  margin-top: 16px;
}

.review-actions .field-hint {
  margin: 0;
}

/*
 * A row that flies out on saving.
 *
 * Struck through and pale, but still there - whoever ticks a box by mistake should be able to
 * find the row again and take the tick back. If it vanished at once, the only answer would be
 * that something is missing.
 */
tr.review-row-removed {
  opacity: .45;
}

tr.review-row-removed td:not(.column-select) {
  text-decoration: line-through;
}

/*
 * The total below the table.
 *
 * Until September 2026 net, tax and gross stood as three bare paragraphs straight under the table
 * - without spacing, left-aligned, and so the most important amount on the page read like a
 * footnote. Now a card of its own, the amounts right-aligned below one another, so the digits
 * line up.
 */
.review-summary dl {
  margin: 0 0 4px;
  max-width: 340px;
  margin-left: auto;
}

.review-summary dl > div {
  display: flex;
  justify-content: space-between;
  gap: 24px;
  padding: 6px 0;
}

.review-summary dt {
  margin: 0;
  color: var(--text-muted);
}

.review-summary dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  /* Amounts to the right - that way the decimal places line up under one another. */
  text-align: right;
}

.review-summary .review-summary-total {
  margin-top: 4px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
  font-size: 17px;
  font-weight: 600;
}

.review-summary .review-summary-total dt {
  color: var(--text);
}

.review-summary .card-hint {
  margin: 0;
  text-align: right;
}

/*
 * The instructions on the start page of the order portal.
 *
 * Four steps below one another, the number set off from the text. No grid and no icons - this is
 * read once and then never again.
 */
.guide-steps {
  margin: 0;
  padding-left: 20px;
  list-style: decimal;
}

.guide-steps > li {
  margin-bottom: 12px;
}

.guide-steps > li:last-child {
  margin-bottom: 0;
}

.guide-steps .field-hint {
  display: block;
}

/*
 * The sentence that says what to do on a page.
 *
 * Stands between the title row and the content and may touch neither - a hint stuck to the title
 * reads as its continuation.
 */
.page-lead {
  margin: 0 0 22px;
  max-width: 62ch;
  line-height: 1.55;
}

.page-lead .field-hint {
  display: block;
  margin-top: 6px;
}

/*
 * Head row of an image card in the photo studio: name, state, date.
 *
 * Name and marking stood side by side without spacing - flex with a gap instead of spaces, which
 * the browser collapses anyway. The date gets a row of its own, it does not belong in the same
 * line as the state.
 */
.release-image-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.release-image-head .field-hint {
  flex-basis: 100%;
  margin-top: 0;
}

/*
 * Heading and text within a card.
 *
 * h2 carries the browser's default - much spacing above, much below. In a card that has padding
 * of its own already, the heading therefore sits too low and the first sentence too far away. The
 * last paragraph gets no spacing below, or the card would have it twice.
 */
.card > h2:first-child,
.card > h3:first-child {
  margin-top: 0;
  margin-bottom: 10px;
}

.card > p:last-child,
.card > ul:last-child,
.card > ol:last-child {
  margin-bottom: 0;
}

/* Between a paragraph and the list below it, less is needed than between two paragraphs. */
.card > p + ul,
.card > p + ol {
  margin-top: -4px;
}

/*
 * The delete button of an image card in the photo studio.
 *
 * Set apart from the rest of the card, at the bottom - what throws an image away should not stand
 * beside what merely files it. The spacing above it is the safety distance.
 */
.release-image-actions {
  margin-top: auto;
  padding-top: 12px;
}

.release-image-actions form {
  margin: 0;
}

/*
 * The score scale of the rating in the order portal.
 *
 * Six buttons, one decision - the same reasoning as with the image release: one click instead of
 * open, choose, close. Radio fields lie beneath, so the page gets by without a script and the
 * keyboard follows along by itself.
 */
.rating-scale {
  margin: 0 0 18px;
  padding: 0;
  border: 0;
}

.rating-scale legend {
  padding: 0;
  margin-bottom: 8px;
  font-weight: 600;
}

.rating-scale-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.rating-point input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.rating-point span {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  font-size: 17px;
  font-weight: 600;
  cursor: pointer;
}

.rating-point span:hover {
  border-color: var(--brand);
}

.rating-point input:checked + span {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}

.rating-point input:focus-visible + span {
  outline: 2px solid var(--brand-dark);
  outline-offset: 2px;
}

/*
 * The spread of the ratings.
 *
 * One bar per step, scaled to the widest value and not to the total: with eleven ratings all six
 * bars would otherwise be dashes, and a spread in which nothing can be told apart is none.
 */
.rating-spread th {
  width: 90px;
  white-space: nowrap;
}

.rating-spread .field-hint {
  display: inline;
  margin-left: 4px;
}

.rating-spread-bar {
  width: 100%;
}

.rating-spread .column-number {
  width: 70px;
}

.rating-bar {
  display: block;
  min-width: 2px;
  height: 14px;
  border-radius: 3px;
  background: var(--brand);
}

/* Weak and good take the colours of the pills next to them - same statement, same colour. */
.rating-bar-weak {
  background: var(--bad, #b3261e);
}

.rating-bar-good {
  background: var(--good, #1e7a45);
}
