/*
  ASK FMIS design system.

  One palette, one type scale, one spacing rhythm, expressed as custom properties so a
  light and a dark theme are the same stylesheet with different tokens. Nothing here is
  inline, because the content security policy forbids inline style, which is deliberate.
*/

/*
 * The browser hides [hidden] with display: none from its own stylesheet, which any author
 * rule outranks. Every grid or flex element in here therefore stayed visible when a script
 * set `hidden`, which is a silent bug: the code reads as if the thing is gone and it is
 * standing there. One rule, stated once.
 */
[hidden] {
  display: none !important;
}

:root {
  color-scheme: light;

  --ink-900: #0d1424;
  --ink-800: #16203a;
  --ink-700: #26324f;
  --ink-500: #57648a;
  --ink-400: #7c88ab;
  --ink-300: #a9b2ca;

  --surface: #ffffff;
  --surface-2: #f6f7fb;
  --surface-3: #eceff7;
  --line: #dfe3ee;
  --line-strong: #c7cddf;

  --primary: #3d4fdb;
  --primary-strong: #2f3fbb;
  /* Text and icons drawn on top of the primary. A brand with a light primary sets this to
     near black; white is only correct for a dark primary. */
  --on-primary: #ffffff;
  /* The brand colour where it is used as type or a thin line on a light surface. Equal to
     the primary for a brand whose primary is dark enough to read; a brand built on a light
     primary points this at its second colour instead. */
  --brand-ink: var(--primary);
  --primary-soft: color-mix(in srgb, var(--primary) 12%, var(--surface));
  --teal: #12a594;
  --teal-soft: #e0f5f2;
  --amber: #d98207;
  --amber-soft: #fdf0dc;
  --danger: #c8372c;
  --danger-soft: #fbe9e7;
  /* A fixed blue, for things the house style must not recolour. */
  --blauw: #1d5fd8;
  --goed: #1f9d55;
  /* Text on a filled danger or teal badge. */
  --on-accent: #ffffff;

  --radius-s: 6px;
  --radius-m: 10px;
  --radius-l: 16px;
  --shadow-1: 0 1px 2px rgba(13, 20, 36, 0.06), 0 1px 3px rgba(13, 20, 36, 0.04);
  --shadow-2: 0 4px 12px rgba(13, 20, 36, 0.08), 0 2px 4px rgba(13, 20, 36, 0.04);
  --shadow-3: 0 16px 40px rgba(13, 20, 36, 0.14);

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;

  --font: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --mono: "Cascadia Mono", "SF Mono", Consolas, monospace;

  --sidebar-width: 236px;
}

:root[data-thema="donker"] {
  color-scheme: dark;

  --ink-900: #f2f5fb;
  --ink-800: #e4e9f4;
  --ink-700: #ccd4e6;
  --ink-500: #96a1bd;
  --ink-400: #7b87a6;
  --ink-300: #5d6885;

  --surface: #141a29;
  --surface-2: #1b2233;
  --surface-3: #232b40;
  --line: #2c3549;
  --line-strong: #3a4560;

  --primary: #7b8afc;
  --on-primary: #11162a;
  --brand-ink: var(--primary);
  --primary-strong: #93a0ff;
  --primary-soft: color-mix(in srgb, var(--primary) 20%, var(--surface));
  --teal: #3fd2bd;
  --teal-soft: #143a37;
  --amber: #f0a844;
  --amber-soft: #3b2c14;
  --danger: #f0776a;
  --danger-soft: #3c1e1b;
  --blauw: #79a6ff;
  --goed: #4cc985;
  --on-accent: #11162a;

  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-2: 0 4px 14px rgba(0, 0, 0, 0.45);
  --shadow-3: 0 18px 44px rgba(0, 0, 0, 0.55);
}

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink-800);
  background: var(--surface-2);
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  color: var(--ink-900);
  font-weight: 600;
  letter-spacing: -0.01em;
}

h1 {
  font-size: 22px;
}
h2 {
  font-size: 17px;
}
h3 {
  font-size: 15px;
}

p {
  margin: 0 0 var(--space-3);
}

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

a:hover {
  text-decoration: underline;
}

svg.icon {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
}

.muted {
  color: var(--ink-500);
}

.small {
  font-size: 12.5px;
}

.mono {
  font-family: var(--mono);
  font-size: 12.5px;
}

/* ---------------------------------------------------------------- login */

.login {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 1fr;
  place-items: center;
  padding: var(--space-5);
  background:
    radial-gradient(1100px 520px at 12% -8%, var(--primary-soft), transparent 62%),
    radial-gradient(900px 480px at 108% 104%, var(--teal-soft), transparent 58%),
    var(--surface-2);
}

.login-card {
  width: 100%;
  max-width: 400px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-3);
  padding: var(--space-6);
}

.login-brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
}

.login-brand img {
  width: 44px;
  height: 44px;
}

.login-brand .name {
  font-size: 19px;
  font-weight: 650;
  color: var(--ink-900);
  letter-spacing: -0.02em;
}

.login-hint {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
  font-size: 12.5px;
  color: var(--ink-500);
}

/* ---------------------------------------------------------------- shell */

.shell {
  display: grid;
  grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
  min-height: 100vh;
}

.sidebar {
  background: var(--surface);
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  padding: var(--space-4) var(--space-3);
  position: sticky;
  top: 0;
  height: 100vh;
}

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-2) var(--space-5);
}

.sidebar-brand img {
  width: 32px;
  height: 32px;
}

.sidebar-brand .name {
  font-weight: 650;
  color: var(--ink-900);
  letter-spacing: -0.02em;
}

.nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1;
}

.nav a {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 9px var(--space-3);
  border-radius: var(--radius-m);
  color: var(--ink-700);
  font-weight: 500;
  transition: background 0.12s ease, color 0.12s ease;
}

.nav a:hover {
  background: var(--surface-2);
  text-decoration: none;
}

.nav a.active {
  background: var(--primary-soft);
  color: var(--primary-strong);
  font-weight: 600;
}

.sidebar-foot {
  border-top: 1px solid var(--line);
  padding-top: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.who {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-m);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.who:hover, .who:focus-visible { background: var(--surface-2); }

/* Mijn account: a wider dialog, a bigger avatar, and a line between the blocks. */
.modal.modal-breed { max-width: 880px; }
.avatar.avatar-groot { width: 48px; height: 48px; font-size: 17px; }
.account-blok { display: flex; flex-direction: column; gap: var(--space-2); padding-top: var(--space-4); border-top: 1px solid var(--line); }
.account-blok h3 { margin: 0; font-size: 15px; }

.avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--primary);
  color: var(--on-primary);
  display: grid;
  place-items: center;
  font-size: 12px;
  font-weight: 650;
  flex: 0 0 auto;
}

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

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  position: sticky;
  top: 0;
  z-index: 20;
}

/* The title block has to be allowed to shrink, or its longest word sets the page width. */
.topbar .titles {
  min-width: 0;
}

.topbar .titles h1 {
  overflow-wrap: anywhere;
}

.topbar .titles p {
  margin: 2px 0 0;
  font-size: 12.5px;
  color: var(--ink-500);
}

.topbar-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.content {
  padding: var(--space-5) var(--space-6) var(--space-7);
  flex: 1;
}

/* ---------------------------------------------------------------- controls */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: 36px;
  padding: 0 var(--space-4);
  border-radius: var(--radius-m);
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink-800);
  font: inherit;
  font-weight: 550;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease, transform 0.06s ease;
  white-space: nowrap;
}

.btn:hover {
  background: var(--surface-2);
}

.btn:active {
  transform: translateY(1px);
}

.btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.btn svg.icon {
  width: 17px;
  height: 17px;
}

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

.btn-primary:hover {
  background: var(--primary-strong);
  border-color: var(--primary-strong);
}

.btn-danger {
  color: var(--danger);
  border-color: var(--line-strong);
}

.btn-danger:hover {
  background: var(--danger-soft);
}

.btn-ghost {
  border-color: transparent;
  background: transparent;
}

.btn-ghost:hover {
  background: var(--surface-2);
}

.btn-small {
  height: 30px;
  padding: 0 var(--space-3);
  font-size: 13px;
}

label {
  display: block;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink-700);
  margin-bottom: var(--space-1);
}

input[type="text"],
input[type="email"],
input[type="tel"],
input[type="url"],
input[type="password"],
input[type="number"],
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="search"],
select,
textarea {
  width: 100%;
  height: 36px;
  padding: 0 var(--space-3);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-m);
  background: var(--surface);
  color: var(--ink-900);
  font: inherit;
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}

/* A 16px font is what stops iOS zooming in when a field is tapped. */
@media (max-width: 640px) {
  input[type="text"],
  input[type="email"],
  input[type="tel"],
  input[type="url"],
  input[type="password"],
  input[type="number"],
  input[type="date"],
  input[type="time"],
  input[type="datetime-local"],
  input[type="search"],
  select,
  textarea {
    font-size: 16px;
  }
}

textarea {
  height: auto;
  min-height: 92px;
  padding: var(--space-3);
  resize: vertical;
  line-height: 1.5;
}

input:focus,
select:focus,
textarea:focus,
.btn:focus-visible,
.nav a:focus-visible {
  outline: none;
  border-color: var(--brand-ink);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

.field {
  margin-bottom: var(--space-4);
}

.field-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--space-4);
}

.checkline {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.checkline input {
  width: auto;
  height: auto;
}

.checkline label {
  margin: 0;
  font-weight: 500;
}

/* ---------------------------------------------------------------- surfaces */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-1);
}

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

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

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

.grid {
  display: grid;
  gap: var(--space-4);
}

.grid-2 {
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}

.grid-3 {
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

.grid-4 {
  grid-template-columns: repeat(auto-fit, minmax(196px, 1fr));
}

.stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.spread {
  justify-content: space-between;
}

/* ---------------------------------------------------------------- stat tiles */

.stat {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-l);
  padding: var(--space-4) var(--space-5);
  box-shadow: var(--shadow-1);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.stat .label {
  font-size: 12.5px;
  color: var(--ink-500);
  font-weight: 550;
}

.stat .value {
  font-size: 28px;
  font-weight: 660;
  color: var(--ink-900);
  letter-spacing: -0.02em;
  line-height: 1.15;
}

.stat .foot {
  font-size: 12px;
  color: var(--ink-400);
}

.stat.accent-primary {
  border-left: 3px solid var(--primary);
}
.stat.accent-teal {
  border-left: 3px solid var(--teal);
}
.stat.accent-amber {
  border-left: 3px solid var(--amber);
}
.stat.accent-danger {
  border-left: 3px solid var(--danger);
}

.stat.clickable { cursor: pointer; }
.stat.clickable:hover, .stat.clickable:focus-visible { border-color: var(--primary); }

/* ---------------------------------------------------------------- tables */

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}

thead th {
  text-align: left;
  font-size: 11.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-400);
  font-weight: 650;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

tbody td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}

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

tbody tr.clickable {
  cursor: pointer;
}

tbody tr.clickable:hover {
  background: var(--surface-2);
}

/* Every other status in the report list. */
tbody tr.band {
  background: color-mix(in srgb, var(--primary) 5%, var(--surface));
}

tbody tr.band.clickable:hover {
  background: color-mix(in srgb, var(--primary) 10%, var(--surface));
}

/* A column header that sorts: the label with an up and a down arrow beside it. */
.sorteer {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  cursor: pointer;
}

.sorteer:hover, .sorteer:focus-visible { color: var(--ink-800); }
.sorteer-pijlen { display: inline-flex; }

/* The funnel in a column head, and the Excel style list it opens. */
.kolom-filter {
  display: inline-grid;
  place-items: center;
  margin-left: 4px;
  padding: 3px;
  border: 0;
  border-radius: var(--radius-s);
  background: none;
  color: var(--ink-400);
  vertical-align: middle;
  cursor: pointer;
}
.kolom-filter .icon { width: 13px; height: 13px; }
.kolom-filter:hover, .kolom-filter:focus-visible { color: var(--ink-800); background: var(--surface-2); outline: none; }
.kolom-filter.aan { color: var(--primary-strong); background: var(--primary-soft); }
.kolomfilter {
  position: fixed;
  z-index: 60;
  width: 270px;
  display: grid;
  gap: var(--space-2);
  padding: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-3);
  font-size: 13.5px;
}
.kolomfilter-sorteer, .kolomfilter-acties { display: flex; gap: var(--space-2); }
.kolomfilter-acties { justify-content: flex-end; }
.kolomfilter-lijst { max-height: 260px; overflow-y: auto; border: 1px solid var(--line); border-radius: var(--radius-s); padding: 2px 0; }
.kolomfilter-regel { display: flex; align-items: center; gap: var(--space-2); padding: 5px var(--space-3); cursor: pointer; color: var(--ink-900); }
.kolomfilter-regel:hover { background: var(--surface-2); }
.kolomfilter-regel input { width: auto; height: auto; margin: 0; }
.kolomfilter-regel.alles { font-weight: 600; border-bottom: 1px solid var(--line); }
.kolomfilter-regel.leeg span { font-style: italic; color: var(--ink-500); }
.kolomfilter-niets { margin: 0; padding: var(--space-2) var(--space-3); }

/* Report list: headers move by dragging and resize from the grip on their right edge. */
.meldingtabel thead th { position: relative; cursor: grab; user-select: none; }
.meldingtabel thead th.sleept { opacity: 0.45; }
.meldingtabel thead th.kolom-doel { box-shadow: inset 3px 0 0 var(--primary); }
.kolom-greep {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 9px;
  cursor: col-resize;
  touch-action: none;
}
.kolom-greep::after {
  content: "";
  position: absolute;
  top: 25%;
  bottom: 25%;
  right: 4px;
  border-right: 1px solid var(--line-strong);
}
.kolom-greep:hover::after { border-right: 2px solid var(--primary); }
table.vaste-kolommen { table-layout: fixed; min-width: 100%; }
table.vaste-kolommen th, table.vaste-kolommen td { overflow: hidden; text-overflow: ellipsis; }
table.vaste-kolommen td { overflow-wrap: anywhere; }

/* A picker with its button on one line, the button level with the field. */
.toewijs-regel { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-3); }
.toewijs-regel .field { margin-bottom: 0; flex: 1 1 160px; min-width: 0; max-width: 360px; }
.subkop { font-size: 13px; font-weight: 650; margin: var(--space-2) 0 0; }
.sorteer-pijlen .pijl { width: 12px; height: 12px; opacity: 0.45; }
.sorteer-pijlen .pijl.aan { opacity: 1; color: var(--primary); }

/* The step filter on the report list: the counts in a column on the right. */
.stapkiezer { position: relative; }
.stapkiezer-knop {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  height: 36px;
  padding: 0 var(--space-3);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-m);
  background: var(--surface);
  color: var(--ink-900);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.stapkiezer-knop:focus-visible {
  outline: none;
  border-color: var(--brand-ink);
  box-shadow: 0 0 0 3px var(--primary-soft);
}
.stapkiezer-naam { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stapkiezer-getal { min-width: 3ch; text-align: right; font-variant-numeric: tabular-nums; color: var(--ink-500); }
.stapkiezer-pijl { width: 14px; height: 14px; flex: 0 0 auto; }
.stapkiezer-lijst {
  position: absolute;
  z-index: 30;
  top: calc(100% + 4px);
  left: 0;
  min-width: 100%;
  max-height: 380px;
  overflow-y: auto;
  padding: var(--space-1) 0;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-2);
}
.stapkiezer-optie {
  display: flex;
  justify-content: space-between;
  gap: var(--space-5);
  width: 100%;
  padding: 7px var(--space-3);
  border: 0;
  background: none;
  color: var(--ink-900);
  font: inherit;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}
.stapkiezer-optie:hover, .stapkiezer-optie:focus-visible { background: var(--surface-2); outline: none; }
.stapkiezer-optie[aria-selected="true"] { font-weight: 650; }

/* A filter button that is switched on. */
.btn.aan {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--primary-strong);
}

.afrond-balk { border-color: var(--primary); }

/* A report row that opens its asset or location. */
.rij-link { color: var(--ink-800); text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 2px; }
.rij-link:hover { color: var(--primary); text-decoration-color: currentColor; }

/*
 * A grid or flex child has an automatic minimum of its own content, so one wide table
 * stretches its card, its track and in the end the page. Pinning the minimum to zero is
 * what lets the scroll happen inside the wrapper, which is where it belongs.
 */
.grid > *,
.split > *,
.stack > *,
.card > *,
.card-body > * {
  min-width: 0;
}

.table-wrap {
  overflow-x: auto;
  min-width: 0;
}

/* ---------------------------------------------------------------- badges */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 22px;
  padding: 0 9px;
  border-radius: 11px;
  font-size: 11.5px;
  font-weight: 620;
  letter-spacing: 0.01em;
  background: var(--surface-3);
  color: var(--ink-700);
  white-space: nowrap;
}

.badge::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

.badge.neutral {
  color: var(--ink-500);
}
.badge.info {
  background: var(--primary-soft);
  color: var(--primary-strong);
}
.badge.ok {
  background: var(--teal-soft);
  color: var(--teal);
}
.badge.warn {
  background: var(--amber-soft);
  color: var(--amber);
}
.badge.danger {
  background: var(--danger-soft);
  color: var(--danger);
}

/* ---------------------------------------------------------------- timeline */

.timeline {
  position: relative;
  padding-left: var(--space-5);
}

.timeline::before {
  content: "";
  position: absolute;
  left: 7px;
  top: 6px;
  bottom: 6px;
  width: 2px;
  background: var(--line);
}

.timeline-item {
  position: relative;
  padding: 0 0 var(--space-4);
}

.timeline-item::before {
  content: "";
  position: absolute;
  left: calc(var(--space-5) * -1 + 3px);
  top: 5px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--line-strong);
}

.timeline-item .when {
  font-size: 11.5px;
  color: var(--ink-400);
}

.timeline-item .what {
  color: var(--ink-800);
}

/* ---------------------------------------------------------------- chat */

.chat {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-height: 420px;
  overflow-y: auto;
  padding: var(--space-4) var(--space-5);
}

.bubble {
  max-width: 78%;
  padding: 9px var(--space-4);
  border-radius: var(--radius-l);
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-word;
}

.bubble.systeem {
  align-self: flex-start;
  background: var(--surface-3);
  color: var(--ink-800);
  border-bottom-left-radius: var(--radius-s);
}

.bubble.melder {
  align-self: flex-end;
  background: var(--primary);
  color: var(--on-primary);
  border-bottom-right-radius: var(--radius-s);
}

/* Kasper in Gesprek Intern. */
.bubble.kasper {
  background: color-mix(in srgb, var(--primary) 12%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--primary) 30%, transparent);
}

/* The two conversations on a report, as tabs in the card head. */
.chat-kop { gap: var(--space-3); }
.chat-tabs { display: flex; gap: var(--space-1); flex-wrap: wrap; min-width: 0; }
.chat-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px var(--space-3);
  border: 1px solid transparent;
  border-radius: var(--radius-m);
  background: none;
  color: var(--ink-500);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
}
.chat-tab:hover { color: var(--ink-900); }
.chat-tab.aan { color: var(--ink-900); background: var(--surface-2); border-color: var(--line); }
.chat-tab:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--primary-soft); }

/* The open report list for a coordinator: Jouw meldingen in a blue frame, then a straight bar
   with Kasper's meldingen, then the rest. Blue is fixed, not the house style's colour. Each
   heading folds its group away. */
.meldingtabel {
  --jouw-rand: color-mix(in srgb, var(--blauw) 55%, var(--surface));
}
.meldingtabel tr.jouw-kop td {
  padding: 2px 8px 0;
  border: 2px solid var(--jouw-rand);
  border-bottom: none;
}
.jouw-kop-tekst {
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 0.04em;
  color: var(--blauw);
}
.groep-knop {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  padding: 3px 8px;
  border: none;
  border-radius: var(--radius-s);
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  cursor: pointer;
}
.groep-knop:focus-visible { outline: 2px solid var(--blauw); outline-offset: -2px; }
.groep-knop .groep-pijl { width: 16px; height: 16px; transition: transform 0.15s; }
.groep-knop[aria-expanded="false"] .groep-pijl { transform: rotate(-90deg); }
.groep-knop[aria-expanded="true"] .groep-aantal { display: none; }
.groep-aantal { font-weight: 500; }
.card.jouw-dicht .meldingtabel tr.jouw,
.card.kasper-dicht .meldingtabel tr.kasper { display: none; }
.card.jouw-dicht .meldingtabel tr.jouw-kop td { border-bottom: 2px solid var(--jouw-rand); }
.meldingtabel tr.jouw td:first-child { border-left: 2px solid var(--jouw-rand); }
.meldingtabel tr.jouw td:last-child { border-right: 2px solid var(--jouw-rand); }
.meldingtabel tr.jouw-laatst td { border-bottom: 2px solid var(--jouw-rand); }
.meldingtabel tr.jouw-leeg td { padding: 18px 12%; }
.jouw-streep { display: block; width: 100%; height: 10px; fill: var(--jouw-rand); }
.meldingtabel tr.actiebalk td {
  padding: 2px 8px;
  background: var(--primary-soft);
  border-top: 2px solid var(--primary);
  border-bottom: 2px solid var(--primary);
}
.actiebalk-inhoud {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  /* Ink, not the brand colour: a light brand colour on its own tint cannot be read. */
  color: var(--ink-900);
}
.actiebalk-inhoud .groep-tekst {
  font-weight: 650;
  letter-spacing: 0.03em;
  white-space: nowrap;
}
.prio-kritiek { color: var(--danger); font-weight: 600; }

/* The engineer form: a building, and next to it whether this person is primary there. */
.gebouw-primair { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); }
.gebouw-primair .checkline { margin: 0; }
.primair-keuze input:disabled + span { opacity: 0.45; }

/* The floors of a new building: a bar of chips and two tiles to add one below or above. */
.verdiepingen-balk {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding: var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius, 10px);
  background: var(--surface-2);
}
.verdieping-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 28px;
  padding: 0 4px 0 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  font-size: 13px;
}
.verdieping-chip:not(:has(button)) { padding-right: 10px; }
/* A floor the building already has: it stays, so it reads quieter than a new one. */
.verdieping-chip.vast { background: transparent; color: var(--ink-500); border-style: dashed; }
.verdieping-weg {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-500);
  cursor: pointer;
}
.verdieping-weg:hover { background: var(--surface-2); color: var(--danger); }
.verdieping-weg .icon { width: 12px; height: 12px; }
.verdiepingen-tegels { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
.verdieping-tegel { justify-content: center; border: 1px dashed var(--line-strong); }

/* What the postcode lookup found, between the postcode and the street. */
.adres-status { margin: calc(-1 * var(--space-2)) 0 var(--space-3); }

/* Instellingen: the heading above the workflow and routing design. */
.instellingen-kop { margin: var(--space-4) 0 0; font-size: 18px; }

/* The defaults of the action bar, listed in its settings card. */
.actiebalk-standaard { margin: 0; padding-left: 18px; }

/* Kaspers meldingen in the topbar of the dashboard. */
.kasper-teller {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 0 6px;
  border: none;
  background: none;
  color: var(--ink-700);
  font-size: 13px;
  white-space: nowrap;
}
button.kasper-teller { cursor: pointer; }
button.kasper-teller:hover { color: var(--ink-900); text-decoration: underline; }
.kasper-teller strong { color: var(--ink-900); font-size: 14px; font-weight: 700; }
.kasper-label-kort { display: none; }
@media (max-width: 860px) {
  .kasper-label { display: none; }
  .kasper-label-kort { display: inline; }
}
.actie-reden {
  color: var(--danger);
}

.intern-stip {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--danger);
  margin-right: 6px;
  vertical-align: middle;
}
.nav-telling {
  margin-left: auto;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--danger);
  color: var(--on-accent);
  font-size: 11px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
}

.bubble-van {
  font-size: 11.5px;
  opacity: 0.75;
  margin-bottom: 2px;
}

.chat-form {
  display: flex;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-5) var(--space-4);
  border-top: 1px solid var(--line);
}

.chat-form input {
  flex: 1;
}

/* ---------------------------------------------------------------- misc */

.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-3);
  padding: var(--space-7) var(--space-5);
  color: var(--ink-500);
}

.empty svg {
  width: 132px;
  height: 132px;
  color: var(--line-strong);
}

.toast-host {
  position: fixed;
  right: var(--space-5);
  bottom: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  z-index: 200;
  max-width: 380px;
}

.toast {
  background: var(--ink-900);
  color: #fff;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-3);
  font-size: 13px;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}

:root[data-thema="donker"] .toast {
  background: var(--surface-3);
  border: 1px solid var(--line-strong);
}

:root[data-thema="donker"] .toast.fout {
  background: var(--danger-soft);
  border-color: var(--danger);
}

.toast.fout {
  background: var(--danger);
}

.modal-host {
  position: fixed;
  inset: 0;
  background: rgba(13, 20, 36, 0.45);
  display: grid;
  place-items: center;
  padding: var(--space-5);
  z-index: 150;
  overflow-y: auto;
}

.modal {
  width: 100%;
  max-width: 640px;
  background: var(--surface);
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-3);
  border: 1px solid var(--line);
  max-height: 92vh;
  display: flex;
  flex-direction: column;
}

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--line);
}

.modal-body {
  padding: var(--space-5);
  overflow-y: auto;
}

.modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--line);
}

.deflist {
  display: grid;
  grid-template-columns: 168px 1fr;
  gap: var(--space-2) var(--space-4);
  font-size: 13.5px;
}

.deflist dt {
  color: var(--ink-500);
  font-weight: 550;
}

.deflist dd {
  margin: 0;
  color: var(--ink-800);
}

.legend {
  display: flex;
  gap: var(--space-4);
  font-size: 12px;
  color: var(--ink-500);
}

.legend span {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.legend i {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  display: inline-block;
}

.qr-panel {
  display: flex;
  align-items: center;
  gap: var(--space-5);
}

.qr-panel img {
  width: 148px;
  height: 148px;
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  background: #fff;
  padding: var(--space-2);
}

.spec-grid {
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  gap: var(--space-2);
  align-items: center;
}

/* Documents on an asset: the column heads, and room for the file picker. */
.doc-kop { font-size: 12px; font-weight: 600; color: var(--ink-500); margin-top: var(--space-2); }
.doc-kop > span:last-child { width: 32px; }
.doc-rij input.verborgen, .doc-drop input.verborgen { display: none; }
.doc-vak.doc-drop.over { border-color: var(--primary); background: color-mix(in srgb, var(--primary) 8%, var(--surface-2)); }
.doc-vak .doc-kop { margin-top: 0; }
/* Documents are dropped on the whole block: the form part and the card on the asset page. */
.card.over { border-color: var(--primary); background: color-mix(in srgb, var(--primary) 6%, var(--surface)); }
.card.over { outline: 2px dashed var(--primary); outline-offset: -2px; }

.candidate {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  cursor: pointer;
  background: var(--surface);
  text-align: left;
  width: 100%;
  font: inherit;
  color: inherit;
}

.candidate:hover {
  border-color: var(--primary);
  background: var(--primary-soft);
}

.candidate.chosen {
  border-color: var(--primary);
  background: var(--primary-soft);
}

.score {
  font-size: 11.5px;
  font-weight: 650;
  color: var(--ink-500);
}

.steps {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
}

.step {
  /*
   * Zero basis and no minimum, so four steps divide the width instead of insisting on the
   * width of their own text. A flex item defaults to min-width auto, which is what pushed
   * the last step two pixels off a phone screen.
   */
  flex: 1 1 0;
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-m);
  background: var(--surface-3);
  color: var(--ink-500);
  font-size: 12.5px;
  font-weight: 600;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.step.now {
  background: var(--primary);
  color: var(--on-primary);
}

.step.done {
  background: var(--teal-soft);
  color: var(--teal);
}

/* A step already reached, which can be clicked to go back to it. */
.step.step-link {
  border: 0;
  font: inherit;
  cursor: pointer;
}

.step.step-link:hover,
.step.step-link:focus-visible {
  text-decoration: underline;
  outline: none;
}

.flow-nodes {
  display: grid;
  gap: var(--space-2);
}

.flow-node {
  display: grid;
  grid-template-columns: 128px 1fr;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  font-size: 13px;
  background: var(--surface);
}

.flow-node .kind {
  font-size: 11.5px;
  font-weight: 650;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-400);
}

.flow-node.current {
  border-color: var(--primary);
  background: var(--primary-soft);
}

.split {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: var(--space-4);
  align-items: start;
}

@media (max-width: 1080px) {
  .split {
    grid-template-columns: 1fr;
  }
}

/* Signing out at the very bottom of the page, on a phone only. */
.mobiel-voet { display: none; }

@media (max-width: 860px) {
  .sidebar-foot { display: none; }
  .mobiel-voet {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-top: var(--space-6);
    padding: var(--space-4);
    border-top: 1px solid var(--line);
    background: var(--surface);
  }
  .nav a { position: relative; }
  .nav-telling { position: absolute; top: 2px; right: 2px; margin: 0; }

  .shell {
    /* minmax rather than 1fr: without the zero minimum the horizontal nav below sets the
       track to its own content width and the whole page scrolls sideways. */
    grid-template-columns: minmax(0, 1fr);
  }

  .sidebar {
    position: static;
    height: auto;
    min-width: 0;
    border-right: none;
    border-bottom: 1px solid var(--line);
  }

  .sidebar-brand,
  .sidebar-foot,
  .who,
  .content,
  .topbar {
    min-width: 0;
  }

  .nav {
    flex-direction: row;
    overflow-x: auto;
    min-width: 0;
  }

  .nav a span {
    display: none;
  }

  .content,
  .topbar {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }

  .deflist {
    grid-template-columns: 1fr;
    gap: var(--space-1) 0;
  }
}

/* ---------------------------------------------------------------- mail wizard */

.method-option {
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  padding: var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  background: var(--surface);
  cursor: pointer;
  transition: border-color 0.12s ease, background 0.12s ease;
}

.method-option:hover:not(:disabled) {
  border-color: var(--primary);
}

.method-option.chosen {
  border-color: var(--primary);
  background: var(--primary-soft);
}

.method-option.unavailable {
  cursor: not-allowed;
  opacity: 0.7;
  background: var(--surface-2);
}

.method-option p {
  margin: 0;
}

.guide-step {
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: var(--space-4);
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--line);
}

.guide-step:last-of-type {
  border-bottom: none;
}

.guide-index {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--primary-soft);
  color: var(--primary-strong);
  display: grid;
  place-items: center;
  font-size: 12.5px;
  font-weight: 650;
}

.guide-portal {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  background: var(--surface-2);
  border-radius: var(--radius-s);
  color: var(--ink-700);
  margin-bottom: var(--space-2);
}

.guide-portal svg {
  width: 15px;
  height: 15px;
  flex: 0 0 auto;
  color: var(--ink-400);
}

.code-wrap {
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  overflow: hidden;
  margin-top: var(--space-2);
}

.code-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 5px var(--space-3);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}

pre.code {
  margin: 0;
  padding: var(--space-4);
  background: var(--surface);
  font-family: var(--mono);
  font-size: 12.5px;
  line-height: 1.6;
  white-space: pre;
  overflow-x: auto;
  color: var(--ink-800);
}

:root[data-thema="donker"] pre.code {
  background: var(--surface-3);
}

.check {
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  background: var(--surface);
}

.check svg {
  width: 17px;
  height: 17px;
}

.check pre.code {
  margin-top: var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--surface-2);
  font-size: 12px;
  white-space: pre-wrap;
}

/* ---------------------------------------------------------------- utilities

   The content security policy forbids the style attribute, so anything that would
   have been an inline style lives here. Values that are computed at runtime are set
   through the CSSOM instead, which the policy does allow.
*/

.gap-2 { gap: 2px; }
.gap-4 { gap: 4px; }
.gap-6 { gap: 6px; }
.gap-8 { gap: 8px; }
.gap-10 { gap: 10px; }
.gap-12 { gap: 12px; }

.mt-6 { margin-top: 6px; }
.mt-8 { margin-top: 8px; }

.note { margin: 6px 0 0; }
.note-tight { margin: 4px 0 0; }
.note-loose { margin: 8px 0 0; }

.minw0 { min-width: 0; }
/* A button that reads as a link, in the link colour of the house style. */
.linkknop { display: block; margin-top: 2px; padding: 0; border: 0; background: none; color: var(--brand-ink); font: inherit; text-align: left; white-space: nowrap; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.linkknop.small { font-size: 12.5px; }
.component-acties { flex-wrap: nowrap; justify-content: flex-end; }
.wrap { flex-wrap: wrap; }

/* Audit log: the search takes the room, the period and the reset sit beside it. */
.auditfilters { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 8px; }
.auditfilters .zoekveld { flex: 1 1 240px; min-width: 0; }
.auditfilters select { width: auto; max-width: 100%; }
.audittabel td, .wijzigtabel td { vertical-align: top; }
.audittabel .tijd { white-space: nowrap; }
.wijzigtabel pre.code {
  padding: 6px 8px;
  max-width: 420px;
  font-size: 12px;
  white-space: pre-wrap;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--surface-2);
}
.strong { font-weight: 600; }
.weight-normal { font-weight: 500; }

.form-error {
  color: var(--danger);
  min-height: 18px;
}

/* Filter bar columns, so a row of controls keeps its proportions when it wraps. */
.col-search { flex: 2; min-width: 240px; }
.col-filter { flex: 1; min-width: 160px; }
.col-filter-wide { flex: 1.5; min-width: 180px; }

.panel {
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
}

.panel-soft {
  padding: var(--space-3);
  background: var(--surface-2);
  border-radius: var(--radius-m);
}

.mail-body {
  white-space: pre-wrap;
  font-family: inherit;
  margin: 0;
  padding: var(--space-3);
  background: var(--surface-2);
  border-radius: var(--radius-m);
}

.secret-reveal {
  word-break: break-all;
  padding: var(--space-3);
  background: var(--surface-3);
  border-radius: var(--radius-s);
  font-family: var(--mono);
}

.meter {
  height: 6px;
  border-radius: 3px;
  background: var(--surface-3);
  overflow: hidden;
}

.meter-fill {
  height: 100%;
  background: var(--primary);
  border-radius: 3px;
}

.legend i.legend-primary { background: var(--primary); }
.legend i.legend-teal { background: var(--teal); }

/* The sprite sheets are injected into the document and must never render. */
#sprites { display: none; }


/* ---------------------------------------------------------------- status pipeline */

.pipeline {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.pipe-track {
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: var(--space-2);
}

/* The supplier row has six steps, the technical services row four. */
.pipe-track.stappen-6, .stage-counts.stappen-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
.pipe-track.stappen-4, .stage-counts.stappen-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.pipe-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: var(--space-2) 4px;
  border-radius: var(--radius-m);
  border: 1px solid var(--line);
  background: var(--surface-2);
  text-align: center;
  min-width: 0;
}

.pipe-step.clickable { cursor: pointer; }
.pipe-step.clickable:hover { border-color: var(--line-strong); }

.pipe-dot {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink-500);
  font-size: 12px;
  font-weight: 600;
  flex: none;
}

.pipe-label {
  font-size: 11px;
  line-height: 1.25;
  color: var(--ink-500);
  overflow-wrap: anywhere;
}

.pipe-step.done { border-color: var(--teal); background: var(--teal-soft); }
.pipe-step.done .pipe-dot { background: var(--teal); border-color: var(--teal); color: var(--on-accent); }
.pipe-step.done .pipe-label { color: var(--ink-700); }

.pipe-step.now { border-color: var(--primary); background: var(--primary-soft); }
.pipe-step.now .pipe-dot { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.pipe-step.now .pipe-label { color: var(--ink-900); font-weight: 600; }

/* Not applicable, not skipped: nothing was missed, this route simply does not apply. */
.pipe-step.nvt { background: transparent; border-style: dashed; opacity: 0.55; }
.pipe-step.nvt .pipe-label { text-decoration: line-through; }

.pipe-step.off { opacity: 0.4; }

@media (max-width: 900px) {
  .pipe-track { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .pipe-track.stappen-6, .stage-counts.stappen-6 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ---------------------------------------------------------------- stage counts */

.stage-counts {
  display: grid;
  grid-template-columns: repeat(8, minmax(0, 1fr));
  gap: 6px;
}

.stage-count {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  gap: 1px;
  padding: 6px var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  background: var(--surface-2);
  min-width: 0;
}

.stage-count.clickable { cursor: pointer; }
.stage-count.clickable:hover { border-color: var(--primary); }
.stage-count.has-open { background: var(--primary-soft); border-color: var(--primary); }
.stage-count.geen-open { opacity: 0.75; }

/* The step number in the corner, so a cell is three lines rather than four. */
.stage-index { position: absolute; top: 5px; right: 7px; font-size: 10px; color: var(--ink-400); }
.stage-value { font-size: 18px; font-weight: 650; color: var(--ink-900); line-height: 1.1; }
.stage-label { font-size: 11px; color: var(--ink-500); overflow-wrap: anywhere; }
.stage-foot { font-size: 10px; color: var(--ink-400); }

@media (max-width: 900px) {
  .stage-counts { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.chip {
  border: 1px solid var(--line);
  background: var(--surface-2);
  border-radius: 999px;
  padding: 4px var(--space-3);
  font: inherit;
  font-size: 12px;
  color: var(--ink-500);
  cursor: pointer;
}

.chip:hover { border-color: var(--primary); color: var(--ink-800); }

.chip.on {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--primary-strong);
  font-weight: 600;
}

.chips {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}

/* A photo on a record, shown at a size that is actually readable. */
.record-photo {
  display: block;
  width: 100%;
  max-width: 320px;
  border-radius: var(--radius-m);
  border: 1px solid var(--line);
}

/* ---------------------------------------------------------------- pickers */

.picker {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.picker-results,
.picker-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 260px;
  overflow-y: auto;
}

.picker-option {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  align-items: baseline;
  text-align: left;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--surface);
  font: inherit;
  color: var(--ink-800);
  cursor: pointer;
}

.picker-option:hover { border-color: var(--primary); background: var(--primary-soft); }

.picker-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 4px var(--space-2);
  border-radius: var(--radius-s);
  font-weight: 400;
  cursor: pointer;
}

.picker-row:hover { background: var(--surface-2); }

.picker-chosen { min-height: 22px; }

/* ---------------------------------------------------------------- attachments */

.thumbs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: var(--space-3);
}

.thumbs a {
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-decoration: none;
}

.thumbs img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-m);
  border: 1px solid var(--line);
  background: var(--surface-2);
}

/* A fact tile holds a sentence rather than a number, so it needs a smaller size. */
.stat .value-small {
  font-size: 17px;
  line-height: 1.3;
  overflow-wrap: anywhere;
}


/* ---------------------------------------------------------------- notifications */

.bell-host {
  position: relative;
  display: flex;
}

.bell {
  position: relative;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-m);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-500);
  cursor: pointer;
}

.bell:hover { border-color: var(--line-strong); color: var(--ink-800); }
.bell.has-unread { color: var(--danger); border-color: var(--danger); }

.bell-count {
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  border-radius: 9px;
  background: var(--danger);
  color: var(--on-accent);
  font-size: 11px;
  line-height: 18px;
  text-align: center;
  font-weight: 600;
}

.bell-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: min(360px, calc(100vw - 32px));
  z-index: 40;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-3);
  overflow: hidden;
}

.bell-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3);
  border-bottom: 1px solid var(--line);
}

.bell-list {
  max-height: 380px;
  overflow-y: auto;
}

.bell-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-3);
  border-bottom: 1px solid var(--line);
  border-left: 3px solid transparent;
  cursor: pointer;
}

.bell-item:last-child { border-bottom: none; }
.bell-item:hover { background: var(--surface-2); }
.bell-item.ongelezen { background: var(--surface-2); }
.bell-item.ongelezen .bell-title { font-weight: 600; }
.bell-item.waarschuwing { border-left-color: var(--amber); }
.bell-item.urgent { border-left-color: var(--danger); }

.bell-title {
  color: var(--ink-900);
  font-size: 13.5px;
}


/* ---------------------------------------------------------------- branding */

.sidebar-brand .brand-logos {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

/* The customer mark sits beside ours, separated by a rule so neither looks like part of
   the other. Height bound, width free: a wordmark and a square mark both have to fit. */
.brand-customer {
  max-height: 26px;
  max-width: 92px;
  object-fit: contain;
  padding-left: var(--space-2);
  border-left: 1px solid var(--line);
}

.login-brand .brand-customer {
  max-height: 34px;
  max-width: 120px;
}

/* With a customer logo: theirs centred above the menu, ours at the top centre. */
.sidebar-brand.met-klantlogo .brand-klant {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: center;
  min-width: 0;
}

.sidebar-brand.met-klantlogo .brand-customer {
  width: auto;
  height: auto;
  max-height: 64px;
  max-width: 100%;
  padding-left: 0;
  border-left: none;
}

.topbar.met-merk {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
}

.topbar.met-merk .topbar-actions {
  justify-self: end;
}

.topbar-merk,
.merk-midden-mobiel {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: 650;
  color: var(--ink-900);
  letter-spacing: -0.02em;
  white-space: nowrap;
}

.topbar-merk img,
.merk-midden-mobiel img {
  width: 28px;
  height: 28px;
}

.merk-midden-mobiel { display: none; }

@media (max-width: 1080px) {
  .topbar-merk span { display: none; }
}

/* On a phone the sidebar is the bar at the top, so our mark sits in its centre. */
@media (max-width: 860px) {
  .topbar-merk { display: none; }
  .topbar.met-merk { display: flex; }
  .sidebar-brand.met-klantlogo {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    padding-bottom: var(--space-3);
  }
  .sidebar-brand.met-klantlogo .brand-klant { justify-content: flex-start; }
  .sidebar-brand.met-klantlogo .brand-customer { max-height: 32px; }
  .merk-midden-mobiel { display: flex; }
}

.swatch-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.swatch-row input[type="color"] {
  width: 46px;
  height: 34px;
  padding: 2px;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--surface);
  cursor: pointer;
}

.brand-preview {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  background: var(--surface-2);
}


/* ---------------------------------------------------------------- tabs */

/* Tabs across the top of a page. They scroll sideways on a phone rather than wrapping. */
.tabs {
  display: flex;
  gap: var(--space-1);
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
  scrollbar-width: none;
}

.tab {
  padding: var(--space-2) var(--space-3);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  color: var(--ink-500);
  font-weight: 600;
  font-size: 14px;
  text-decoration: none;
  white-space: nowrap;
}

.tab:hover { color: var(--ink-800); }
.tab.active { color: var(--brand-ink); border-bottom-color: var(--primary); }

/* ---------------------------------------------------------------- signature */

/* The name as a signature, in a decorative script. White behind the image, in both themes. */
.sierlijk {
  font-family: "Segoe Script", "Brush Script MT", "Snell Roundhand", "Apple Chancery", cursive;
  font-size: 1.15em;
}

canvas.signature {
  display: block;
  width: 100%;
  max-width: 560px;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  background: #ffffff;
}

/* ---------------------------------------------------------------- LMRA */

/* A line with its Ja and Nee boxes. The text wraps; the boxes keep their width on a phone. */
.lmra-list { display: flex; flex-direction: column; gap: var(--space-1); }

.lmra-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-3);
  padding: 6px var(--space-2);
  border-radius: var(--radius-s);
}

.lmra-item + .lmra-item { border-top: 1px solid var(--line); }
.lmra-row.open { background: var(--amber-soft); }
.lmra-row.blokkeert { background: var(--danger-soft); }
.lmra-tekst { font-size: 14px; overflow-wrap: anywhere; }
.lmra-vinken { display: flex; gap: var(--space-2); }

.lmra-vink {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--surface);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.lmra-vink input { width: 18px; height: 18px; margin: 0; accent-color: var(--primary); }

/* Follow-up lines of a hazard that applies. */
.lmra-sub {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin: var(--space-1) 0 var(--space-2) var(--space-3);
  padding-left: var(--space-3);
  border-left: 3px solid var(--amber);
}

.lmra-note { padding: var(--space-1) var(--space-2) var(--space-2); }

/* Start or send, pinned to the bottom of the screen while the LMRA is in view. */
.lmra-acties {
  position: sticky;
  bottom: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3) 0;
  border-top: 1px solid var(--line);
  background: var(--surface);
}

/* On a phone every line gets the full width, with thumb sized Ja and Nee underneath. */
@media (max-width: 640px) {
  .lmra-row { grid-template-columns: minmax(0, 1fr); gap: var(--space-2); padding: var(--space-2); }
  .lmra-vinken { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; max-width: 260px; }
  .lmra-vink { min-height: 44px; justify-content: center; font-size: 15px; }
  .lmra-vink input { width: 22px; height: 22px; }
  .lmra-sub { margin-left: 0; padding-left: var(--space-2); }
  .lmra-acties .btn { flex: 1 1 100%; min-height: 44px; justify-content: center; }
}

/* ---------------------------------------------------------------- inline notice */

.notice-warn {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--amber);
  border-left-width: 3px;
  border-radius: var(--radius-m);
  background: var(--amber-soft);
  margin-bottom: var(--space-3);
}

.notice-warn .panel { background: var(--surface); }

/* ---------------------------------------------------------------- location tree */

/* Locations as widgets: a box per location, sublocations as boxes inside it. */
.locwidgets { display: flex; flex-direction: column; gap: var(--space-4); }
/* Under the buildings: the place a new one is made, for the system administrator only. */
.locwidget-nieuw {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border: 1px dashed var(--line-strong);
  border-left: 4px solid var(--teal);
  border-radius: var(--radius-l);
}
.locwidget-nieuw p { margin: 0; }
.locwidget {
  --soort: var(--line-strong);
  border: 1px solid var(--line);
  border-left: 4px solid var(--soort);
  border-radius: var(--radius-m);
  background: var(--surface);
  min-width: 0;
}
.locwidget.depth-0 { border-radius: var(--radius-l); box-shadow: var(--shadow-1); }
.locwidget.depth-1, .locwidget.depth-3 { background: var(--surface-2); }
.locwidget.soort-terrein { --soort: var(--primary); }
.locwidget.soort-gebouw { --soort: var(--teal); }
.locwidget.soort-verdieping { --soort: var(--amber); }
.locwidget.soort-ruimte { --soort: var(--ink-300); }
.locwidget-kop { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); min-width: 0; border-radius: inherit; }
.locwidget.depth-0 > .locwidget-kop { padding: var(--space-4) var(--space-5); }
.locwidget-kop.clickable { cursor: pointer; }
.locwidget-kop.clickable:hover { background: color-mix(in srgb, var(--soort) 7%, transparent); }
.locwidget-toggle {
  flex: none;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--surface);
  color: var(--ink-500);
  cursor: pointer;
}
.locwidget-toggle:hover, .locwidget-toggle:focus-visible { border-color: var(--soort); color: var(--ink-800); }
.locwidget-toggle .icon { width: 16px; height: 16px; transform: rotate(-90deg); transition: transform 0.15s; }
.locwidget.open > .locwidget-kop .locwidget-toggle .icon { transform: none; }
.locwidget-leeg { flex: none; width: 28px; }
.locwidget-titel { flex: 1; min-width: 0; display: grid; gap: 2px; }
.locwidget-naam {
  justify-self: start;
  max-width: 100%;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-weight: 600;
  color: var(--ink-900);
  text-align: left;
  overflow-wrap: anywhere;
  cursor: pointer;
}
.locwidget.depth-0 > .locwidget-kop .locwidget-naam { font-size: 16px; }
button.locwidget-naam:hover, button.locwidget-naam:focus-visible { color: var(--primary); text-decoration: underline; }
.locwidget-meta { display: flex; flex-wrap: wrap; gap: 2px 12px; font-size: 12.5px; color: var(--ink-500); }
.locwidget-meta .ontbreekt { color: var(--amber); font-weight: 600; }

/* The building address in the location form, and the installation on a drawing. */
.adres-veld,
.installatie-veld { border: 1px solid var(--line); border-radius: var(--radius-m); padding: var(--space-3); margin: 0 0 var(--space-4); }
.adres-veld legend,
.installatie-veld legend { padding: 0 var(--space-1); font-weight: 600; font-size: 13px; }
.vinklijst { max-height: 220px; overflow-y: auto; border: 1px solid var(--line); border-radius: var(--radius-s); padding: var(--space-2); margin-top: var(--space-2); display: flex; flex-direction: column; gap: 2px; }
.locwidget-acties { flex: none; }
.locwidget-inhoud {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: 0 var(--space-4) var(--space-4) calc(var(--space-4) + 28px + var(--space-3));
}
.locwidget.depth-0 > .locwidget-inhoud { padding-left: calc(var(--space-5) + 28px + var(--space-3)); padding-right: var(--space-5); }
/* A phone: the actions get their own line under the name, and the nesting stays shallow. */
@media (max-width: 640px) {
  .locwidget-kop, .locwidget.depth-0 > .locwidget-kop { flex-wrap: wrap; padding: var(--space-3) var(--space-3) var(--space-2); gap: var(--space-2); }
  .locwidget-titel { flex: 1 1 0; }
  .locwidget-acties { flex-basis: 100%; justify-content: flex-end; gap: var(--space-1); }
  .locwidget-leeg { display: none; }
  .locwidget-inhoud, .locwidget.depth-0 > .locwidget-inhoud { padding: 0 var(--space-2) var(--space-2) var(--space-2); }
}

.cascade {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}


/* ---------------------------------------------------------------- reporting */

.widget-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: var(--space-4);
  align-items: start;
}


/* ---------------------------------------------------------------- workflow phases */

.phase-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: 6px var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--surface-2);
  font: inherit;
  font-size: 13px;
  color: var(--ink-800);
  text-align: left;
  cursor: pointer;
}

.phase-head:hover { border-color: var(--brand-ink); }
.phase-head .small { margin-left: auto; }
.phase-head .small + .small { margin-left: 0; }

.phase-toggle {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  flex: none;
  border-radius: var(--radius-s);
  background: var(--surface-3);
  font-size: 12px;
  line-height: 1;
}

.phase-body {
  padding-left: var(--space-3);
  margin-bottom: var(--space-2);
}

/* ---------------------------------------------------------------- inline priority */

/*
 * The native dropdown arrow is dropped for a drawn caret. It saves about twenty pixels,
 * which on a pill this size is most of what made it look like a button rather than a
 * label.
 */
.prio-select {
  width: auto;
  flex: none;
  height: 19px;
  padding: 0 13px 0 6px;
  font-size: 10px;
  letter-spacing: 0.01em;
  line-height: 1;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: var(--surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 5'%3E%3Cpath d='M0 0l4 5 4-5z' fill='%2364748b'/%3E%3C/svg%3E") no-repeat right 5px center / 6px 4px;
  color: var(--ink-800);
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
}

.prio-select.danger { border-color: var(--danger); color: var(--danger); }
.prio-select.warn { border-color: var(--amber); color: var(--amber); }
.prio-select.info { border-color: var(--primary); }


/* ---------------------------------------------------------------- drawings */

.drawing-split {
  grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr);
}

.drawing-canvas {
  position: relative;
  display: inline-block;
  max-width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  overflow: hidden;
  background: var(--surface-2);
}

.drawing-canvas.dropping {
  outline: 2px dashed var(--brand-ink);
  outline-offset: -4px;
}

.drawing-image {
  display: block;
  max-width: 100%;
  height: auto;
}

/* The floor plan laid over another drawing, where the alignment puts it: faint and grey, so
   the technical drawing and its text stay readable. The slider beside it sets the opacity. */
.plattegrond-overlay {
  position: absolute;
  max-width: none;
  opacity: 0.18;
  mix-blend-mode: multiply;
  filter: grayscale(1);
  pointer-events: none;
}

/* A room that no longer matched after an update. */
.zone.controleren {
  stroke: var(--amber);
  stroke-dasharray: 8 6;
  stroke-opacity: 1;
}

.drawing-thumb {
  width: 160px;
  height: 110px;
  object-fit: cover;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--surface-2);
}

/* Pins are placed as a percentage of the image, so they survive a rescan at another size.
   The transform pulls the marker onto the point rather than beside it. */
.pin {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  gap: 4px;
  cursor: pointer;
  white-space: nowrap;
}

.pin-dot {
  width: 12px;
  height: 12px;
  flex: none;
  border-radius: 50%;
  border: 2px solid var(--surface);
  background: var(--primary);
  box-shadow: var(--shadow-1);
}

.pin.asset .pin-dot { background: var(--teal); }

.pin:hover .pin-dot,
.pin:focus-visible .pin-dot {
  transform: scale(1.35);
  outline: none;
}

.pin-dot { transition: transform 90ms ease-out; }

/*
 * What a marker stands for, opened from the marker itself.
 *
 * Names used to be printed next to every dot, which on a floor with forty installations is
 * a plan nobody can read. This card carries the same information plus the things somebody
 * standing in front of the machine actually wants to do, and it is positioned against the
 * plan so it moves with the drawing.
 */
.pin-card {
  position: absolute;
  z-index: 6;
  transform: translate(14px, -50%);
  width: 250px;
  max-width: calc(100vw - 48px);
  padding: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  background: var(--surface);
  box-shadow: var(--shadow-2, var(--shadow-1));
  white-space: normal;
}

/* Near the right or bottom edge the card would hang off the plan, so it swaps sides. */
.pin-card.flip-x { transform: translate(calc(-100% - 14px), -50%); }
.pin-card.flip-y { transform: translate(14px, calc(-100% + 14px)); }
.pin-card.flip-x.flip-y { transform: translate(calc(-100% - 14px), calc(-100% + 14px)); }

.pin-card .deflist {
  grid-template-columns: auto minmax(0, 1fr);
  gap: 2px var(--space-2);
  margin: 0;
}

/* The cross that takes a drawn outline off the plan. Only drawn while drawing is on. */
.zone-remove {
  cursor: pointer;
  pointer-events: auto;
}

.zone-remove circle {
  fill: var(--surface);
  stroke: var(--danger, #c8102e);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

.zone-remove path {
  stroke: var(--danger, #c8102e);
  stroke-width: 2.5;
  stroke-linecap: round;
  fill: none;
  vector-effect: non-scaling-stroke;
}

.zone-remove:hover circle { fill: var(--danger, #c8102e); }
.zone-remove:hover path { stroke: var(--surface); }

/*
 * The plan on the whole screen. The browser paints a black backdrop behind a full screen
 * element, so the panel has to bring its own background or the page reads as broken.
 */
.drawing-panel:fullscreen,
.drawing-panel.fullscreen-fallback {
  background: var(--surface);
  overflow: auto;
}

.drawing-panel:fullscreen .card-body,
.drawing-panel.fullscreen-fallback .card-body {
  min-height: 100%;
}

.drawing-panel:fullscreen .drawing-canvas,
.drawing-panel.fullscreen-fallback .drawing-canvas {
  display: block;
  width: 100%;
}

.drawing-panel.fullscreen-fallback {
  position: fixed;
  inset: 0;
  z-index: 40;
  border-radius: 0;
}

.drag-item {
  padding: 5px var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--surface);
  cursor: grab;
}

.drag-item:hover { border-color: var(--brand-ink); }
.drag-item:active { cursor: grabbing; }


@media (max-width: 900px) {
  .drawing-split { grid-template-columns: minmax(0, 1fr); }
}


/* A deploy happened while this tab was open. Offered, not forced: somebody may be halfway
   through a report. */
.update-bar {
  position: fixed;
  bottom: var(--space-4);
  left: 50%;
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface);
  box-shadow: var(--shadow-3);
  font-size: 13px;
}


/* ---------------------------------------------------------------- printing */

/*
 * The print sheet lives in the page rather than in an iframe or a popup: an iframe loses
 * the stylesheet and the logo, and a phone blocks the popup. While `body.printing` is on,
 * everything but the sheet is out of the flow, so the paper carries only the sheet.
 */

#printsheet { display: none; }

body.printing > *:not(#printsheet) { display: none !important; }

body.printing #printsheet { display: block; }

.print-sheet {
  background: #fff;
  color: #111;
  padding: 0;
}

.print-head { margin-bottom: 8px; }

.print-canvas {
  position: relative;
  display: inline-block;
  max-width: 100%;
  border: 1px solid #999;
}

.print-canvas img {
  display: block;
  max-width: 100%;
  height: auto;
}

.print-pin {
  position: absolute;
  transform: translate(-50%, -50%);
  display: grid;
  place-items: center;
  width: 16px;
  height: 16px;
  border-radius: 999px;
  border: 1px solid #111;
  background: #fff;
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
}

.print-pin.asset { border-radius: 3px; }

.print-legend {
  width: 100%;
  border-collapse: collapse;
  font-size: 10pt;
}

.print-legend th,
.print-legend td {
  border-bottom: 1px solid #ccc;
  padding: 3px 6px;
  text-align: left;
  vertical-align: top;
}

.print-legend th:first-child,
.print-legend td:first-child { width: 28px; }

/*
 * The label. A handheld label printer feeds a roll, so the sheet is the sticker: the QR
 * takes what height there is and the name gets one line under it. Anything else on here
 * shrinks the code, and a small code is one that needs a second scan.
 */
.qr-sticker {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.5mm;
  width: 100%;
  height: 100%;
  padding: 1.5mm;
  box-sizing: border-box;
}

.qr-sticker-code {
  width: auto;
  height: 26mm;
  max-width: 100%;
  image-rendering: pixelated;
}

.qr-sticker-naam {
  max-width: 100%;
  font-size: 9pt;
  font-weight: 700;
  line-height: 1.1;
  text-align: center;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

@media print {
  body.printing {
    background: #fff;
    margin: 0;
  }

  .print-sheet { box-shadow: none; }
}


/* ---------------------------------------------------------------- photo field */

.photo-drop {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-m);
  background: var(--surface-2);
}

.photo-drop.over {
  border-color: var(--primary);
  background: color-mix(in srgb, var(--primary) 8%, var(--surface-2));
}

.photo-drop.busy {
  opacity: 0.6;
  pointer-events: none;
}

.photo-preview {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.photo-preview img {
  width: 96px;
  height: 96px;
  object-fit: cover;
  border-radius: var(--radius-m);
  border: 1px solid var(--line);
  background: var(--surface);
}

.photo-empty {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 96px;
  height: 96px;
  padding: var(--space-2);
  flex-direction: column;
  justify-content: center;
  text-align: center;
  border-radius: var(--radius-m);
  border: 1px solid var(--line);
  background: var(--surface);
}

.photo-empty .icon {
  width: 22px;
  height: 22px;
  color: var(--ink-500);
}

.photo-actions {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}

/* The real inputs never show: the buttons above stand in for them. */
.hidden-file {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* ---------------------------------------------------------------- qr scanner */

.scan-frame {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-m);
  background: #000;
  aspect-ratio: 4 / 3;
}

.scan-frame video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* A window in the middle, so someone knows where to hold the sticker. */
.scan-frame::after {
  content: "";
  position: absolute;
  inset: 18% 18%;
  border: 2px solid rgba(255, 255, 255, 0.85);
  border-radius: var(--radius-m);
  pointer-events: none;
}

/* ---------------------------------------------------------------- on a phone */

/*
 * Below 640 the dialogs stop being dialogs and become sheets: full width, anchored to the
 * bottom, scrolling inside. A centred box with a margin all round looks deliberate on a
 * laptop and cramped on a phone, where half of the remaining height is taken by the
 * keyboard the moment a field is tapped.
 */
@media (max-width: 640px) {
  .modal-host {
    padding: 0;
    place-items: end stretch;
  }

  .modal {
    max-width: none;
    /* Dynamic units, so the sheet follows the browser chrome instead of hiding behind it. */
    max-height: 94dvh;
    border-radius: var(--radius-l) var(--radius-l) 0 0;
    border-bottom: none;
  }

  .modal-head,
  .modal-foot,
  .modal-body {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }

  .modal-head h2,
  .modal-head h3 {
    font-size: 16px;
    line-height: 1.25;
  }

  /* The actions are the thing a thumb reaches for, so they get the full width. */
  .modal-foot {
    flex-direction: column-reverse;
    gap: var(--space-2);
    position: sticky;
    bottom: 0;
    background: var(--surface);
  }

  .modal-foot .btn {
    width: 100%;
    justify-content: center;
    min-height: 44px;
  }

  /* Two fields side by side is 100px each at this width, which is not a field. */
  .field-row,
  .spec-grid {
    grid-template-columns: 1fr;
  }

  .spec-grid .btn {
    justify-self: start;
  }

  /* A 16px font is what stops iOS zooming in on focus. */
  .modal input,
  .modal select,
  .modal textarea {
    font-size: 16px;
    min-height: 42px;
  }

  .modal .picker-list,
  .modal .picker-results {
    max-height: 40vh;
  }

  .photo-preview img,
  .photo-empty {
    width: 84px;
    height: 84px;
  }

  .photo-actions .btn {
    flex: 1 1 auto;
    justify-content: center;
    min-height: 40px;
  }

  /* Title and actions stack instead of fighting over one line. */
  .topbar {
    flex-wrap: wrap;
    row-gap: var(--space-2);
  }

  .topbar .titles {
    flex: 1 1 100%;
  }

  .topbar .titles h1 {
    font-size: 19px;
  }

  .topbar-actions {
    flex-wrap: wrap;
  }

  /* Filter bars wrap instead of squeezing every control onto one line. */
  .col-search,
  .col-filter,
  .col-filter-wide {
    flex: 1 1 100%;
    min-width: 0;
  }
}


/* ---------------------------------------------------------------- pins per room */

/*
 * Dropping a room brings its installations, so the list is grouped rather than flat: the
 * room is the heading and what is in it sits under it. A flat list of fourteen names gives
 * no way to tell which one was the room.
 */
.pin-group + .pin-group {
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
}

.pin-head {
  font-weight: 600;
}

.pin-row {
  padding-left: var(--space-4);
  border-left: 2px solid var(--line);
  margin-top: 4px;
}

/* Each legend keeps its heading with its table when the page breaks. */
.print-block {
  break-inside: avoid;
  margin-top: 10px;
}


/* ---------------------------------------------------------------- folded rows */

/*
 * Sixty door handles with the same yearly check is a list nobody reads. The name is one
 * row with a count; the sixty are one click away.
 */
.grouprow > td {
  background: var(--surface-2);
  font-weight: 600;
}

.grouprow.open > td {
  border-bottom: none;
}

.fold {
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  flex: none;
  border-radius: var(--radius-s);
  background: var(--surface-3);
  font-size: 12px;
  line-height: 1;
}

/* A fold button with an arrow pointing down, turned up when open. */
.fold.fold-pijl {
  width: 22px;
  height: 22px;
  /* Without these the browser's own button padding pushes the arrow to the right. */
  padding: 0;
  border: 1px solid var(--line);
  color: var(--ink-700);
  cursor: pointer;
}

.fold-pijl .icon { display: block; width: 16px; height: 16px; transition: transform 0.15s ease; }
.fold-pijl.open .icon { transform: rotate(180deg); }

.subrow > td:first-child {
  padding-left: var(--space-6);
}


/* ---------------------------------------------------------------- room outlines */

/*
 * The outlines sit over the scan, faint enough that the walls underneath stay readable. A
 * shape that shouts is a shape that hides the thing it describes.
 */
.zone-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  color: var(--primary);
}

.zone {
  pointer-events: auto;
}

/*
 * The preview layer is never a drop target. Anything in it that could take the pointer
 * would make the browser re-evaluate the target mid-drag, which is what made the cursor
 * flicker to "no drop" and swallowed the drop itself.
 */
.preview-layer,
.preview-layer * {
  pointer-events: none;
}

.zone.unnamed {
  stroke-dasharray: 6 5;
}

.zone-label {
  font-size: 22px;
  font-weight: 600;
  fill: var(--ink-800);
  paint-order: stroke;
  stroke: var(--surface);
  stroke-width: 5px;
  stroke-linejoin: round;
  pointer-events: none;
}

/* A technical drawing with a floor plan: a small number in the room, the name in the legend. */
.zone-nummer {
  font-size: 21px;
  font-weight: 700;
  fill: var(--ink-800);
  paint-order: stroke;
  stroke: var(--surface);
  stroke-width: 4px;
  stroke-linejoin: round;
  pointer-events: none;
}

.zone-legenda {
  margin: 10px 0 8px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
}

.zone-legenda-lijst {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  columns: 3 180px;
  column-gap: 20px;
  font-size: 13px;
}

.zone-legenda-lijst li {
  display: flex;
  gap: 8px;
  break-inside: avoid;
  padding: 1px 0;
}

.zone-legenda-nummer {
  min-width: 22px;
  font-weight: 700;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.zone-vertex {
  fill: var(--surface);
  stroke: var(--primary);
  stroke-width: 2px;
  vector-effect: non-scaling-stroke;
}

/*
 * The instructions sit above the drawing and stay there while it is scrolled. They used to
 * be in a card beside it, which on a real plan is a thousand pixels below the fold: people
 * clicked four corners, saw nothing happen and had no way to finish.
 */
.zone-toolbar {
  display: grid;
  gap: var(--space-2);
  position: sticky;
  top: 0;
  z-index: 5;
  margin-bottom: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--primary);
  border-radius: var(--radius-m);
  background: color-mix(in srgb, var(--primary) 8%, var(--surface));
}

.zone-toolbar .icon {
  width: 18px;
  height: 18px;
  color: var(--primary-strong);
}

/*
 * The two text lines keep their height whatever they say. The bar sits directly above the
 * drawing, so a line that wraps would move the plan down while somebody is clicking corners
 * into it, and every corner after that lands in the wrong place.
 */
.zone-line {
  display: block;
  min-height: 2.7em;
  line-height: 1.35;
}

.zone-line-small {
  display: block;
  min-height: 1.4em;
  line-height: 1.35;
}

.zone-count {
  padding: 2px var(--space-2);
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  font-size: 12px;
  font-weight: 600;
}

/* While drawing, the cursor says what a click will do. */
.drawing-canvas.drawing-zones {
  cursor: crosshair;
}

/* Over a corner that a click would snap to, or over the point that closes the room. */
.drawing-canvas.drawing-zones.snapping {
  cursor: pointer;
}

/* The first point becomes the closing target once there is a room to close. */
.zone-vertex.closing {
  fill: var(--primary);
  stroke: var(--surface);
  stroke-width: 3px;
}

.drawing-canvas.drawing-zones .pin {
  pointer-events: none;
}

.zone-swatch {
  display: inline-block;
  width: 12px;
  height: 12px;
  flex: none;
  border-radius: 3px;
  border: 1px solid var(--line-strong);
}


/* ---------------------------------------------------------------- drag preview */

/*
 * A drop used to be a guess: the marker appeared where the browser decided the pointer was,
 * and whether it had landed in a room was something you found out afterwards.
 */
.zone-target {
  stroke-dasharray: 10 6;
}

.drop-ghost {
  fill: var(--primary);
  fill-opacity: 0.35;
  stroke: var(--surface);
  stroke-width: 3px;
  vector-effect: non-scaling-stroke;
}

.drop-cross {
  stroke: var(--primary);
  stroke-width: 2px;
  stroke-dasharray: 4 4;
  vector-effect: non-scaling-stroke;
}

.drop-label {
  font-size: 22px;
  font-weight: 600;
  fill: var(--ink-800);
  paint-order: stroke;
  stroke: var(--surface);
  stroke-width: 5px;
  stroke-linejoin: round;
}

/* ---------------------------------------------------------------- dashboard blocks */

/*
 * The arrangeable part of the dashboard. A block is a card plus a grip, and the grip is
 * what says the thing can be moved at all: a card that silently happens to be draggable is
 * a feature nobody finds.
 */
/*
 * Tiles of one size: the Assets block. Three per row, a fixed row height, and larger
 * blocks span two or three tiles in either direction. Dense packing fills the gaps a wide
 * block would otherwise leave.
 */
.dash-blocks {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* Thin rows: each block spans as many as its content needs, so none ends in empty space. */
  grid-auto-rows: 8px;
  grid-auto-flow: row dense;
  column-gap: var(--space-4);
  row-gap: 0;
}

.dash-block {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  /* As tall as the content, so the space between blocks is outside the card; a longer one scrolls. */
  align-self: start;
  max-height: 560px;
  border-radius: var(--radius-m);
}

.dash-block > .card {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.dash-block > .card > .card-body {
  flex: 1;
  min-height: 0;
  overflow: auto;
}

@media (max-width: 1100px) {
  .dash-blocks { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 700px) {
  .dash-blocks {
    grid-template-columns: minmax(0, 1fr);
    grid-auto-rows: auto;
    row-gap: var(--space-4);
  }
}

.dash-block.dragging {
  opacity: 0.45;
}

.dash-block .block-grip {
  display: block;
  padding: 0 0 4px 2px;
  color: var(--ink-400);
  font-size: 11px;
  cursor: grab;
  user-select: none;
}

.dash-block .block-grip.locked {
  cursor: default;
  color: var(--amber);
}

/* Where the block will land. Drawn on the neighbour, so nothing moves until the drop. */
.dash-block.drop-before::before,
.dash-block.drop-after::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 3px;
  border-radius: 2px;
  background: var(--primary);
}

.dash-block.drop-before::before { left: calc(var(--space-4) / -2); }
.dash-block.drop-after::after { right: calc(var(--space-4) / -2); }

/* ---------------------------------------------------------------- bar chart with an axis */

/*
 * A chart with a scale. Without one a bar is a shape rather than a measurement, and the
 * two series were drawn against different heights, which made them look comparable when
 * they were not. One scale, ticks on the left, and the figure named on hover.
 */
.chart {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-2);
}

.chart-axis {
  position: relative;
  width: 26px;
  height: 140px;
}

.chart-tick {
  position: absolute;
  right: 0;
  transform: translateY(50%);
  font-size: 11px;
  color: var(--ink-400);
  font-variant-numeric: tabular-nums;
}

.chart-plot {
  position: relative;
  height: 140px;
}

.chart-lines {
  position: absolute;
  inset: 0;
}

.chart-line {
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--line);
}

.chart-days {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-end;
  gap: 4px;
}

.chart-day {
  flex: 1;
  min-width: 0;
  height: 100%;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 2px;
}

.chart-bar {
  flex: 1;
  min-width: 2px;
  min-height: 2px;
  border-radius: 2px 2px 0 0;
  cursor: pointer;
}

.chart-bar.made { background: var(--primary); }
.chart-bar.done { background: var(--teal); }

.chart-bar:hover,
.chart-bar:focus-visible {
  filter: brightness(1.15);
  outline: none;
}

.chart-tip {
  position: absolute;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  padding: 4px var(--space-2);
  border-radius: var(--radius-s);
  background: var(--ink-900);
  color: var(--surface);
  font-size: 11px;
  line-height: 1.35;
  white-space: nowrap;
  pointer-events: none;
  z-index: 3;
}
.chart-tip strong { display: flex; align-items: center; gap: 6px; font-size: 13px; }
/* The colour of the bar, so it is clear which one the figure belongs to. */
.chart-tip-kleur { width: 9px; height: 9px; border-radius: 2px; flex: none; }
.chart-tip-kleur.made { background: var(--primary); }
.chart-tip-kleur.done { background: var(--teal); }

/* ---------------------------------------------------------------- maintenance urgency */

/*
 * How long until something has to happen, as a colour.
 *
 * The colour is set per element through the CSSOM rather than as a class per band, because
 * the bands are computed on the server: one scale, and a screen that cannot drift from the
 * spreadsheet and the printout that use the same figures.
 */
.termijn {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
  color: #fff;
  background: var(--termijn-kleur, var(--ink-500));
}

.legenda-stip {
  width: 11px;
  height: 11px;
  flex: none;
  border-radius: 3px;
  display: inline-block;
}

/* ---------------------------------------------------------------- the maintenance year */

.jaarplan {
  width: 100%;
  border-collapse: collapse;
}

.jaarplan th.maandkop {
  width: 34px;
  text-align: center;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.jaarplan td.maandcel {
  width: 34px;
  text-align: center;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  padding: 3px 0;
}

.jaarplan td.maandcel.gevuld {
  color: #fff;
  font-weight: 600;
  background: var(--maand-kleur, var(--ink-500));
  border-radius: 3px;
}

/* On paper the colour has to survive a printer that drops backgrounds by default. */
@media print {
  .print-jaarplan td.maandcel.gevuld,
  .legenda-stip,
  .termijn {
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }
}

.print-title {
  font-size: 18px;
  margin: 0 0 10px;
}

/* ---------------------------------------------------------------- manual */

.manual {
  display: grid;
  grid-template-columns: minmax(200px, 260px) minmax(0, 1fr);
  gap: var(--space-4);
  align-items: start;
}

.manual > .card:first-child {
  position: sticky;
  top: var(--space-4);
}

@media (max-width: 900px) {
  .manual { grid-template-columns: minmax(0, 1fr); }
  .manual > .card:first-child { position: static; }
}

.manual-toc {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.manual-toc a {
  padding: 5px var(--space-2);
  border-radius: var(--radius-s);
  color: var(--ink-700, var(--ink-800));
  text-decoration: none;
}

.manual-toc a:hover { background: var(--surface-2); }

.manual-toc a.active {
  background: var(--surface-2);
  color: var(--brand-ink, var(--primary));
  font-weight: 600;
}

.manual-sections { margin-bottom: var(--space-2); }

.manual-body {
  max-width: 820px;
  line-height: 1.55;
}

.manual-body p,
.manual-body ul,
.manual-body ol { margin: 0 0 var(--space-3); }

.manual-body ul,
.manual-body ol { padding-left: 1.3em; }

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

.manual-body .table-wrap { margin-bottom: var(--space-4); }

.manual-body code {
  font-size: 0.92em;
  padding: 0 4px;
  border-radius: 4px;
  background: var(--surface-2);
}

.manual-h2 {
  margin: var(--space-5) 0 var(--space-2);
  font-size: 16px;
  scroll-margin-top: var(--space-5);
}

.manual-body > .manual-h2:first-child { margin-top: 0; }

.manual-h3 {
  margin: var(--space-4) 0 var(--space-2);
  font-size: 14px;
}

.manual-note {
  margin: 0 0 var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--primary);
  border-radius: var(--radius-s);
  background: var(--surface-2);
}

.manual-scale { margin-bottom: var(--space-4); gap: 6px; }

/* Process diagrams, drawn as SVG and coloured by the theme. */
.manual-figure { margin: 0 0 var(--space-4); }

.manual-flow {
  display: block;
  width: 100%;
  height: auto;
}

.manual-flow-step rect {
  fill: var(--surface-2);
  stroke: var(--line);
  stroke-width: 1.5;
}

.manual-flow-step.optional rect {
  fill: var(--surface);
  stroke-dasharray: 5 4;
}

.manual-flow-step text {
  fill: var(--ink-800);
  font-size: 13px;
  font-family: inherit;
}

.manual-flow-line {
  stroke: var(--ink-400);
  stroke-width: 1.5;
}

.manual-flow-jump {
  fill: none;
  stroke: var(--primary);
  stroke-width: 1.5;
  stroke-dasharray: 4 3;
}

.manual-flow-head { fill: var(--ink-400); }

/* ---------------------------------------------------------------- technical services columns */

.td-kolommen {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-4);
  align-items: stretch;
}

@media (max-width: 900px) {
  .td-kolommen { grid-template-columns: minmax(0, 1fr); }
}

.td-kolom { transition: box-shadow 120ms ease-out; }

/* The three columns scroll once they are longer than this. */
.td-lijst {
  max-height: 360px;
  min-height: 90px;
  overflow: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.td-leeg {
  padding: var(--space-4);
  border: 1px dashed var(--line);
  border-radius: var(--radius-m);
  text-align: center;
}

.td-pool {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 6px;
  align-items: start;
}

.td-drop {
  outline: 2px dashed var(--primary);
  outline-offset: -3px;
}

.td-groep {
  border: 1px solid var(--line);
  border-radius: var(--radius-m);
  background: var(--surface);
  cursor: grab;
}

.td-groep:hover { border-color: var(--brand-ink); }
.td-groep.dragging { opacity: 0.45; }

.td-groep-kop {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  padding: 6px var(--space-2);
  min-width: 0;
}

.td-naam {
  font-weight: 600;
  min-width: 0;
  overflow-wrap: anywhere;
}

.td-leden {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 0 var(--space-2) 6px 30px;
}

.td-lid {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  font-weight: 400;
  cursor: pointer;
}

.prewrap {
  white-space: pre-wrap;
  word-break: break-word;
}

/* An attachment shown as a file: a link that opens it in its own tab, never drawn inline. */
.file-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: 600;
  overflow-wrap: anywhere;
}

.file-link .icon {
  width: 16px;
  height: 16px;
  flex: none;
}

/* ---------------------------------------------------------------- loading */

/* The bar along the top of the window while the API is busy. */
.laadbalk {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  z-index: 300;
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
  background: color-mix(in srgb, var(--primary) 16%, transparent);
  transition: opacity 0.2s ease;
}
.laadbalk.aan { opacity: 1; }
.laadbalk span {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 38%;
  border-radius: 0 3px 3px 0;
  background: linear-gradient(90deg, transparent, var(--primary) 30%, var(--brand-ink) 100%);
  animation: laadbalk 1.15s cubic-bezier(0.45, 0, 0.25, 1) infinite;
}
.laadbalk.klaar { opacity: 0; transition: opacity 0.3s ease 0.15s; }
.laadbalk.klaar span { animation: none; width: 100%; background: var(--primary); }
@keyframes laadbalk {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(270%); }
}

/* Outlines of a screen or a card that is still loading. */
.skel {
  display: block;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--surface-3) 0%, color-mix(in srgb, var(--surface-3) 45%, var(--surface)) 50%, var(--surface-3) 100%);
  background-size: 220% 100%;
  animation: skel 1.4s ease-in-out infinite;
}
.skel-lijn { height: 12px; max-width: 100%; }
.skel-lijn.skel-kop { height: 16px; }
.skel-lijn.skel-groot { height: 26px; }
.skel-lijn.skel-veld { height: 38px; border-radius: var(--radius-s); }
@keyframes skel {
  0% { background-position: 100% 0; }
  100% { background-position: -120% 0; }
}
.skelet { animation: skel-in 0.2s ease both; }
@keyframes skel-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
.skel-kaart .card-head h2 { color: var(--ink-500); }
.skel-regels { display: grid; gap: 14px; padding: 4px 0; }
.skel-tegels { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-4); }
.skel-tegels .card-body { display: grid; gap: 12px; }
.skel-raster { display: grid; grid-template-columns: 2fr 1fr; gap: var(--space-4); align-items: start; }
.skel-raster.skel-detail { grid-template-columns: 1.4fr 1fr; }
.skel-titel { display: flex; align-items: center; gap: var(--space-4); padding: var(--space-2) 0; }
/* On the page background rather than in a card: a shade darker, or it disappears. */
.skel-titel .skel { background-image: linear-gradient(90deg, var(--line) 0%, color-mix(in srgb, var(--line) 45%, var(--surface)) 50%, var(--line) 100%); }
.skel-deflist { display: grid; grid-template-columns: 1fr 2fr; gap: 14px var(--space-5); }
.skel-balk { display: flex; gap: var(--space-3); }
.skel-tabel { display: grid; gap: 0; }
.skel-rij { display: grid; grid-template-columns: 2fr 1.2fr 1fr 1fr; gap: var(--space-5); align-items: center; padding: 14px 0; border-bottom: 1px solid var(--line); }
.skel-rij:last-child { border-bottom: 0; }
@media (max-width: 760px) {
  .skel-tegels { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .skel-raster, .skel-raster.skel-detail { grid-template-columns: minmax(0, 1fr); }
  .skel-rij { grid-template-columns: 2fr 1fr; }
  .skel-rij > :nth-child(n + 3) { display: none; }
}

/* A list being fetched again: dimmed, but only when it takes a moment. */
.verversen { opacity: 0.5; transition: opacity 0.2s ease 0.15s; }

/* A spinner in a button that is working, and a small inline one with a text. */
.btn.bezig::after,
.draaier {
  content: "";
  display: inline-block;
  flex: none;
  width: 14px;
  height: 14px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: draai 0.7s linear infinite;
}
.btn.bezig::after { margin-left: 2px; opacity: 0.85; }
.draaier { color: var(--primary); }
.laadregel { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) 0; }
@keyframes draai {
  to { transform: rotate(360deg); }
}

/* Until the application has started. */
.opstart {
  min-height: 100vh;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 22px;
  background: var(--surface-2);
}
.opstart img { width: 52px; height: 52px; animation: opstart-puls 1.6s ease-in-out infinite; }
.opstart-balk { position: relative; width: 140px; height: 3px; overflow: hidden; border-radius: 3px; background: color-mix(in srgb, var(--primary) 16%, transparent); }
.opstart-balk span { position: absolute; inset: 0 auto 0 0; width: 40%; border-radius: 3px; background: var(--primary); animation: laadbalk 1.15s cubic-bezier(0.45, 0, 0.25, 1) infinite; }
@keyframes opstart-puls {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(0.94); opacity: 0.8; }
}

/* Text for screen readers only. */
.verborgen-tekst {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .skel, .opstart img { animation: none; }
  .laadbalk span, .opstart-balk span { animation-duration: 2.6s; }
  .btn.bezig::after, .draaier { animation-duration: 1.6s; }
}

/* Without a connection: a quiet line at the bottom of the screen. */
/* A hosted demo near its end: the date and the way to upgrade, above the screen. */
.proef-balk {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin: 0 var(--space-5) var(--space-4);
  padding: 10px 14px;
  border: 1px solid var(--amber);
  border-radius: var(--radius-m);
  background: var(--amber-soft);
  color: var(--ink-900);
  font-size: 13.5px;
}

.offline-balk {
  position: fixed;
  left: 50%;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 250;
  max-width: calc(100vw - 32px);
  padding: 10px 18px;
  border-radius: 999px;
  background: var(--ink-900);
  color: var(--surface);
  font-size: 14px;
  box-shadow: var(--shadow-3);
}
.offline-balk[hidden],
.offline-scherm .offline-balk { display: none; }

/* ---------------------------------------------------------------- report heading */

/* Only Terug on this row, so it takes little room above Voortgang. */
.terug-rij { margin-block: calc(var(--space-2) * -1); }

/* Voortgang, then the report number and the priority, in one heading row. */
.voortgang-kop { gap: var(--space-3); }
.voortgang-kop h1.voortgang-nummer { font-size: 17px; margin-left: var(--space-2); }

.voortgang-keuzes {
  gap: var(--space-4);
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
}

/* A printed drawing sized to the page in millimetres, with the room outlines over it. */
.print-canvas.op-maat { display: block; max-width: none; }
.print-canvas.op-maat img { width: 100%; height: 100%; max-width: none; }
.print-vlakken { position: absolute; inset: 0; width: 100%; height: 100%; }
.print-vlak {
  fill: rgba(31, 95, 191, 0.08);
  stroke: #1f5fbf;
  stroke-width: 2;
  print-color-adjust: exact;
  -webkit-print-color-adjust: exact;
}
.print-pin.locatie { border-color: #1f5fbf; color: #1f5fbf; }

/* ---------------------------------------------------------------- dashboard comparison */

/* The figure with its arrow against the twelve months before. */
.stat .value-rij { display: flex; align-items: center; gap: var(--space-2); }
.trend { width: 22px; height: 22px; flex: none; }
.trend-goed { color: var(--goed); }
.trend-slecht { color: var(--danger); }
.trend-gelijk { color: var(--ink-900); }

/* A confirmation on the sign in screen, such as a changed password. */
.form-ok { color: var(--teal); font-weight: 550; }

/* ---------------------------------------------------------------- report charts */

/* Never wider than this, or a chart in a full-width card blows its text up. */
.grafiek-svg { display: block; width: 100%; max-width: 460px; height: auto; max-height: 340px; }
.grafiek-svg text { font-family: var(--font); }
.grafiek-label { font-size: 12px; fill: var(--ink-700); }
.grafiek-waarde { font-size: 12px; fill: var(--ink-500); font-family: var(--mono); }
.grafiek-as { font-size: 11px; fill: var(--ink-400); }
.grafiek-lijn { stroke: var(--line); stroke-width: 1; }
.grafiek-rij { display: flex; align-items: center; gap: var(--space-5); flex-wrap: wrap; }
.grafiek-taart { width: 170px; height: 170px; flex: none; }
.grafiek-totaal { font-size: 26px; font-weight: 650; fill: var(--ink-900); }
.grafiek-legenda { flex: 1; min-width: 180px; display: grid; gap: 6px; }
.grafiek-stip { display: inline-block; width: 10px; height: 10px; border-radius: 3px; flex: none; }

/*
 * One colour per part, fill for the chart and background for the legend dot. Fixed rather than
 * the house style: a brand with red and yellow would give two parts of a pie the same colour.
 * The PDF of a management report uses the same seven.
 */
.g-0 { fill: #3d4fdb; background: #3d4fdb; stroke: #3d4fdb; }
.g-1 { fill: #12a594; background: #12a594; stroke: #12a594; }
.g-2 { fill: #d98207; background: #d98207; stroke: #d98207; }
.g-3 { fill: #c8372c; background: #c8372c; stroke: #c8372c; }
.g-4 { fill: #8b5cf6; background: #8b5cf6; stroke: #8b5cf6; }
.g-5 { fill: #0ea5e9; background: #0ea5e9; stroke: #0ea5e9; }
.g-6 { fill: #a9b2ca; background: #a9b2ca; stroke: #a9b2ca; }
.grafiek-taart .ring { fill: none; }

/* ---------------------------------------------------------------- blueprint */

/* The floor plan fitted by hand: blue lines over the drawing, the paper transparent. */
.blauwdruk {
  position: absolute;
  max-width: none;
  transform-origin: 0 0;
  filter: url(#blauwdruk-filter);
  opacity: 0.85;
  cursor: move;
  touch-action: none;
  user-select: none;
  z-index: 4;
}
.blauwdruk-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.drawing-canvas.uitlijnen { overflow: hidden; outline: 2px dashed #1f5cf2; outline-offset: 2px; }
.drawing-canvas.uitlijnen .pin,
.drawing-canvas.uitlijnen .zone-layer { opacity: 0.35; pointer-events: none; }
.blauwdruk-balk {
  display: grid;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid #1f5cf2;
  border-radius: var(--radius-m);
  background: color-mix(in srgb, #1f5cf2 8%, var(--surface));
}

/* ---------------------------------------------------------------- report widgets, packed */

/* Each widget spans as many thin rows as it is tall, so the columns close up. */
.widget-grid.metselwerk {
  grid-auto-rows: 8px;
  row-gap: 0;
  grid-auto-flow: row dense;
}

/* A contract that ends within six months, or ended: the action sign in the supplier list. */
.contract-actie { display: inline-flex; align-items: center; gap: 4px; color: var(--danger); font-weight: 600; }
.contract-actie .icon { width: 15px; height: 15px; }
