/* =========================================================
   Modfix — Component library
   ONE definition for every UI element, used identically by the public
   site and the admin panel. If you need a new element, add it here — do
   not style it in a page stylesheet.
   Sections: buttons · badges · surfaces · forms · tables · filters ·
   modal/drawer · toast · tabs · stats · empty/loading · stepper ·
   pick grid · select cards + cart · timeline · kanban · misc
   ========================================================= */

/* ===== Buttons ===== */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 12px 20px; border-radius: var(--radius-pill);
  font: 700 .93rem/1 var(--font-head);
  border: 1px solid transparent; cursor: pointer; white-space: nowrap;
  text-decoration: none; color: var(--text-main); background: transparent;
  max-width: 100%;
  transition: transform var(--t-fast) var(--ease), box-shadow var(--t-fast), background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.btn svg { width: 18px; height: 18px; flex-shrink: 0; }
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn-primary { background: var(--blue); color: #fff; box-shadow: var(--shadow-glow-blue); }
.btn-primary:hover { background: var(--blue-hover); }
.btn-cyan { background: var(--cyan); color: var(--text-on-accent); }
.btn-cyan:hover { background: var(--cyan-hover); }
.btn-ghost { background: transparent; color: var(--text-main); border-color: var(--border); }
.btn-ghost:hover { border-color: var(--cyan); color: var(--cyan); }
.btn-outline { background: transparent; color: var(--cyan); border-color: var(--cyan); }
.btn-outline:hover { background: var(--cyan-dim); }
.btn-soft { background: var(--bg-card); color: var(--text-main); border-color: var(--border); }
.btn-soft:hover { background: var(--bg-card-hover); border-color: var(--cyan); }
.btn-critical { background: transparent; color: var(--red); border-color: var(--red); }
.btn-critical:hover { background: var(--red-dim); }
.btn-success { background: var(--green); color: var(--text-on-accent); }
.btn-block { width: 100%; }
.btn-sm { padding: 8px 14px; font-size: .84rem; }
.btn-sm svg { width: 15px; height: 15px; }
.btn-lg { padding: 15px 26px; font-size: 1rem; }
.btn-xs { padding: 5px 10px; font-size: .76rem; border-radius: var(--radius-xs); }
/* Long-label safety net. Dutch compounds ("Bekijk alle mods voor jouw
   apparaat") are far longer than their English equivalents and used to burst
   out of the viewport on narrow screens, because .btn is nowrap. Any button
   that is allowed to fill its container may wrap instead of overflowing. */
.btn-wrap, .btn-block { white-space: normal; text-align: center; }
.btn[disabled], .btn.is-loading { opacity: .55; cursor: not-allowed; transform: none; pointer-events: none; }
.btn.is-loading::before {
  content: ""; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid currentColor; border-right-color: transparent;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.icon-btn {
  width: 38px; height: 38px; border-radius: 10px; border: 1px solid var(--border);
  background: var(--bg-card); color: var(--text-muted);
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer; position: relative; flex-shrink: 0;
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast);
}
.icon-btn svg { width: 18px; height: 18px; }
.icon-btn:hover { color: var(--cyan); border-color: var(--cyan); }
.icon-btn.is-danger:hover { color: var(--red); border-color: var(--red); background: var(--red-dim); }
.icon-btn.is-sm { width: 30px; height: 30px; border-radius: 8px; }
.icon-btn.is-sm svg { width: 15px; height: 15px; }
.icon-btn .dot { position: absolute; top: 7px; right: 7px; width: 8px; height: 8px; border-radius: 50%; background: var(--amber); border: 2px solid var(--bg-card); }
.icon-btn .count {
  position: absolute; top: -6px; right: -6px; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px;
  background: var(--red); color: #fff; font: 800 .68rem/18px var(--font-head); text-align: center;
}

.link { color: var(--cyan); font-weight: 600; }
.link:hover { text-decoration: underline; }

/* ===== Badges ===== */
.badge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 11px; border-radius: var(--radius-pill);
  font: 700 .74rem/1.4 var(--font-head); letter-spacing: .01em; white-space: nowrap;
}
.badge-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.badge-neutral  { background: rgba(148,163,184,.14); color: var(--text-muted); }
.badge-info     { background: var(--blue-dim); color: var(--blue-soft); }
.badge-progress { background: var(--cyan-dim); color: var(--cyan); }
.badge-complete { background: var(--green-dim); color: var(--green); }
.badge-pending  { background: var(--amber-dim); color: var(--amber); }
.badge-critical { background: var(--red-dim); color: var(--red); }
.badge-violet   { background: var(--violet-dim); color: var(--violet); }
.badge-outline  { background: transparent; border: 1px solid var(--border); color: var(--text-muted); }
.badge.is-tight { padding: 2px 8px; }
/* Ticket status → badge tier (single source of truth for both sides) */
.st-requested     { background: var(--blue-dim); color: var(--blue-soft); }
.st-received      { background: rgba(148,163,184,.14); color: var(--text-muted); }
.st-diagnosing    { background: var(--violet-dim); color: var(--violet); }
.st-waiting_parts { background: var(--amber-dim); color: var(--amber); }
.st-in_progress   { background: var(--cyan-dim); color: var(--cyan); }
.st-completed     { background: var(--green-dim); color: var(--green); }
.st-shipped       { background: var(--green-dim); color: var(--green); }
.st-cancelled     { background: var(--red-dim); color: var(--red); }
/* Shop order status → the same badge tier (T6c). `shipped` and `cancelled`
   are shared with the ticket pipeline on purpose: one colour language means
   green always reads as done and red always reads as stopped, whichever board
   you are looking at. */
.st-demo             { background: var(--violet-dim); color: var(--violet); }
.st-awaiting_payment { background: var(--amber-dim); color: var(--amber); }
.st-paid             { background: var(--blue-dim); color: var(--blue-soft); }
.st-processing       { background: var(--cyan-dim); color: var(--cyan); }
.st-refunded         { background: rgba(148,163,184,.14); color: var(--text-muted); }
.st-failed           { background: var(--red-dim); color: var(--red); }
/* Kind */
.kind-repair { background: var(--cyan-dim); color: var(--cyan); }
.kind-mod { background: var(--violet-dim); color: var(--violet); }

/* ===== Surfaces ===== */
.card { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-md); }
.card.is-interactive { cursor: pointer; transition: border-color var(--t-fast), transform var(--t-fast), box-shadow var(--t-fast); }
.card.is-interactive:hover { border-color: var(--cyan); transform: translateY(-2px); box-shadow: var(--shadow-glow-cyan); }
.panel { padding: 22px 24px; }
.panel-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 18px; flex-wrap: wrap; }
.panel-head h3 { font-size: 1.02rem; margin: 0; }
.panel-head p { margin: 4px 0 0; font-size: .86rem; }
.panel-head .btn { flex-shrink: 0; }
.divider { height: 1px; background: var(--border-soft); margin: 18px 0; border: none; }

.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 24px; flex-wrap: wrap; }
.page-head h1, .page-head h2 { font-size: 1.5rem; margin-bottom: 4px; }
.page-head p { margin: 0; font-size: .92rem; }
.page-head-actions { display: flex; gap: 10px; flex-wrap: wrap; }

.eyebrow {
  display: inline-block; font: 700 .78rem/1 var(--font-head); letter-spacing: .06em; text-transform: uppercase;
  color: var(--cyan); background: var(--cyan-dim); padding: 6px 12px; border-radius: var(--radius-pill); margin: 0 0 14px;
}

/* Alerts */
.alert {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 12px 14px; border-radius: var(--radius-sm); font-size: .88rem;
  border: 1px solid var(--border); background: var(--bg-card); color: var(--text-main);
}
.alert svg { width: 18px; height: 18px; flex-shrink: 0; margin-top: 1px; }
.alert-info { border-color: rgba(56,189,248,.35); background: var(--cyan-dim); }
.alert-warn { border-color: rgba(245,158,11,.4); background: var(--amber-dim); }
.alert-error { border-color: rgba(239,68,68,.4); background: var(--red-dim); }
.alert-success { border-color: rgba(34,197,94,.4); background: var(--green-dim); }

/* ===== Forms ===== */
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 18px; min-width: 0; }
.field label, .field-label { font: 600 .84rem/1.2 var(--font-head); color: var(--text-muted); }
.field label .req { color: var(--cyan); margin-left: 2px; }
.field input:not([type="radio"]):not([type="checkbox"]),
.field select, .field textarea, .input {
  width: 100%; min-width: 0;
  background: var(--bg-input); border: 1px solid var(--border); color: var(--text-main);
  border-radius: var(--radius-sm); padding: 11px 14px;
  font: 500 .94rem/1.35 var(--font-body); outline: none;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.field textarea { resize: vertical; min-height: 110px; }
.field input::placeholder, .field textarea::placeholder, .input::placeholder { color: var(--text-faint); }
.field input:focus, .field select:focus, .field textarea:focus, .input:focus {
  border-color: var(--cyan); box-shadow: 0 0 0 3px var(--cyan-dim);
}
.field.is-invalid input, .field.is-invalid select, .field.is-invalid textarea { border-color: var(--red); }
.field select, select.input {
  appearance: none; -webkit-appearance: none; padding-right: 36px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394A3B8' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center; background-size: 16px;
}
.field-error { color: var(--red); font-size: .8rem; min-height: 1.2em; }
.field-hint { color: var(--text-faint); font-size: .8rem; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; }
.form-grid > .span-2 { grid-column: 1 / -1; }
.form-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 8px; flex-wrap: wrap; }
.form-banner { display: none; margin-bottom: 18px; }
.form-banner.show { display: flex; }
.input-group { display: flex; align-items: stretch; }
.input-group .input { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.input-group .btn { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
.input.is-sm { padding: 8px 12px; font-size: .86rem; }
.input.is-search { padding-left: 38px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748B' stroke-width='2'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.5-3.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: 12px center; background-size: 17px; }

.checkbox-row { display: flex; align-items: center; gap: 9px; font-size: .88rem; color: var(--text-muted); cursor: pointer; }
.checkbox-row input { accent-color: var(--cyan); width: 16px; height: 16px; cursor: pointer; margin: 0; }

.switch { display: inline-block; position: relative; width: 42px; height: 24px; flex-shrink: 0; vertical-align: middle; }
.switch input { opacity: 0; width: 100%; height: 100%; position: absolute; margin: 0; cursor: pointer; }
.switch-track { position: absolute; inset: 0; background: var(--border); border-radius: 999px; transition: background var(--t-fast); pointer-events: none; }
.switch-track::after { content: ""; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px; border-radius: 50%; background: var(--text-main); transition: transform var(--t-fast); }
.switch input:checked ~ .switch-track { background: var(--blue); }
.switch input:checked ~ .switch-track::after { transform: translateX(18px); }
.toggle-row { display: flex; align-items: center; justify-content: space-between; padding: 14px 0; border-bottom: 1px solid var(--border-soft); gap: 16px; }
.toggle-row:last-child { border-bottom: none; }
.toggle-row-text strong { display: block; font-size: .92rem; color: var(--text-main); }
.toggle-row-text span { font-size: .82rem; color: var(--text-faint); }

/* Choice cards (radio-style options: handover, service type) */
.choice-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.choice-card {
  display: flex; gap: 12px; align-items: flex-start; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 14px 16px;
  background: var(--bg-input); transition: border-color var(--t-fast), background var(--t-fast);
}
.choice-card:hover { border-color: var(--cyan); }
.choice-card:has(input:checked) { border-color: var(--cyan); background: var(--cyan-dim); }
.choice-card:has(input:focus-visible) { outline: 2px solid var(--cyan); outline-offset: 2px; }
.choice-card input { margin-top: 3px; accent-color: var(--blue); flex-shrink: 0; }
.choice-card-body { display: flex; flex-direction: column; gap: 3px; font-size: .85rem; color: var(--text-muted); min-width: 0; }
.choice-card-body strong { color: var(--text-main); font-size: .92rem; }

/* Inline status select (admin) */
.status-select {
  appearance: none; -webkit-appearance: none;
  background: var(--bg-input); border: 1px solid var(--border); color: var(--text-main);
  border-radius: var(--radius-pill); padding: 6px 30px 6px 12px; font: 700 .78rem var(--font-head);
  cursor: pointer; outline: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394A3B8' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 8px center; background-size: 14px;
}
.status-select:focus { border-color: var(--cyan); box-shadow: 0 0 0 3px var(--cyan-dim); }
/* Never wider than its cell, whatever the longest stage label happens to be. */
.status-select { max-width: 100%; text-overflow: ellipsis; }

/* ===== Tables ===== */
.table-wrap { overflow-x: auto; border-radius: var(--radius-md); border: 1px solid var(--border); background: var(--bg-card); }
.data-table { width: 100%; border-collapse: collapse; min-width: 640px; }
/* Seven-column tables: auto layout let one long customer name eat the row and
   push the last column out of sight, while device names wrapped to three lines.
   Fixed layout + a colgroup gives every column a predictable share instead. */
/* min-width is what actually protects the columns: below it the wrap scrolls
   instead of squeezing a Dutch label ("Wacht op onderdelen") out of its cell. */
.data-table.is-fixed { table-layout: fixed; min-width: 1040px; }
.data-table.is-fixed td, .data-table.is-fixed th { overflow-wrap: anywhere; }
.data-table .cell-tight, .data-table .cell-tight .row-sub { white-space: nowrap; }
/* col-total carries "Nog te bepalen", not just an amount — 10% clipped it. */
.col-ticket { width: 13%; } .col-customer { width: 18%; } .col-device { width: 17%; }
.col-kind { width: 11%; } .col-stage { width: 17%; } .col-priority { width: 10%; } .col-total { width: 14%; }
.data-table th {
  text-align: left; font: 700 .72rem/1 var(--font-head); letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-faint); padding: 13px 16px; background: var(--bg-void); border-bottom: 1px solid var(--border); white-space: nowrap;
}
.data-table td { padding: 13px 16px; border-bottom: 1px solid var(--border-soft); font-size: .9rem; color: var(--text-main); vertical-align: middle; }
.data-table tbody tr { background: var(--bg-card); transition: background .12s; }
.data-table tbody tr:hover { background: var(--bg-card-hover); }
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tr.is-selected { background: var(--cyan-dim) !important; }
.data-table tr.is-inactive td:not(.cell-check) { opacity: .55; }
.data-table tr.is-clickable { cursor: pointer; }
.data-table .cell-muted { color: var(--text-muted); }
.data-table .cell-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.data-table .cell-check { width: 40px; padding-right: 0; }
.data-table .cell-actions { text-align: right; white-space: nowrap; }
.data-table .cell-actions .icon-btn { margin-left: 4px; }
.data-table input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--cyan); cursor: pointer; margin: 0; display: block; }
.data-table .row-title { font-weight: 700; color: var(--text-main); }
.data-table .row-sub { font-size: .78rem; color: var(--text-faint); }
.table-foot { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; font-size: .82rem; color: var(--text-faint); gap: 12px; flex-wrap: wrap; }

/* ===== Filters / chips / bulk bar ===== */
.filter-row { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; flex-wrap: wrap; }
.filter-row .grow-search { margin-left: auto; min-width: 220px; flex: 0 1 300px; }
.chip {
  padding: 8px 15px; border-radius: var(--radius-pill); border: 1px solid var(--border);
  background: var(--bg-card); color: var(--text-muted); font: 600 .83rem/1 var(--font-head);
  cursor: pointer; transition: all var(--t-fast); display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
}
.chip:hover { border-color: var(--cyan); color: var(--cyan); }
.chip.active { background: var(--cyan); border-color: var(--cyan); color: var(--text-on-accent); }
.chip .chip-count { font-size: .72rem; opacity: .75; }
.chip svg { width: 14px; height: 14px; flex-shrink: 0; }
.chip-group { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.seg { display: inline-flex; border: 1px solid var(--border); border-radius: var(--radius-pill); padding: 3px; gap: 2px; background: var(--bg-card); }
.seg button {
  border: none; background: transparent; color: var(--text-muted);
  font: 700 .78rem/1 var(--font-head); letter-spacing: .02em;
  padding: 7px 12px; border-radius: var(--radius-pill); cursor: pointer; transition: all var(--t-fast);
  display: inline-flex; align-items: center; gap: 6px;
}
.seg button svg { width: 14px; height: 14px; }
.seg button.active { background: var(--blue); color: #fff; }
.seg button:not(.active):hover { color: var(--text-main); }

.bulk-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap;
  padding: 12px 16px; margin-bottom: 14px; border-radius: var(--radius-sm);
  background: var(--cyan-dim); border: 1px solid var(--cyan);
  font: 700 .88rem/1 var(--font-head); color: var(--text-main);
}
.bulk-bar-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* ===== Modal & drawer ===== */
.modal-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,.62); z-index: var(--z-modal);
  display: flex; align-items: center; justify-content: center; padding: 24px;
  animation: fade-in .15s var(--ease);
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
.modal-panel {
  background: var(--bg-slate); border: 1px solid var(--border); border-radius: 16px;
  width: 100%; max-width: 620px; max-height: calc(100vh - 48px); overflow-y: auto; padding: 26px 28px;
  box-shadow: var(--shadow-lg); animation: rise .18s var(--ease);
}
@keyframes rise { from { transform: translateY(10px); opacity: 0; } to { transform: none; opacity: 1; } }
.modal-panel.is-wide { max-width: 860px; }
.modal-panel.is-sm { max-width: 440px; }
.modal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; gap: 12px; }
.modal-head h2 { font-size: 1.15rem; margin: 0; }
.modal-close {
  background: none; border: none; color: var(--text-muted); cursor: pointer; padding: 6px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; border-radius: 999px;
}
.modal-close svg { width: 18px; height: 18px; }
.modal-close:hover { color: var(--text-main); background: var(--bg-card); }
.modal-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 8px; flex-wrap: wrap; }
.detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 20px; margin: 0 0 18px; }
/* dt and dd share a grid row, so they need the same top margin — otherwise
   every label sits ~8px below the value it belongs to. Stacked (span-2) pairs
   keep the tight offset because there the label really is above the value. */
.detail-grid dt { font: 600 .74rem/1.45 var(--font-head); color: var(--text-faint); text-transform: uppercase; letter-spacing: .04em; margin-top: 10px; }
.detail-grid dd { margin: 10px 0 0; color: var(--text-main); font-size: .92rem; line-height: 1.45; overflow-wrap: anywhere; }
.detail-grid dt.span-2 + dd.span-2 { margin-top: 2px; }
.detail-grid dd.span-2, .detail-grid dt.span-2 { grid-column: 1 / -1; }

.drawer-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.55); z-index: var(--z-drawer); display: flex; justify-content: flex-end; animation: fade-in .15s; }
/* Locks the page behind an open drawer/modal so the board can't scroll away
   underneath it (most visible on mobile). */
body.is-locked { overflow: hidden; }
.drawer {
  width: 100%; max-width: 520px; height: 100%; overflow-y: auto; padding: 26px 28px;
  background: var(--bg-slate); border-left: 1px solid var(--border); box-shadow: var(--shadow-lg);
  animation: slide-in .2s var(--ease); outline: none;
}
@keyframes slide-in { from { transform: translateX(30px); opacity: 0; } to { transform: none; opacity: 1; } }

/* ===== Toast ===== */
.toast-stack { position: fixed; bottom: 24px; right: 24px; z-index: var(--z-toast); display: flex; flex-direction: column; gap: 10px; pointer-events: none; }
.toast {
  background: var(--bg-card); border: 1px solid var(--border); color: var(--text-main);
  padding: 13px 16px; border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
  font-size: .88rem; font-weight: 600; max-width: 340px;
  display: flex; align-items: center; gap: 10px; pointer-events: auto;
  animation: rise .2s var(--ease);
}
.toast::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--cyan); flex-shrink: 0; }
.toast.is-success::before { background: var(--green); }
.toast.is-error::before { background: var(--red); }
.toast.is-warn::before { background: var(--amber); }
.toast.is-leaving { opacity: 0; transform: translateY(8px); transition: opacity .2s, transform .2s; }

/* ===== Tabs ===== */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 20px; overflow-x: auto; }
.tab {
  padding: 11px 16px; border: none; background: none; color: var(--text-muted);
  font: 700 .88rem/1 var(--font-head); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px;
  white-space: nowrap; display: inline-flex; align-items: center; gap: 8px;
}
.tab:hover { color: var(--text-main); }
.tab.active { color: var(--cyan); border-bottom-color: var(--cyan); }
.tab .tab-count { font-size: .72rem; background: var(--bg-card); padding: 2px 7px; border-radius: 999px; color: var(--text-faint); }
.tab.active .tab-count { background: var(--cyan-dim); color: var(--cyan); }

/* ===== Stat cards ===== */
.stat-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 24px; }
.stat-card { padding: 18px 20px; display: block; color: inherit; }
.stat-card-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.stat-card-icon { width: 38px; height: 38px; border-radius: 10px; display: flex; align-items: center; justify-content: center; }
.stat-card-icon svg { width: 20px; height: 20px; }
.stat-card-icon.cyan { background: var(--cyan-dim); color: var(--cyan); }
.stat-card-icon.blue { background: var(--blue-dim); color: var(--blue-soft); }
.stat-card-icon.amber { background: var(--amber-dim); color: var(--amber); }
.stat-card-icon.green { background: var(--green-dim); color: var(--green); }
.stat-card-icon.violet { background: var(--violet-dim); color: var(--violet); }
.stat-card-icon.red { background: var(--red-dim); color: var(--red); }
.stat-trend { font: 700 .76rem/1 var(--font-head); display: inline-flex; align-items: center; gap: 3px; color: var(--text-faint); }
.stat-trend.up { color: var(--green); }
.stat-trend.down { color: var(--red); }
.stat-card-value { font: 800 1.7rem/1 var(--font-head); color: var(--text-main); margin-bottom: 4px; font-variant-numeric: tabular-nums; }
.stat-card-label { font-size: .84rem; color: var(--text-muted); margin: 0; }

/* Bar chart (pure CSS) */
.bar-chart { display: flex; align-items: flex-end; gap: 12px; height: 170px; padding-top: 24px; }
.bar-chart-col { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 8px; height: 100%; justify-content: flex-end; min-width: 0; }
.bar-chart-stack { width: 100%; max-width: 34px; display: flex; flex-direction: column-reverse; gap: 2px; flex: 1; justify-content: flex-start; position: relative; }
.bar-chart-bar { width: 100%; border-radius: 4px; background: var(--cyan); transition: opacity var(--t-fast); min-height: 0; }
.bar-chart-bar.is-mod { background: var(--violet); }
.bar-chart-bar:hover { opacity: .8; }
.bar-chart-value { position: absolute; top: -20px; left: 50%; transform: translateX(-50%); font: 700 .72rem/1 var(--font-head); color: var(--text-muted); white-space: nowrap; }
.bar-chart-label { font-size: .72rem; color: var(--text-faint); white-space: nowrap; }
.legend { display: flex; gap: 14px; font-size: .78rem; color: var(--text-muted); flex-wrap: wrap; }
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.legend i { width: 10px; height: 10px; border-radius: 3px; background: var(--cyan); display: inline-block; }
.legend i.is-mod { background: var(--violet); }

/* Activity list */
.activity-list { display: flex; flex-direction: column; }
.activity-item { display: flex; gap: 12px; padding: 11px 0; border-bottom: 1px solid var(--border-soft); align-items: flex-start; }
.activity-item:last-child { border-bottom: none; }
.activity-icon { width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0; display: flex; align-items: center; justify-content: center; background: var(--cyan-dim); color: var(--cyan); }
.activity-icon svg { width: 16px; height: 16px; }
.activity-icon.violet { background: var(--violet-dim); color: var(--violet); }
.activity-icon.amber { background: var(--amber-dim); color: var(--amber); }
.activity-icon.green { background: var(--green-dim); color: var(--green); }
.activity-text { font-size: .87rem; color: var(--text-main); margin: 0 0 2px; }
.activity-time { font-size: .76rem; color: var(--text-faint); }

/* ===== Empty / loading states ===== */
.empty-state { text-align: center; padding: 44px 20px; color: var(--text-faint); }
/* Inside a panel that already has its own padding (overview cards). */
.empty-state.is-inline { padding: 18px; }
.empty-state svg { width: 40px; height: 40px; margin: 0 auto 12px; color: var(--text-faint); opacity: .7; }
.empty-state h3 { font-size: 1rem; color: var(--text-muted); margin-bottom: 6px; }
.empty-state p { font-size: .88rem; margin: 0 auto 14px; max-width: 40ch; }
.loading-state { color: var(--text-faint); font-size: .9rem; padding: 24px 0; display: flex; align-items: center; gap: 10px; }
.spinner { width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--border); border-top-color: var(--cyan); animation: spin .7s linear infinite; flex-shrink: 0; }
.skeleton { background: linear-gradient(90deg, var(--bg-card) 25%, var(--bg-card-hover) 50%, var(--bg-card) 75%); background-size: 200% 100%; animation: shimmer 1.2s infinite; border-radius: var(--radius-sm); min-height: 16px; }
@keyframes shimmer { to { background-position: -200% 0; } }

/* ===== Stepper (intake wizard — identical for repair and mod) ===== */
.stepper { display: flex; align-items: center; gap: 0; margin: 0 0 28px; list-style: none; overflow-x: auto; padding-bottom: 4px; }
.stepper li { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; position: relative; }
.stepper li:not(:last-child)::after { content: ""; flex: 1; height: 2px; background: var(--border); margin: 0 10px; min-width: 14px; }
.stepper .step-dot {
  width: 28px; height: 28px; border-radius: 50%; border: 2px solid var(--border); background: var(--bg-card);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  font: 800 .76rem/1 var(--font-head); color: var(--text-faint); transition: all var(--t-fast);
}
.stepper .step-dot svg { width: 14px; height: 14px; }
.stepper .step-label { font: 600 .8rem/1.2 var(--font-head); color: var(--text-faint); white-space: nowrap; }
.stepper li.is-done .step-dot { background: var(--green); border-color: var(--green); color: var(--text-on-accent); }
.stepper li.is-done .step-label { color: var(--text-muted); }
.stepper li.is-done:not(:last-child)::after { background: var(--green); }
.stepper li.is-current .step-dot { border-color: var(--cyan); background: var(--cyan-dim); color: var(--cyan); box-shadow: 0 0 0 4px var(--cyan-dim); }
.stepper li.is-current .step-label { color: var(--text-main); }
.stepper li button { all: unset; display: flex; align-items: center; gap: 8px; cursor: pointer; }
.stepper li.is-done button:hover .step-label { color: var(--cyan); }

.step-back {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 14px 7px 10px; margin-bottom: 18px; border-radius: var(--radius-pill);
  background: transparent; border: 1px solid var(--border); color: var(--text-muted);
  font: 600 .86rem/1 var(--font-head); cursor: pointer; transition: all var(--t-fast);
}
.step-back svg { width: 16px; height: 16px; flex-shrink: 0; }
.step-back:hover { color: var(--cyan); border-color: var(--cyan); background: var(--cyan-dim); }

.step-head { margin-bottom: 22px; }
.step-head h2 { font-size: clamp(1.3rem, 2.6vw, 1.7rem); margin-bottom: 6px; }
.step-head p { margin: 0; max-width: 60ch; }
.step-nav { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-top: 28px; flex-wrap: wrap; }

/* ===== Pick grid (service type, categories, devices) ===== */
.pick-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.pick-grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
.pick-grid.cols-4 { grid-template-columns: repeat(4, 1fr); }
.pick-card {
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-md);
  padding: 20px; text-align: left; cursor: pointer; color: var(--text-main); display: flex; flex-direction: column; gap: 4px;
  transition: border-color var(--t-fast), transform var(--t-fast), box-shadow var(--t-fast); min-width: 0;
}
.pick-card:hover { border-color: var(--cyan); transform: translateY(-2px); box-shadow: var(--shadow-glow-cyan); }
.pick-card.is-selected { border-color: var(--cyan); background: var(--cyan-dim); }
.pick-icon {
  width: 42px; height: 42px; border-radius: 11px; background: var(--cyan-dim); color: var(--cyan);
  display: flex; align-items: center; justify-content: center; margin-bottom: 10px; flex-shrink: 0;
}
.pick-icon svg { width: 22px; height: 22px; }
.pick-icon.violet { background: var(--violet-dim); color: var(--violet); }
.pick-icon.amber { background: var(--amber-dim); color: var(--amber); }
.pick-icon.green { background: var(--green-dim); color: var(--green); }
.pick-card h3 { font-size: 1rem; margin: 0; overflow-wrap: anywhere; }
.pick-card p { font-size: .83rem; margin: 0; color: var(--text-faint); }
.pick-card .pick-meta { margin-top: auto; padding-top: 8px; font: 700 .8rem var(--font-head); color: var(--cyan); }
.pick-card.is-large { padding: 26px; gap: 8px; }
/* Session 22. 343 phones in one grid is a list, not a choice — the device step
   gets a search box above it. The count sits beside the field so the filter
   always says how much it is hiding. */
.pick-search { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 0 0 16px; min-width: 0; }
.pick-search .input { flex: 1 1 260px; min-width: 0; }
.pick-search-count { font-size: .85rem; color: var(--text-faint); white-space: nowrap; }
.pick-card.is-large .pick-icon { width: 52px; height: 52px; border-radius: 14px; }
.pick-card.is-large .pick-icon svg { width: 26px; height: 26px; }
.pick-card.is-large h3 { font-size: 1.15rem; }

/* ===== Select cards + selection cart (repairs / mods step) ===== */
.select-layout { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 26px; align-items: start; }
.select-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); gap: 14px; }
.select-card {
  position: relative; display: flex; flex-direction: column; gap: 8px; padding: 18px 18px 16px;
  border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-card); cursor: pointer;
  transition: border-color var(--t-fast), background var(--t-fast), transform var(--t-fast);
}
.select-card:hover { border-color: var(--cyan); transform: translateY(-2px); }
.select-card:has(input:focus-visible) { outline: 2px solid var(--cyan); outline-offset: 2px; }
.select-card.selected { border-color: var(--cyan); background: var(--cyan-dim); }
.select-card input[type="checkbox"] { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; pointer-events: none; }
.select-card-head { display: flex; align-items: flex-start; gap: 10px; }
.select-tick {
  flex-shrink: 0; width: 20px; height: 20px; border-radius: 6px; border: 1.5px solid var(--border); background: var(--bg-input);
  display: flex; align-items: center; justify-content: center; color: transparent; transition: all var(--t-fast); margin-top: 1px;
}
.select-tick svg { width: 13px; height: 13px; }
.select-card.selected .select-tick { background: var(--cyan); border-color: var(--cyan); color: var(--text-on-accent); }
.select-card-title { font: 700 .97rem/1.3 var(--font-head); color: var(--text-main); flex: 1; min-width: 0; overflow-wrap: anywhere; }
.select-card-desc { font-size: .84rem; line-height: 1.5; color: var(--text-faint); margin: 0; }
.select-card-price { font: 800 1.05rem var(--font-head); color: var(--cyan); margin-top: auto; }

/* Repair qualities (session 22). A repair that comes in qualities is one card
   that OPENS into a card per quality — name, what it means, price — instead of
   a dropdown: four screen tiers are a choice worth reading, and a <select> hides
   the reading. The list is plain flow content, so it wraps and scrolls on a
   phone like everything else. */
.select-card.is-group { cursor: default; }
.select-card.is-group:hover { transform: none; }
.quality-toggle {
  display: flex; align-items: center; gap: 8px; width: 100%; min-width: 0;
  background: none; border: none; padding: 0; cursor: pointer; text-align: left;
  font: 600 .84rem var(--font-head); color: var(--cyan);
}
.quality-toggle svg { width: 15px; height: 15px; flex-shrink: 0; transition: transform var(--t-fast); }
.quality-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
.quality-list { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; min-width: 0; }
.quality-card {
  display: flex; flex-direction: column; gap: 3px; width: 100%; min-width: 0; text-align: left;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-void);
  padding: 10px 12px; cursor: pointer; transition: border-color var(--t-fast), background var(--t-fast);
}
.quality-card:hover { border-color: var(--cyan); }
.quality-card:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.quality-card.selected { border-color: var(--cyan); background: var(--cyan-dim); }
.quality-card-top { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0; }
.quality-card-name { font: 700 .9rem/1.3 var(--font-head); color: var(--text-main); flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.quality-card-price { font: 800 .92rem var(--font-head); color: var(--cyan); white-space: nowrap; }
.quality-card.selected .quality-card-price { color: var(--text-main); }
.quality-card-desc { font-size: .82rem; line-height: 1.5; color: var(--text-faint); margin: 0; overflow-wrap: anywhere; }
/* What the card says when a quality has been picked. */
.select-card-chosen { font-size: .82rem; color: var(--text-muted); overflow-wrap: anywhere; }

/* The same explanation on the price list, under each quality line. */
.pricelist-variant-desc { display: block; font-size: .78rem; line-height: 1.45; color: var(--text-faint); margin: 2px 0 6px; overflow-wrap: anywhere; }
.select-card-price .from-prefix { font: 600 .76rem var(--font-head); color: var(--text-faint); margin-right: 4px; }

.selection-cart { position: sticky; top: calc(var(--header-h) + 16px); }
.selection-cart-inner { border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-card); padding: 22px; }
.selection-cart h3 { font-size: 1.02rem; margin: 0 0 14px; }
.cart-lines { list-style: none; margin: 0 0 4px; padding: 0; max-height: 320px; overflow-y: auto; }
.cart-line { display: flex; align-items: flex-start; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--border-soft); font-size: .87rem; }
.cart-line:last-child { border-bottom: none; }
.cart-line-name { flex: 1; min-width: 0; color: var(--text-main); overflow-wrap: anywhere; }
.cart-line-price { color: var(--text-muted); white-space: nowrap; }
.cart-line-remove { flex-shrink: 0; width: 20px; height: 20px; padding: 0; border: none; background: transparent; color: var(--text-faint); cursor: pointer; display: flex; align-items: center; justify-content: center; }
.cart-line-remove:hover { color: var(--red); }
.cart-line-remove svg { width: 12px; height: 12px; }
.cart-empty { font-size: .86rem; color: var(--text-faint); margin: 0 0 16px; }
.cart-totals { margin: 14px 0 18px; padding-top: 14px; border-top: 1px solid var(--border); }
.cart-total-row { display: flex; justify-content: space-between; gap: 12px; font-size: .87rem; margin-bottom: 7px; color: var(--text-muted); }
.cart-total-row.is-discount { color: var(--green); }
.cart-total-row.is-total { margin-top: 12px; margin-bottom: 0; padding-top: 12px; border-top: 1px solid var(--border); font: 800 1.15rem var(--font-head); color: var(--text-main); }
.cart-total-row.is-total .cart-total-value { color: var(--cyan); }
.cart-note { font-size: .78rem; color: var(--text-faint); margin: 12px 0 0; text-align: center; }

/* Summary card (estimate / confirmation) */
.summary-card { padding: 22px; }
.summary-card h3 { font-size: .78rem; text-transform: uppercase; letter-spacing: .06em; color: var(--text-faint); margin-bottom: 12px; }
.summary-line { display: flex; justify-content: space-between; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--border-soft); font-size: .9rem; }
.summary-line:last-of-type { border-bottom: none; }
.summary-line span:first-child { color: var(--text-muted); }
.summary-line span:last-child { color: var(--text-main); text-align: right; overflow-wrap: anywhere; }
.summary-total { display: flex; justify-content: space-between; align-items: baseline; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.summary-total strong { font: 800 1.5rem var(--font-head); color: var(--cyan); }
.summary-total .from-prefix { font: 600 .8rem var(--font-head); color: var(--text-faint); margin-right: 4px; }

/* Ticket number box */
.ticket-box {
  display: flex; align-items: center; gap: 12px; background: var(--bg-card); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 14px 16px; margin: 18px 0; flex-wrap: wrap;
}
.ticket-box code { flex: 1; min-width: 140px; color: var(--cyan); font: 800 1.3rem var(--font-mono); letter-spacing: .04em; }
.confirm-check { width: 60px; height: 60px; border-radius: 50%; background: var(--green-dim); color: var(--green); display: flex; align-items: center; justify-content: center; margin: 0 auto 18px; }
.confirm-check svg { width: 28px; height: 28px; }

/* ===== Timeline (tracker) ===== */
.timeline { display: flex; flex-direction: column; margin: 24px 0; }
.timeline-step { display: flex; gap: 16px; }
.timeline-marker { display: flex; flex-direction: column; align-items: center; }
.timeline-dot { width: 26px; height: 26px; border-radius: 50%; border: 2px solid var(--border); background: var(--bg-card); display: flex; align-items: center; justify-content: center; flex-shrink: 0; color: var(--text-faint); }
.timeline-dot svg { width: 13px; height: 13px; }
.timeline-line { width: 2px; flex: 1; background: var(--border); min-height: 26px; }
.timeline-step:last-child .timeline-line { display: none; }
.timeline-content { padding-bottom: 24px; min-width: 0; }
.timeline-content h4 { font-size: .96rem; margin-bottom: 2px; color: var(--text-faint); }
.timeline-content p { font-size: .8rem; margin: 0; }
.timeline-step.done .timeline-dot { border-color: var(--green); background: var(--green); color: var(--text-on-accent); }
.timeline-step.done .timeline-line { background: var(--green); }
.timeline-step.current .timeline-dot { border-color: var(--cyan); background: var(--cyan-dim); color: var(--cyan); box-shadow: 0 0 0 4px var(--cyan-dim); }
.timeline-step.current .timeline-content h4, .timeline-step.done .timeline-content h4 { color: var(--text-main); }

/* ===== Kanban ===== */
/* align-items: stretch keeps every column the same height, so a drop target
   is never a 240px stub next to a 350px neighbour. */
.kanban { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(250px, 1fr); gap: 14px; overflow-x: auto; padding-bottom: 12px; align-items: stretch; }
.kanban-col { background: var(--bg-void); border: 1px solid var(--border); border-radius: var(--radius-md); min-height: 240px; display: flex; flex-direction: column; }
.kanban-col.is-over { border-color: var(--cyan); box-shadow: var(--shadow-glow-cyan); }
/* The stage chip focuses a column instead of collapsing the board. */
.kanban-col.is-focus { border-color: var(--blue); background: var(--bg-slate); }
.kanban-col.is-focus > .kanban-col-head { border-bottom-color: var(--blue); }
.kanban-col-head { display: flex; align-items: center; gap: 8px; padding: 12px 14px; border-bottom: 1px solid var(--border); font: 700 .82rem/1 var(--font-head); color: var(--text-main); }
.kanban-col-head .badge { margin-left: auto; }
.kanban-col-body { padding: 10px; display: flex; flex-direction: column; gap: 8px; flex: 1; }
/* position: relative is load-bearing — the card holds an .sr-only label, and an
   absolutely-positioned child whose containing block sits OUTSIDE .kanban is not
   clipped by its overflow-x, so it stretched the whole page to the board's full
   scroll width. Keeping the containing block on the card keeps it clipped. */
.kanban-card { position: relative; background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 12px 13px; cursor: grab; transition: border-color var(--t-fast), transform var(--t-fast); }
.kanban-card:hover { border-color: var(--cyan); }
.kanban-card.is-dragging { opacity: .5; }
/* Wraps rather than overflows: id + "Hoog" + "Reparatie" is wider than a
   230px mobile column, and only in Dutch — the English pair still fits. */
.kanban-card-top { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }
.kanban-card-top .kanban-card-id { margin-right: auto; white-space: nowrap; flex-shrink: 0; }
.kanban-card-top .badge { flex-shrink: 0; max-width: 100%; }
.kanban-card-id { font: 700 .76rem var(--font-mono); color: var(--cyan); }
.kanban-card-title { font: 700 .9rem/1.3 var(--font-head); color: var(--text-main); margin-bottom: 2px; overflow-wrap: anywhere; }
.kanban-card-sub { font-size: .78rem; color: var(--text-faint); overflow-wrap: anywhere; }
.kanban-card-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 8px; font-size: .76rem; color: var(--text-faint); }
/* Priority as a left edge: costs no horizontal room in a 250px column, which
   a third badge did in Dutch. The card carries a title + sr-only label. */
.kanban-card.is-high { border-left: 3px solid var(--red); padding-left: 10px; }
.kanban-empty { font-size: .8rem; color: var(--text-faint); text-align: center; padding: 20px 8px; border: 1px dashed var(--border); border-radius: var(--radius-sm); }

/* =========================================================
   Two-stage repair payments (T9) — /pay, the tracker's pay card, and the
   money panel in the ticket drawer.

   Written before any markup, like every block since T6a (U7).

   Reuses `.quote-*` where it can: a pay card and a quote card are the same
   object — an amount, an explanation and one decision — so `.pay-card` is a
   modifier on the existing component rather than a second one. The gate fails
   if a `.pay-amount` or `.pay-actions` ever appears, because `.quote-amount`
   and `.quote-actions` already exist and already wrap correctly.

   Nothing here may pin text to one line: outcome notes are free text and a
   Dutch amount label runs long.
   ========================================================= */
.pay-card.is-due { border-color: var(--amber); }
.pay-card .quote-amount { color: var(--amber); }
.pay-purpose { display: block; font-size: .84rem; color: var(--text-muted); margin: 0 0 4px; overflow-wrap: anywhere; }

/* The whole page at /pay. One column, centred, nothing else on it — a payment
   screen with navigation to wander off into is a payment screen people leave. */
.pay-shell { max-width: 520px; margin: 0 auto; min-width: 0; }
.pay-lines { display: flex; flex-direction: column; gap: 8px; margin: 0 0 18px; padding: 0; list-style: none; }
.pay-lines li { display: flex; justify-content: space-between; gap: 12px; font-size: .9rem; color: var(--text-muted); flex-wrap: wrap; }
.pay-lines li span:last-child { color: var(--text-main); overflow-wrap: anywhere; }
.pay-total { display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; align-items: baseline;
  border-top: 1px solid var(--border); padding-top: 14px; margin-bottom: 20px; min-width: 0; }
.pay-total strong { font: 800 1.6rem/1.2 var(--font-head); color: var(--cyan); overflow-wrap: anywhere; }
.pay-total span { font-size: .9rem; color: var(--text-muted); overflow-wrap: anywhere; }
.pay-note { font-size: .85rem; line-height: 1.6; color: var(--text-faint); margin: 16px 0 0; overflow-wrap: anywhere; }
/* The quote card's "total − already paid = still to pay" (session 22). */
.quote-breakdown { margin: 10px 0 14px; }

/* The money panel in the ticket drawer. */
.money-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; margin-bottom: 14px; min-width: 0; }
.money-cell { border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-void); padding: 10px 12px; min-width: 0; }
.money-cell span { display: block; font-size: .74rem; color: var(--text-faint); overflow-wrap: anywhere; }
.money-cell strong { display: block; font: 800 1.02rem/1.3 var(--font-head); color: var(--text-main); overflow-wrap: anywhere; }
.money-cell.is-due strong { color: var(--amber); }
.money-cell.is-paid strong { color: var(--green); }
.money-list { display: flex; flex-direction: column; gap: 10px; margin: 0 0 14px; padding: 0; list-style: none; }
.money-item { border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 10px 12px; min-width: 0; }
.money-item-top { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; min-width: 0; }
.money-item-top strong { flex: 1 1 auto; min-width: 0; font-size: .9rem; overflow-wrap: anywhere; }
.money-moves { margin: 8px 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 4px; }
.money-moves li { display: flex; justify-content: space-between; gap: 10px; font-size: .78rem; color: var(--text-faint); flex-wrap: wrap; }
.money-moves li span:last-child { color: var(--text-muted); overflow-wrap: anywhere; }
/* The one loud thing: a no-fix keeps the customer's money, so the drawer says
   so where the balance button would otherwise be. */
.money-nofix {
  display: flex; align-items: flex-start; gap: 10px; min-width: 0;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-void);
  padding: 11px 13px; margin: 0 0 14px; font-size: .85rem; line-height: 1.55;
  color: var(--text-muted); overflow-wrap: anywhere;
}
.money-nofix svg { width: 17px; height: 17px; flex-shrink: 0; margin-top: 2px; color: var(--text-faint); }
/* T-PAY. Under an open request: the Tikkie link the workshop pasted, and the
   "ontvangen via" buttons. The input and its button wrap under each other on a
   narrow drawer rather than squeezing the link to nothing. */
.money-manual { margin: 10px 0 0; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.money-manual-row { display: flex; gap: 8px; flex-wrap: wrap; min-width: 0; }
.money-manual-row input { flex: 1 1 200px; min-width: 0; }
.money-manual .form-actions { margin: 0; }

/* T-PAY. The choice of how to pay on /pay, and what each choice shows. */
.pay-methods { display: flex; flex-direction: column; gap: 10px; margin: 0 0 18px; min-width: 0; }
.pay-method-panel { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.pay-copy { display: flex; align-items: center; gap: 6px; justify-content: flex-end; min-width: 0; flex-wrap: wrap; }
.pay-copy span { overflow-wrap: anywhere; font-family: var(--font-mono); }
.pay-copy .icon-btn { flex-shrink: 0; }

/* Avatar */
.avatar {
  width: 36px; height: 36px; border-radius: 50%; flex-shrink: 0;
  background: linear-gradient(135deg, var(--cyan), var(--blue));
  display: flex; align-items: center; justify-content: center;
  font: 800 .85rem/1 var(--font-head); color: var(--text-on-accent);
}
.avatar.is-visitor { background: var(--bg-card); border: 1px solid var(--border); color: var(--text-muted); }
.avatar.is-sm { width: 28px; height: 28px; font-size: .7rem; }

/* A row of primary/secondary CTAs. Both buttons take the same width, so the
   pair stays aligned no matter how much longer one language's label is. */
.cta-pair { display: flex; gap: 12px; flex-wrap: wrap; }
.cta-pair .btn { flex: 1 1 auto; min-width: 180px; }

/* Layout helpers shared by public + admin */
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; align-items: start; }
.two-col > * { min-width: 0; }

/* Misc */
.kbd { font: 600 .74rem var(--font-mono); background: var(--bg-void); border: 1px solid var(--border); border-radius: 5px; padding: 2px 6px; color: var(--text-muted); }
.price { font: 800 1.1rem var(--font-head); color: var(--cyan); white-space: nowrap; }
.price .from-prefix { font: 600 .74rem var(--font-head); color: var(--text-faint); margin-right: 4px; }
.stock-pill { font: 700 .74rem var(--font-head); }
.stock-pill.is-low { color: var(--amber); }
.stock-pill.is-out { color: var(--red); }
.stock-pill.is-ok { color: var(--green); }
.lang-switch { display: inline-flex; align-items: center; border: 1px solid var(--border); border-radius: var(--radius-pill); padding: 3px; gap: 2px; background: var(--bg-card); }
.lang-switch button { border: none; background: transparent; color: var(--text-muted); font: 700 .74rem/1 var(--font-head); letter-spacing: .03em; padding: 6px 10px; border-radius: var(--radius-pill); cursor: pointer; transition: all var(--t-fast); }
.lang-switch button.active { background: var(--blue); color: #fff; }
.lang-switch button:not(.active):hover { color: var(--text-main); }
.logo { display: inline-flex; align-items: center; gap: 9px; font: 800 1.2rem/1 var(--font-head); color: var(--text-main); white-space: nowrap; }
.logo-mark { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: 10px; background: var(--blue); color: #fff; flex-shrink: 0; }
.logo-mark svg { width: 22px; height: 22px; }
.logo-mod { color: var(--blue-soft); }

/* ===== Catalogue admin — three-column picker =====
   Categorieën -> Apparaten -> Reparaties. Each column is an independent
   scroll region, so a long device list never stretches its neighbours.
   Column headings wrap rather than clip: the Dutch labels ("Reparaties",
   "Categorieën") sit next to a count pill and an add button inside a third
   of the content width, which is where an English-first layout would break. */
.catalog-cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; align-items: stretch; }
.catalog-col {
  display: flex; flex-direction: column; min-width: 0; overflow: hidden;
  background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-md);
}
.catalog-col-head {
  display: flex; align-items: center; gap: 9px; padding: 12px 13px;
  background: var(--bg-void); border-bottom: 1px solid var(--border);
}
.catalog-col-head h3 {
  font: 700 .74rem/1.3 var(--font-head); letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-faint); margin: 0; min-width: 0; overflow-wrap: anywhere;
}
.catalog-col-count {
  font: 700 .7rem/1 var(--font-head); color: var(--text-faint); background: var(--bg-card);
  border: 1px solid var(--border); border-radius: var(--radius-pill); padding: 4px 8px; flex-shrink: 0;
}
.catalog-col-head .catalog-col-add { margin-left: auto; flex-shrink: 0; }
.catalog-col-body { flex: 1; overflow-y: auto; max-height: 58vh; min-height: 120px; padding: 6px; }
.catalog-col.is-muted .catalog-col-body { opacity: .45; pointer-events: none; }
.catalog-col-empty { padding: 20px 12px; text-align: center; font-size: .83rem; color: var(--text-faint); }

/* position: relative so nothing absolute inside a row escapes the scroll box. */
.catalog-row {
  position: relative; display: flex; align-items: center; gap: 8px;
  padding: 7px 8px; border-radius: var(--radius-sm); transition: background var(--t-fast);
}
.catalog-row:hover { background: var(--bg-card-hover); }
.catalog-row.is-selected { background: var(--cyan-dim); }
.catalog-row.is-inactive .catalog-row-name { opacity: .5; }
.catalog-row input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--cyan); cursor: pointer; margin: 0; flex-shrink: 0; }
.catalog-row-main {
  flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px;
  background: none; border: none; padding: 0; margin: 0; text-align: left; cursor: pointer; color: inherit; font: inherit;
}
.catalog-row-main:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; border-radius: 4px; }
.catalog-row-name { font: 600 .89rem/1.3 var(--font-head); color: var(--text-main); overflow-wrap: anywhere; }
.catalog-row-meta { font-size: .75rem; color: var(--text-faint); overflow-wrap: anywhere; }
.catalog-row-flags { display: flex; gap: 4px; flex-shrink: 0; }
.catalog-row-actions { display: flex; gap: 1px; flex-shrink: 0; }

/* Session 26. The model photo in the device editor: the photo (contained, on
   a dark square, like the site shows it) and its two buttons. */
.catalog-photo { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.catalog-photo-preview {
  width: 88px; height: 88px; flex-shrink: 0; display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-sm); border: 1px solid var(--border); background: var(--bg-void);
  font-size: .75rem; text-align: center; padding: 6px; overflow: hidden;
}
.catalog-photo-preview img { width: 100%; height: 100%; object-fit: contain; }
.catalog-photo-none { color: var(--text-faint); line-height: 1.35; }
.catalog-photo-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* Session 29. The model column's brand filter, and the quality names editor.
   Brand and quality names are catalogue data: they wrap, never scroll. */
.catalog-brands { display: flex; flex-wrap: wrap; gap: 6px; padding: 10px 12px; border-bottom: 1px solid var(--border-soft); }
.catalog-brands .chip { white-space: normal; max-width: 100%; text-align: left; }
.catalog-qualities-intro { font-size: .86rem; color: var(--text-muted); margin: 0 0 14px; }
.catalog-qualities { display: flex; flex-direction: column; gap: 16px; max-height: 60vh; overflow-y: auto; padding-right: 4px; }
.catalog-qualities-group h3 { font-size: .9rem; margin: 0 0 8px; }
.catalog-quality { display: grid; grid-template-columns: 90px minmax(0, 1fr) minmax(0, 1fr); gap: 8px; align-items: center; margin-bottom: 6px; }
.catalog-quality-meta { font-size: .75rem; color: var(--text-faint); overflow-wrap: anywhere; }
.catalog-quality.is-head { font: 700 .72rem/1 var(--font-head); letter-spacing: .05em; text-transform: uppercase; color: var(--text-faint); margin-bottom: 0; }
@media (max-width: 560px) { .catalog-quality.is-head { display: none; } }
@media (max-width: 560px) {
  .catalog-quality { grid-template-columns: 1fr; }
}

/* Session 30. The import preview's change lists: one line per change, the
   old → new price on the right. Model and repair names wrap. */
.import-changes { list-style: none; margin: 0 0 12px; padding: 0; max-height: 220px; overflow-y: auto; border: 1px solid var(--border-soft); border-radius: var(--radius-sm); }
.import-changes li { display: flex; justify-content: space-between; gap: 12px; padding: 6px 10px; font-size: .82rem; border-bottom: 1px solid var(--border-soft); }
.import-changes li:last-child { border-bottom: none; }
.import-changes li span:first-child { min-width: 0; overflow-wrap: anywhere; color: var(--text-muted); }
.import-changes li span:last-child { flex-shrink: 0; text-align: right; }
.import-changes li.is-more { color: var(--text-faint); font-style: italic; }

/* Device picker inside the mod editor. */
.catalog-devicepick {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 4px 14px;
  max-height: 240px; overflow-y: auto; padding: 10px 12px;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-input);
}
.catalog-devicepick-group { grid-column: 1 / -1; font: 700 .72rem/1 var(--font-head); letter-spacing: .05em; text-transform: uppercase; color: var(--text-faint); margin: 10px 0 4px; }
.catalog-devicepick-group:first-child { margin-top: 0; }

@media (max-width: 1100px) {
  .catalog-cols { grid-template-columns: 1fr; }
  .catalog-col-body { max-height: 300px; }
}
@media (max-width: 560px) {
  .catalog-devicepick { grid-template-columns: 1fr; }
}

/* ===== Quote block =====
   Shared by the customer tracker and the admin drawer, so one rule set decides
   what a quote looks like on both sides. The amount is the only thing that may
   not wrap; every label around it can, because the Dutch strings here are the
   longest on the page ("Offerte in afwachting van je akkoord" is 2.1x its
   English twin) and they sit in a card that is half a column wide at 1440. */
.quote-card { padding: 20px 22px; border-color: var(--amber); }
.quote-card.is-accepted { border-color: var(--green); }
.quote-card.is-declined { border-color: var(--red); }
.quote-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.quote-head h3 {
  font: 700 .78rem/1.3 var(--font-head); letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-faint); margin: 0; min-width: 0; overflow-wrap: anywhere;
}
.quote-amount {
  font: 800 1.9rem/1.15 var(--font-head); color: var(--cyan);
  margin: 0 0 4px; overflow-wrap: anywhere;
}
.quote-meta { font-size: .8rem; color: var(--text-faint); margin: 0 0 12px; overflow-wrap: anywhere; }
.quote-note {
  margin: 0 0 14px; padding: 11px 13px; border-radius: var(--radius-sm);
  background: var(--bg-input); border: 1px solid var(--border-soft);
  font-size: .88rem; color: var(--text-main); white-space: pre-wrap; overflow-wrap: anywhere;
}
/* Accept / decline. Equal-width pair so the Dutch "Offerte accepteren" and
   "Afwijzen" never leave a lopsided row, and both wrap instead of clipping. */
.quote-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.quote-actions .btn { flex: 1 1 auto; min-width: 150px; max-width: 100%; white-space: normal; }
.quote-state { display: flex; align-items: flex-start; gap: 9px; font-size: .88rem; overflow-wrap: anywhere; }
.quote-state svg { width: 18px; height: 18px; flex-shrink: 0; margin-top: 1px; }
.quote-state.is-accepted { color: var(--green); }
.quote-state.is-declined { color: var(--red); }

/* ===== Settings admin =====
   A stack of independent sections. Business info and shipping/warranty
   all write to one endpoint and share the sticky save bar; the account and
   password sections own their own button because they post somewhere else.
   Every label here is a full Dutch sentence rather than a noun ("Vul een heel
   aantal dagen in, tussen 0 en 3650."), so nothing in this block may be
   nowrap and the bar itself has to wrap onto a second line on a phone. */
.settings-form { display: flex; flex-direction: column; gap: 18px; }
/* The sticky save bar belongs to the three groups it saves, so those groups
   are its containing block: scroll past them and the bar leaves with them
   instead of hovering over the account section, which saves elsewhere. */
.settings-group { display: flex; flex-direction: column; gap: 18px; }
.settings-section { padding: 22px 24px; }
.settings-section .form-grid { margin-top: 2px; }
.settings-section .field:last-child { margin-bottom: 0; }
.settings-note { display: flex; gap: 10px; margin: 0 0 18px; }
.settings-note p { margin: 0; font-size: .86rem; overflow-wrap: anywhere; }

.settings-bar {
  position: sticky; bottom: 0; z-index: 5;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 16px; margin-top: 2px;
  background: var(--bg-slate); border: 1px solid var(--border); border-radius: var(--radius-md);
}
.settings-bar.is-dirty { border-color: var(--amber); }
/* Pushes the buttons right at 1440 and simply sits above them at 320. */
.settings-bar-status { flex: 1 1 220px; min-width: 0; font-size: .84rem; color: var(--text-faint); overflow-wrap: anywhere; }
.settings-bar.is-dirty .settings-bar-status { color: var(--amber); }
.settings-bar .btn { max-width: 100%; }

/* Reveal button lives inside the input, so a long Dutch label never widens it. */
.settings-secret { position: relative; display: flex; }
/* Same specificity as the base .field input rule, declared later, so the
   right-hand padding that makes room for the eye actually lands. */
.field .settings-secret input:not([type="checkbox"]) { flex: 1; min-width: 0; padding-right: 44px; }
.settings-secret .icon-btn {
  position: absolute; top: 50%; right: 5px; transform: translateY(-50%);
  width: 30px; height: 30px; border: none; background: transparent;
}
.settings-secret .icon-btn svg { width: 16px; height: 16px; }

/* =========================================================
   Price list — the catalogue rendered as public marketing copy.
   Used by /repair (categories -> devices -> fixed-price repairs) and
   /modding (mods with a "from" price). One accordion group per device,
   collapsed by default: 26 devices with every repair expanded is a wall.
   Every string in here is catalogue data, so it is bilingual AND
   arbitrarily long — nothing in this block may pin text to one line.
   ========================================================= */
/* Loading placeholders need a height, and a height in the markup is an inline
   style (U2). Two sizes cover every list this project renders. */
.skeleton.is-card { min-height: 132px; }
.skeleton.is-row { min-height: 68px; }

.pricelist { display: flex; flex-direction: column; gap: 12px; }
.pricelist-filters { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 22px; }
.pricelist-search { flex: 1 1 240px; min-width: 0; max-width: 340px; }
/* Category names come from the catalogue ("Retro handhelds & consoles" is a
   value an admin can type). The base .chip is nowrap, which would push a
   horizontal scrollbar onto the page at 320px — let these ones wrap. */
.pricelist-filters .chip { white-space: normal; max-width: 100%; text-align: left; }

.pricelist-group { border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-card); overflow: hidden; }
.pricelist-group.is-open { border-color: var(--cyan); }
.pricelist-head {
  width: 100%; display: flex; align-items: center; gap: 14px;
  padding: 15px 18px; background: none; border: none; text-align: left; color: inherit;
  transition: background var(--t-fast);
}
.pricelist-head:hover { background: var(--bg-card-hover); }
.pricelist-head-main { flex: 1 1 auto; min-width: 0; }
.pricelist-title { display: block; font: 700 1rem/1.3 var(--font-head); color: var(--text-main); overflow-wrap: anywhere; }
.pricelist-sub { display: block; font: 500 .8rem/1.45 var(--font-body); color: var(--text-faint); overflow-wrap: anywhere; }
.pricelist-from { flex: 0 1 auto; font: 700 .86rem/1.3 var(--font-head); color: var(--cyan); text-align: right; overflow-wrap: anywhere; }
.pricelist-caret { flex: 0 0 auto; color: var(--text-faint); display: flex; transition: transform var(--t-base) var(--ease); }
.pricelist-caret svg { width: 18px; height: 18px; }
.pricelist-group.is-open .pricelist-caret { transform: rotate(180deg); }

.pricelist-body { display: none; border-top: 1px solid var(--border); padding: 4px 18px 16px; }
.pricelist-group.is-open .pricelist-body { display: block; }
.pricelist-row { display: flex; align-items: flex-start; gap: 16px; padding: 13px 0; border-bottom: 1px solid var(--border-soft); }
.pricelist-row:last-of-type { border-bottom: none; }
.pricelist-row-main { flex: 1 1 auto; min-width: 0; }
.pricelist-row-name { display: block; font: 600 .93rem/1.35 var(--font-head); color: var(--text-main); overflow-wrap: anywhere; }
.pricelist-row-desc { display: block; font-size: .82rem; line-height: 1.5; color: var(--text-faint); margin-top: 2px; overflow-wrap: anywhere; }
.pricelist-row-time { display: inline-flex; align-items: center; gap: 5px; font-size: .78rem; color: var(--text-faint); margin-top: 5px; }
.pricelist-row-time svg { width: 13px; height: 13px; flex-shrink: 0; }
.pricelist-row-price { flex: 0 0 auto; font: 700 .95rem/1.4 var(--font-head); color: var(--text-main); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.pricelist-foot { display: flex; justify-content: flex-end; padding-top: 14px; }
.pricelist-foot .btn { max-width: 100%; }
.pricelist-note { font-size: .85rem; color: var(--text-faint); margin: 20px 0 0; text-align: center; }

/* =========================================================
   Intake (session 23) — /repair: the price list on the left and the request
   form on the right. Replaced the wizard's step cards. Everything in the list
   is catalogue data — bilingual and arbitrarily long — so nothing in this
   block may pin text to one line (U9).
   ========================================================= */
.intake-tabs { margin-bottom: 22px; }
.intake-tabs button { padding: 8px 22px; font-size: .92rem; }
.intake-chips { margin: 0 0 14px; min-height: 26px; }
.intake-prices .input.is-search { margin-bottom: 16px; }
.intake-chips .chip { white-space: normal; max-width: 100%; text-align: left; }
.intake-hint { font-size: .88rem; color: var(--text-faint); margin: 12px 0; }
/* Session 25. The walk category -> brand -> model. Cards fill the list column
   (two across on a phone); the breadcrumb says where the visitor is and is the
   way back. Category and brand names are catalogue data, so they wrap. */
.pick-grid.intake-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.pick-card.is-compact { padding: 14px 16px; }
.pick-card.is-compact .pick-icon { width: 34px; height: 34px; margin-bottom: 6px; }
.pick-card.is-compact .pick-icon svg { width: 18px; height: 18px; }
/* Session 25. A brand card leads with the brand's logo (single colour, it takes
   the card's text colour) or, for a brand without one, its lettermark. */
.brand-card-logo { display: flex; align-items: center; height: 30px; margin-bottom: 8px; color: var(--text-main); }
.brand-card-logo svg { height: 26px; width: auto; max-width: 110px; }
.pick-card.is-brand:hover .brand-card-logo { color: var(--cyan); }
.brand-card-logo .brand-mark {
  width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  background: var(--cyan-dim); color: var(--cyan); font: 800 .9rem/1 var(--font-head);
}

.intake-chips .intake-crumb { background: none; border: none; padding: 2px 0; font: 600 .88rem/1.3 var(--font-head); color: var(--cyan); cursor: pointer; overflow-wrap: anywhere; text-align: left; }
.intake-chips .intake-crumb:hover { text-decoration: underline; }
.intake-chips .intake-crumb.is-current { font-weight: 800; font-size: 1rem; color: var(--text-main); cursor: default; text-decoration: none; }
.intake-chips .intake-crumb.is-model { color: var(--text-muted); cursor: default; }
.intake-chips .intake-crumb.is-model:hover { text-decoration: none; }
.intake-crumb-sep { display: inline-flex; color: var(--text-faint); }
.intake-crumb-sep svg { width: 14px; height: 14px; }
.intake-chips { align-items: center; }

/* A model in the search results. */
.device-list { display: flex; flex-direction: column; gap: 8px; }
.device-pick {
  width: 100%; display: flex; align-items: center; gap: 12px; min-width: 0;
  padding: 12px 16px; border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--bg-card); color: inherit; text-align: left; cursor: pointer;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.device-pick:hover { border-color: var(--cyan); background: var(--bg-card-hover); }
.device-pick:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.device-pick-name { flex: 1 1 auto; min-width: 0; font: 700 .95rem/1.3 var(--font-head); color: var(--text-main); overflow-wrap: anywhere; }
.device-pick-meta { flex: 0 1 auto; font-size: .8rem; color: var(--text-faint); text-align: right; overflow-wrap: anywhere; }
.device-pick > svg { width: 16px; height: 16px; flex-shrink: 0; color: var(--text-faint); }
/* Session 26. A model's photo, or the drawing of its kind of device. A photo is
   contained, never cropped: a phone shot is tall, a console shot is wide. */
.device-pick-thumb, .price-head-thumb {
  flex-shrink: 0; display: flex; align-items: center; justify-content: center; overflow: hidden;
  border-radius: var(--radius-sm); background: transparent; color: var(--text-muted);
}
/* Session 28 (Furkan): a drawing blends into its row — no box behind it. Only
   an uploaded photo gets a backdrop, so its own edges do not float. */
.device-pick-thumb:has(img), .price-head-thumb:has(img) { background: var(--bg-void); }
.device-pick-thumb { width: 46px; height: 58px; }
.device-pick-thumb .art { width: 32px; height: 32px; }
.price-head-thumb { width: 76px; height: 76px; }
.price-head-thumb .art { width: 56px; height: 56px; }
.device-pick-thumb img, .price-head-thumb img { width: 100%; height: 100%; object-fit: contain; }
/* Session 27. A back view is portrait (a phone is 1:2), so it is sized by its
   height; every line is 1.6px whatever the size, so a thumbnail and the
   heading look like the same drawing. */
.device-pick-thumb .art.is-back { width: auto; height: 52px; }
.price-head-thumb .art.is-back { width: auto; height: 66px; }
.art.is-back * { vector-effect: non-scaling-stroke; }
.device-pick:hover .device-pick-thumb { color: var(--text-main); }
/* The drawings stroke in currentColor; their one accent part is cyan. */
.art .art-accent { stroke: var(--cyan); }
.price-row-art { width: 38px; height: 38px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; color: var(--text-muted); }
.price-row-art svg { width: 100%; height: 100%; }
.price-row.is-selected .price-row-art { color: var(--text-main); }
.intake-others { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border-soft); }
.intake-others-label { display: block; font-size: .84rem; color: var(--text-muted); margin-bottom: 8px; }
.intake-others .chip { white-space: normal; max-width: 100%; text-align: left; }

/* The chosen model's prices. */
.price-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.price-head-main { flex: 1 1 200px; min-width: 0; }
.price-head-name { display: block; font: 800 1.3rem/1.25 var(--font-head); color: var(--text-main); overflow-wrap: anywhere; }
.price-head-sub { display: block; font-size: .84rem; color: var(--text-faint); }
.price-rows { display: flex; flex-direction: column; gap: 8px; }
/* Every price is its own toggle: click to pick, click again to unpick. */
.price-row {
  width: 100%; display: flex; align-items: flex-start; gap: 12px; min-width: 0;
  padding: 12px 16px; border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--bg-card); color: inherit; text-align: left; cursor: pointer;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.price-row:hover { border-color: var(--cyan); }
.price-row:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.price-row.is-selected { border-color: var(--cyan); background: var(--cyan-dim); }
.price-row-tick {
  width: 20px; height: 20px; flex-shrink: 0; margin-top: 1px; border-radius: 6px;
  border: 1.5px solid var(--border); display: flex; align-items: center; justify-content: center; color: transparent;
}
.price-row-tick svg { width: 12px; height: 12px; }
.price-row.is-selected .price-row-tick { background: var(--cyan); border-color: var(--cyan); color: var(--text-on-accent); }
.price-row-main { flex: 1 1 auto; min-width: 0; }
.price-row-name { display: block; font: 600 .93rem/1.35 var(--font-head); color: var(--text-main); overflow-wrap: anywhere; }
.price-row-desc { display: block; font-size: .8rem; line-height: 1.5; color: var(--text-faint); margin-top: 2px; overflow-wrap: anywhere; }
.price-row-price { flex: 0 0 auto; font: 700 .95rem/1.4 var(--font-head); color: var(--cyan); font-variant-numeric: tabular-nums; text-align: right; }
.price-row-price .from-prefix { font: 600 .74rem var(--font-head); color: var(--text-faint); margin-right: 4px; }
/* A repair that comes in qualities: a heading, then one row per quality. */
.price-group { border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-card); padding: 12px 12px 4px; }
.price-group-head { padding: 0 4px 10px; display: flex; align-items: center; gap: 12px; }
.price-group-title { flex: 1 1 auto; min-width: 0; }
.price-group .price-row { margin-bottom: 8px; background: var(--bg-void); }
.price-group .price-row.is-selected { background: var(--cyan-dim); }
/* Session 27. A repair with qualities: one row, the choice in a dropdown. The
   row itself is not a button, so it has no hover lift and no tick. */
/* Session 28: the dropdown became an expanding block. Closed it is one row;
   open, the qualities slide out underneath. The row itself is a container —
   the head and each quality are the buttons. */
.price-row.is-quality { display: block; padding: 0; cursor: default; }
.price-row.is-quality:hover { border-color: var(--border); }
.price-row.is-quality.is-open, .price-row.is-quality.is-selected, .price-row.is-quality.is-selected:hover { border-color: var(--cyan); }
.price-row-tick.is-spacer { visibility: hidden; }
.quality-head {
  width: 100%; display: flex; align-items: center; gap: 12px; min-width: 0;
  padding: 12px 16px; background: none; border: none; border-radius: inherit;
  color: inherit; text-align: left; cursor: pointer;
}
.quality-head:hover .price-row-name { color: var(--cyan); }
.quality-head:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.quality-summary { display: block; font-size: .8rem; line-height: 1.45; color: var(--text-faint); margin-top: 2px; overflow-wrap: anywhere; }
.price-row.is-quality.is-selected .quality-summary { color: var(--cyan); font-weight: 600; }
.quality-chevron { display: flex; flex-shrink: 0; color: var(--text-faint); }
.quality-chevron svg { width: 16px; height: 16px; transition: transform var(--t-fast); }
.price-row.is-quality.is-open .quality-chevron svg { transform: rotate(180deg); }
/* The slide: a grid row going from 0fr to 1fr animates to the content's own
   height, with no height measured in script. */
.quality-panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .22s ease; }
.price-row.is-quality.is-open .quality-panel { grid-template-rows: 1fr; }
.quality-panel-inner { overflow: hidden; min-height: 0; }
.quality-options { display: flex; flex-direction: column; gap: 6px; padding: 0 12px 12px 12px; }
.quality-option {
  display: grid; grid-template-columns: 16px minmax(0, 1fr) auto; gap: 2px 10px; align-items: center;
  width: 100%; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-void); color: inherit; text-align: left; cursor: pointer;
  transition: border-color var(--t-fast), background var(--t-fast);
}
.quality-option:hover { border-color: var(--cyan); }
.quality-option:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.quality-option.is-selected { border-color: var(--cyan); background: var(--cyan-dim); }
.quality-radio { width: 16px; height: 16px; border-radius: 50%; border: 1.5px solid var(--border); }
.quality-option.is-selected .quality-radio { border-color: var(--cyan); box-shadow: inset 0 0 0 3px var(--bg-void), inset 0 0 0 8px var(--cyan); }
.quality-option-name { font: 600 .9rem/1.3 var(--font-head); color: var(--text-main); overflow-wrap: anywhere; }
.quality-option-price { font: 700 .9rem/1.3 var(--font-head); color: var(--cyan); font-variant-numeric: tabular-nums; text-align: right; }
.quality-option-desc { grid-column: 2 / -1; font-size: .78rem; line-height: 1.45; color: var(--text-faint); overflow-wrap: anywhere; }
.quality-clear {
  align-self: flex-start; margin-top: 2px; padding: 4px 2px; background: none; border: none;
  color: var(--text-muted); font-size: .82rem; text-decoration: underline; cursor: pointer;
}
.quality-clear:hover { color: var(--red); }
@media (prefers-reduced-motion: reduce) {
  .quality-panel, .quality-chevron svg { transition: none; }
}
/* On a phone every pixel goes to the dropdown: no spacer, a smaller drawing. */
@media (max-width: 640px) {
  .price-row-tick.is-spacer { display: none; }
  .price-row-art { width: 30px; height: 30px; }
  .price-row { gap: 10px; padding: 12px; }
  .quality-head { gap: 10px; padding: 12px; }
  .quality-options { padding: 0 8px 10px 8px; }
}

/* The form. */
.intake-form { padding: 24px; scroll-margin-top: calc(var(--header-h) + 12px); }
.intake-form-title { font-size: 1.15rem; margin: 0 0 16px; }
.intake-device { font-size: .92rem; padding: 10px 12px; border: 1px dashed var(--border); border-radius: var(--radius-sm); overflow-wrap: anywhere; }
.intake-device-name { font: 700 .95rem var(--font-head); color: var(--text-main); }
.field.is-invalid .intake-device { border-color: var(--red); }
.intake-form .cart-lines { max-height: none; }
.intake-form .cart-totals { margin: 8px 0 18px; }
.intake-form .cart-empty { margin: 0 0 18px; }
.intake-more { margin: 4px 0 16px; }
.intake-more summary { cursor: pointer; font: 600 .9rem var(--font-head); color: var(--text-main); padding: 6px 0; }
.intake-more[open] summary { margin-bottom: 6px; }
.intake-bench { margin: 0 0 12px; padding: 12px 14px; border: 1px solid var(--border-soft); border-radius: var(--radius-sm); font-size: .85rem; }
.intake-bench p { margin: 6px 0 0; font-size: .82rem; }
.intake-disclaimer { font-size: .82rem; color: var(--text-faint); margin: 0 0 14px; }
/* Session 24. The phone bar: pinned to the bottom while something is picked and
   the form is still further down. Never on a wide screen, where the form is
   beside the list. The text is a count and a total, both can wrap. */
.intake-bar {
  display: none; position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 30;
  align-items: center; gap: 12px; padding: 10px 10px 10px 16px;
  border: 1px solid var(--cyan); border-radius: var(--radius-md);
  background: var(--bg-card); box-shadow: var(--shadow-md);
}
.intake-bar-text { flex: 1 1 auto; min-width: 0; font: 700 .9rem/1.3 var(--font-head); color: var(--text-main); overflow-wrap: anywhere; }
.intake-bar .btn { flex: 0 0 auto; max-width: 55%; }
@media (max-width: 900px) {
  .intake-bar:not([hidden]) { display: flex; }
}

/* =========================================================
   Inventory (T3) — /admin/inventory.
   The summary strip, the filter chips and the table itself are all
   pre-existing components (.stat-card, .chip, .data-table); what lives here
   is only what a stock list needs on top of them: the part cell, the stock
   cell with its quick +/- pair, and the adjust panel + movement log in the
   editor. Every label in this block is catalogue-ish data (supplier names,
   shelf locations, part names an admin types), so nothing here may pin text
   to one line — see U9.
   ========================================================= */
.inventory-filters { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
/* Category labels are translated strings ("Gereedschap"), and the base .chip
   is nowrap — which would push a horizontal scrollbar onto the page at 320px. */
.inventory-filters .chip { white-space: normal; max-width: 100%; text-align: left; }

/* Column widths for the fixed-layout stock table. Narrower than the ticket
   board's 1040px because the part cell carries the SKU as a sub-line rather
   than a column of its own. */
.data-table.is-inventory { min-width: 940px; }
.data-table.is-inventory .col-part { width: 28%; }
.data-table.is-inventory .col-cat { width: 12%; }
.data-table.is-inventory .col-stock { width: 15%; }
.data-table.is-inventory .col-money { width: 11%; }
.data-table.is-inventory .col-loc { width: 10%; }
.data-table.is-inventory .col-flags { width: 13%; }

.inventory-cell-name { display: flex; align-items: center; gap: 10px; min-width: 0; }
.inventory-icon {
  width: 32px; height: 32px; border-radius: 9px; flex-shrink: 0;
  background: var(--bg-void); border: 1px solid var(--border); color: var(--text-muted);
  display: flex; align-items: center; justify-content: center;
}
.inventory-icon svg { width: 17px; height: 17px; }
.inventory-name { min-width: 0; overflow-wrap: anywhere; }

.inventory-stock { display: flex; align-items: center; justify-content: flex-end; gap: 6px; flex-wrap: wrap; }
.inventory-stock-value { font: 800 .96rem/1.3 var(--font-head); font-variant-numeric: tabular-nums; color: var(--text-main); }
.inventory-stock-value.is-low { color: var(--amber); }
.inventory-stock-value.is-out { color: var(--red); }
.inventory-stock-min { font-size: .74rem; color: var(--text-faint); overflow-wrap: anywhere; }
.inventory-quick { display: inline-flex; gap: 2px; flex-shrink: 0; }
.inventory-flags { display: flex; gap: 4px; flex-wrap: wrap; }

/* ---- Editor: the stock panel and its movement log ---- */
.inventory-stockbox { border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-void); padding: 15px 16px; margin-bottom: 18px; }
.inventory-stockbox-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.inventory-stockbox-label { font: 600 .84rem/1.2 var(--font-head); color: var(--text-muted); overflow-wrap: anywhere; }
.inventory-stockbox-value { font: 800 1.45rem/1.1 var(--font-head); color: var(--cyan); font-variant-numeric: tabular-nums; }
.inventory-stockbox-note { font-size: .8rem; color: var(--text-faint); margin: 6px 0 14px; overflow-wrap: anywhere; }
.inventory-adjust { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.inventory-adjust > .span-2 { grid-column: 1 / -1; }
.inventory-adjust .field { margin-bottom: 12px; }
.inventory-adjust-actions { display: flex; justify-content: flex-end; gap: 10px; flex-wrap: wrap; }
.inventory-adjust-actions .btn { max-width: 100%; }

.inventory-moves { list-style: none; margin: 0; padding: 0; max-height: 220px; overflow-y: auto; }
.inventory-move { display: flex; align-items: flex-start; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--border-soft); font-size: .85rem; }
.inventory-move:last-child { border-bottom: none; }
.inventory-move-delta { flex: 0 0 auto; min-width: 46px; text-align: right; font: 800 .88rem/1.45 var(--font-head); font-variant-numeric: tabular-nums; color: var(--text-muted); }
.inventory-move-delta.is-in { color: var(--green); }
.inventory-move-delta.is-out { color: var(--red); }
.inventory-move-main { flex: 1 1 auto; min-width: 0; }
.inventory-move-reason { display: block; color: var(--text-main); overflow-wrap: anywhere; }
.inventory-move-meta { display: block; font-size: .76rem; color: var(--text-faint); overflow-wrap: anywhere; }
.inventory-moves-empty { font-size: .84rem; color: var(--text-faint); margin: 0; overflow-wrap: anywhere; }

@media (max-width: 640px) {
  .inventory-adjust { grid-template-columns: 1fr; }
  .inventory-stock { justify-content: flex-start; }
}

/* =========================================================
   Shop (T6a) — /shop, and everything T6b's checkout will reuse.
   U7: before this block the library had no product components at all.
   The cart is NOT redefined here: the wizard-era `.cart-*` rules
   (.cart-lines / .cart-line / .cart-totals / .cart-total-row) already
   describe a line-item list with totals, and the shop cart is the same
   object. What is new is the product grid, the card, the stock badge and
   the quantity stepper.

   Every string rendered inside these rules is catalogue data an admin
   typed (part names, supplier-ish descriptions, SKUs), so nothing here may
   pin text to one line — the same rule the price list and the stock table
   are held to. NL runs ~25% longer than EN.
   ========================================================= */
.shop-filters { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 22px; }
.shop-search { flex: 1 1 240px; min-width: 0; max-width: 340px; }
/* U9: .chip is nowrap by default and these carry catalogue category labels
   ("Gereedschap", "Modchips") — let them wrap or they scroll the page at 320px. */
.shop-filters .chip { white-space: normal; max-width: 100%; text-align: left; }
.shop-layout { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 26px; align-items: start; }
.shop-note { font-size: .85rem; color: var(--text-faint); margin: 20px 0 0; text-align: center; overflow-wrap: anywhere; }

.product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 14px; }
.product-card {
  display: flex; flex-direction: column; gap: 8px; min-width: 0;
  padding: 18px; border: 1px solid var(--border); border-radius: var(--radius-md);
  background: var(--bg-card); transition: border-color var(--t-fast), transform var(--t-fast), box-shadow var(--t-fast);
}
.product-card:hover { border-color: var(--cyan); transform: translateY(-2px); box-shadow: var(--shadow-glow-cyan); }
.product-card.is-out { opacity: .72; }
.product-card.is-out:hover { transform: none; box-shadow: none; border-color: var(--border); }
.product-card-top { display: flex; align-items: flex-start; gap: 10px; min-width: 0; }
.product-icon {
  width: 40px; height: 40px; border-radius: 11px; flex-shrink: 0;
  background: var(--bg-void); border: 1px solid var(--border); color: var(--cyan);
  display: flex; align-items: center; justify-content: center;
}
.product-icon svg { width: 20px; height: 20px; }
.product-head { min-width: 0; flex: 1 1 auto; }
.product-name { display: block; font: 700 .97rem/1.35 var(--font-head); color: var(--text-main); overflow-wrap: anywhere; }
.product-sku { display: block; font: 600 .74rem/1.4 var(--font-mono); color: var(--text-faint); overflow-wrap: anywhere; }
.product-desc { font-size: .83rem; line-height: 1.5; color: var(--text-faint); margin: 0; overflow-wrap: anywhere; }
.product-price { font: 800 1.12rem/1.3 var(--font-head); color: var(--cyan); font-variant-numeric: tabular-nums; margin-top: auto; overflow-wrap: anywhere; }
.product-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-top: 4px; }
.product-foot .btn { max-width: 100%; }
.product-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.product-in-cart { font: 700 .78rem/1.3 var(--font-head); color: var(--green); overflow-wrap: anywhere; }

/* Stock badge — a .badge variant, so the colour language matches the rest
   of the product (green/amber/red mean the same thing everywhere). */
.stock-badge {
  display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px;
  border-radius: var(--radius-pill); font: 700 .74rem/1.45 var(--font-head);
  white-space: normal; max-width: 100%; overflow-wrap: anywhere;
}
.stock-badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.stock-badge.is-in  { background: var(--green-dim); color: var(--green); }
.stock-badge.is-low { background: var(--amber-dim); color: var(--amber); }
.stock-badge.is-out { background: var(--red-dim); color: var(--red); }

/* Quantity stepper — left unclaimed by T3 on purpose (the stock screen's own
   ±1 pair is .inventory-quick, which adjusts a warehouse count). This one is
   a customer-facing quantity control: −  [n]  +, used on the product card and
   on every cart line. */
.qty-stepper { display: inline-flex; align-items: center; gap: 2px; flex-shrink: 0; border: 1px solid var(--border); border-radius: var(--radius-pill); padding: 2px; background: var(--bg-void); }
.qty-stepper button {
  width: 26px; height: 26px; border: none; background: transparent; border-radius: 50%;
  color: var(--text-muted); cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0;
  transition: color var(--t-fast), background var(--t-fast);
}
.qty-stepper button svg { width: 13px; height: 13px; }
.qty-stepper button:hover:not([disabled]) { color: var(--cyan); background: var(--cyan-dim); }
.qty-stepper button[disabled] { opacity: .4; cursor: not-allowed; }
.qty-stepper-value { min-width: 26px; text-align: center; font: 800 .86rem/1 var(--font-head); color: var(--text-main); font-variant-numeric: tabular-nums; }
.qty-stepper.is-sm button { width: 22px; height: 22px; }
.qty-stepper.is-sm .qty-stepper-value { min-width: 20px; font-size: .8rem; }

/* The cart panel itself reuses .selection-cart / .cart-* from the wizard.
   These two only add what a shop line needs on top: a quantity row under the
   name, and a max-reached hint. */
.cart-line-qty { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 5px; }
.cart-line-sub { display: block; font-size: .76rem; color: var(--text-faint); overflow-wrap: anywhere; }

@media (max-width: 940px) {
  .shop-layout { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .shop-search { max-width: 100%; flex-basis: 100%; }
  .product-grid { grid-template-columns: 1fr; }
  .product-foot { align-items: flex-start; }
}

/* =========================================================
   Demo checkout (T6b) — /checkout and /order.

   THE MOST IMPORTANT RULE IN THIS BLOCK: `.demo-banner`.
   D7 says v1 takes no money. A customer who fills in an address, presses a
   button and gets an order number will assume they have paid unless we say
   otherwise loudly, in the same place they are looking. So the banner is a
   permanent structural element of both pages — not a toast, not an `.alert`
   that a page might forget to `.show`. It is amber (a state, not an error),
   it sits above the fold on the checkout page and directly under the order
   number on the confirmation, and it is deliberately hard to miss.

   Everything else reuses what is already here: the basket is the same
   `.selection-cart` / `.cart-*` object the wizard and /shop use, the form is
   the shared `.field` / `.form-grid` pair, and the money lines are
   `.cart-total-row`. What is new is the two-column checkout shell, the
   grouped form sections and the read-only order line list on /order — a
   placed order has no steppers, so it cannot reuse `.cart-line`.

   Nothing here may pin text to one line: part names, street names and city
   names are all free text, and NL runs ~25% longer than EN.
   ========================================================= */
.demo-banner {
  display: flex; align-items: flex-start; gap: 12px; min-width: 0;
  padding: 14px 16px; margin: 0 0 22px;
  border: 1px solid var(--amber); border-radius: var(--radius-md);
  background: var(--amber-dim); color: var(--text-main);
  font-size: .89rem; line-height: 1.55; overflow-wrap: anywhere;
}
.demo-banner svg { width: 20px; height: 20px; flex-shrink: 0; margin-top: 2px; color: var(--amber); }
.demo-banner-body { min-width: 0; }
.demo-banner strong { display: block; font: 800 .95rem/1.4 var(--font-head); color: var(--amber); overflow-wrap: anywhere; }
.demo-banner p { margin: 3px 0 0; color: var(--text-muted); overflow-wrap: anywhere; }
.demo-banner.is-tight { padding: 11px 14px; margin-bottom: 16px; }

/* The checkout shell. Same proportions and the same collapse point as
   .shop-layout, so moving from the shop to the checkout does not move the
   basket across the screen. */
.checkout-layout { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 26px; align-items: start; }
.checkout-main { min-width: 0; }
.checkout-section { margin-bottom: 26px; min-width: 0; }
.checkout-section:last-child { margin-bottom: 0; }
.checkout-section > h2 { font: 800 1.08rem/1.35 var(--font-head); margin: 0 0 4px; overflow-wrap: anywhere; }
.checkout-section > p { font-size: .87rem; color: var(--text-faint); margin: 0 0 16px; overflow-wrap: anywhere; }
.checkout-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 4px; }
.checkout-actions .btn { max-width: 100%; }
.checkout-back { display: inline-flex; align-items: center; gap: 6px; font-size: .87rem; margin-bottom: 18px; max-width: 100%; overflow-wrap: anywhere; }
.checkout-back svg { width: 15px; height: 15px; flex-shrink: 0; }
/* The postcode/house-number row: two narrow fields that must still stack. */
.checkout-grid-3 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 0 18px; }
.checkout-note { font-size: .8rem; color: var(--text-faint); margin: 10px 0 0; text-align: center; overflow-wrap: anywhere; }

/* Placed-order line list (/order). Read-only on purpose: an order that has
   been recorded is a record, so there is no stepper and no remove button. */
.order-lines { list-style: none; margin: 0; padding: 0; }
.order-line { display: flex; align-items: flex-start; gap: 12px; padding: 11px 0; border-bottom: 1px solid var(--border-soft); font-size: .89rem; min-width: 0; }
.order-line:last-child { border-bottom: none; }
.order-line-qty { flex: 0 0 auto; min-width: 34px; font: 800 .88rem/1.5 var(--font-head); color: var(--text-faint); font-variant-numeric: tabular-nums; }
.order-line-main { flex: 1 1 auto; min-width: 0; }
.order-line-name { display: block; color: var(--text-main); overflow-wrap: anywhere; }
.order-line-meta { display: block; font: 600 .76rem/1.45 var(--font-mono); color: var(--text-faint); overflow-wrap: anywhere; }
.order-line-price { flex: 0 0 auto; color: var(--text-muted); font-variant-numeric: tabular-nums; text-align: right; overflow-wrap: anywhere; }
.order-address { font-size: .89rem; line-height: 1.6; color: var(--text-muted); margin: 0; overflow-wrap: anywhere; white-space: pre-line; }
.order-address strong { display: block; color: var(--text-main); overflow-wrap: anywhere; }
/* "What happens next" — the same shape /confirm uses for a ticket, but as a
   class rather than the three inline styles that file still carries (U2). */
.order-steps { display: flex; flex-direction: column; gap: 10px; margin: 0; padding-left: 18px; color: var(--text-muted); font-size: .92rem; }
.order-steps li { overflow-wrap: anywhere; }

@media (max-width: 940px) {
  .checkout-layout { grid-template-columns: 1fr; }
  /* The summary leads on a phone: you check what you are ordering before you
     type an address, not after. .selection-cart already sticks at this width. */
  .checkout-summary { order: -1; }
}
@media (max-width: 520px) {
  .checkout-grid-3 { grid-template-columns: 1fr; }
}

/* =========================================================
   Orders admin (T6c) — /admin/orders.

   Written before any markup, the way T6a's shop block was (U7).

   Almost nothing here is new. The order lines in the drawer are the
   `.order-line` / `.order-lines` pair T6b already wrote for /order — a placed
   order is a read-only record on both sides of the counter, so it renders the
   same way. The money lines are `.cart-total-row`. The address is
   `.order-address`. The drawer, the detail grid, the badges, the chips and
   the table are all straight out of the shared library. What this block adds
   is the table's column widths, the cells that stack two lines, and a small
   fulfilment panel.

   U8: the orders table is the SECOND Dutch-headed `.data-table` in the
   product. It takes the same escape /admin/inventory took — `.is-fixed` with
   percentage column widths and its own min-width — rather than trusting the
   untested 640px default. Six columns instead of eight, so 900px.

   Nothing here may pin text to one line: customer names, street names, city
   names and part names are all free text, and NL runs ~25% longer than EN.
   ========================================================= */
.orders-filters { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
/* U9: .chip is nowrap by default and these carry Dutch status labels
   ("In behandeling", "Wacht op betaling") — let them wrap. */
.orders-filters .chip { white-space: normal; max-width: 100%; text-align: left; }

.data-table.is-orders { min-width: 900px; }
.data-table.is-orders .col-order { width: 18%; }
.data-table.is-orders .col-customer { width: 24%; }
.data-table.is-orders .col-lines { width: 18%; }
.data-table.is-orders .col-money { width: 12%; }
.data-table.is-orders .col-ship { width: 14%; }
.data-table.is-orders .col-status { width: 14%; }

.orders-id { display: block; font: 800 .86rem/1.4 var(--font-mono); color: var(--cyan); overflow-wrap: anywhere; }
.orders-when { display: block; font-size: .76rem; color: var(--text-faint); overflow-wrap: anywhere; }
.orders-customer { min-width: 0; overflow-wrap: anywhere; }
.orders-lines-cell { display: block; color: var(--text-muted); overflow-wrap: anywhere; }
.orders-lines-sub { display: block; font-size: .76rem; color: var(--text-faint); overflow-wrap: anywhere; }
.orders-badges { display: flex; gap: 4px; flex-wrap: wrap; }
.orders-badges .badge { max-width: 100%; overflow-wrap: anywhere; }

/* Drawer: the read-only half above the fold, the form below it. */
.orders-drawer-title { display: block; font: 800 1.15rem/1.3 var(--font-mono); color: var(--cyan); overflow-wrap: anywhere; }
.orders-section { margin-bottom: 4px; min-width: 0; }
.orders-section h3 { font: 800 .95rem/1.35 var(--font-head); margin: 0 0 10px; overflow-wrap: anywhere; }
.orders-note-box {
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-void);
  padding: 12px 14px; font-size: .88rem; line-height: 1.55; color: var(--text-muted);
  margin: 0; overflow-wrap: anywhere; white-space: pre-line;
}
.orders-track { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.orders-track code { font: 700 .84rem/1.5 var(--font-mono); color: var(--text-main); overflow-wrap: anywhere; }
/* The one loud thing on this screen. Cancelling or refunding gives stock back
   and cannot be undone, so the drawer says so where the button is. */
.orders-warning {
  display: flex; align-items: flex-start; gap: 10px; min-width: 0;
  border: 1px solid var(--amber); border-radius: var(--radius-sm); background: var(--amber-dim);
  padding: 11px 13px; margin: 0 0 14px; font-size: .85rem; line-height: 1.55;
  color: var(--text-muted); overflow-wrap: anywhere;
}
.orders-warning svg { width: 17px; height: 17px; flex-shrink: 0; margin-top: 2px; color: var(--amber); }
.orders-timeline { display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; list-style: none; }
.orders-timeline li { display: flex; justify-content: space-between; gap: 12px; font-size: .83rem; color: var(--text-faint); flex-wrap: wrap; }
.orders-timeline li span:last-child { color: var(--text-muted); overflow-wrap: anywhere; }

@media (max-width: 640px) {
  .orders-track { align-items: flex-start; }
}

/* =========================================================
   Outbox (T7) — /admin/emails.

   Written before any markup, like T6a's shop block, T6c's orders block and
   S9's legal block (U7).

   This screen carries the longest single string in the admin: a fully rendered
   email body, shown verbatim in `.emails-body`. Everything else here is the
   third Dutch-headed `.data-table` (U8), so it takes the same escape the other
   two did — `.is-fixed` with its own min-width and percentage columns rather
   than the untested 640px default. Four columns, so 820px.

   `.st-held`, `.st-queued` and `.st-sent` extend the existing status-chip
   family rather than declaring a fourth badge vocabulary; `held` borrows the
   amber of `waiting_parts` because it means the same thing — something is
   sitting there waiting for a human.
   ========================================================= */
.st-held   { background: var(--amber-dim); color: var(--amber); }
.st-queued { background: var(--blue-dim); color: var(--blue-soft); }
.st-sent   { background: var(--green-dim); color: var(--green); }

.emails-filters { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
/* U9: .chip is nowrap by default and these carry Dutch status labels
   ("Niet verstuurd", "Mislukt") — let them wrap. */
.emails-filters .chip { white-space: normal; max-width: 100%; text-align: left; }

.data-table.is-emails { min-width: 820px; }
.data-table.is-emails .col-when { width: 16%; }
.data-table.is-emails .col-to { width: 26%; }
.data-table.is-emails .col-subject { width: 40%; }
.data-table.is-emails .col-state { width: 18%; }

.emails-subject { display: block; color: var(--text-main); overflow-wrap: anywhere; }
.emails-kind { display: block; font-size: .76rem; color: var(--text-faint); overflow-wrap: anywhere; }
.emails-to { display: block; overflow-wrap: anywhere; }
.emails-ref { display: block; font: 700 .76rem/1.45 var(--font-mono); color: var(--cyan); overflow-wrap: anywhere; }
.emails-when { display: block; font-size: .8rem; color: var(--text-muted); overflow-wrap: anywhere; }

/* The transport banner. Permanently on screen while no SMTP host is set,
   because "held" is a silent state and an admin who does not know delivery is
   off will read an outbox full of amber as a fault. */
.emails-transport {
  display: flex; align-items: flex-start; gap: 10px; min-width: 0;
  border: 1px solid var(--amber); border-radius: var(--radius-sm); background: var(--amber-dim);
  padding: 11px 13px; margin: 0 0 16px; font-size: .87rem; line-height: 1.55;
  color: var(--text-muted); overflow-wrap: anywhere;
}
.emails-transport.is-live { border-color: var(--green); background: var(--green-dim); }
.emails-transport svg { width: 17px; height: 17px; flex-shrink: 0; margin-top: 2px; color: currentColor; }
.emails-transport-text { min-width: 0; overflow-wrap: anywhere; }
.emails-transport-text strong { display: block; color: var(--text-main); overflow-wrap: anywhere; }

.emails-drawer-title { display: block; font: 800 1.02rem/1.35 var(--font-head); color: var(--text-main); overflow-wrap: anywhere; }
.emails-section { margin-bottom: 4px; min-width: 0; }
.emails-section h3 { font: 800 .95rem/1.35 var(--font-head); margin: 0 0 10px; overflow-wrap: anywhere; }
/* The rendered message, verbatim. `pre-wrap` keeps the blank lines that make a
   plain-text email readable; `overflow-wrap: anywhere` stops a long token link
   from widening the drawer (and, through it, the document). */
.emails-body {
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-void);
  padding: 14px 15px; margin: 0; max-height: 420px; overflow-y: auto;
  font: 400 .84rem/1.65 var(--font-mono); color: var(--text-muted);
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.emails-error {
  border: 1px solid var(--red); border-radius: var(--radius-sm); background: var(--red-dim);
  padding: 11px 13px; margin: 0 0 14px; font-size: .85rem; line-height: 1.55;
  color: var(--text-muted); overflow-wrap: anywhere;
}
.emails-meta { display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; list-style: none; }
.emails-meta li { display: flex; justify-content: space-between; gap: 12px; font-size: .83rem; color: var(--text-faint); flex-wrap: wrap; }
.emails-meta li span:last-child { color: var(--text-muted); overflow-wrap: anywhere; }

/* =========================================================
   Legal pages (S9) — /privacy, /voorwaarden, /herroepingsrecht.

   Written before any markup, the way T6a's shop block and T6c's orders block
   were (U7).

   These three pages are long-form prose, which nothing else in the product is.
   Every other surface is a grid of short, known strings; a privacy statement is
   paragraphs, nested lists and defined terms, and the copy is written in the
   dictionary rather than in the markup. So `.legal-body` styles its children by
   TAG, not by class: the dictionary strings carry `<p>`, `<ul>`, `<li>` and
   `<strong>` and no class attributes at all. That is deliberate and gate-locked
   — a class inside a translation string would be a component nobody could find.

   Everything else is reused. The missing-details notice is `.orders-warning`'s
   shape, the callout is `.orders-note-box`'s, and the page frame is the same
   `.section` / `.container` every public page uses.

   Nothing here may pin text to one line: this is the longest Dutch copy in the
   product, and legal phrases ("herroepingsrecht", "verwerkingsverantwoordelijke")
   are single words longer than a 320px column.
   ========================================================= */

/* A measured column. Legal prose is unreadable at full container width, and a
   fixed ch measure beats a fixed px one because NL runs ~25% longer than EN. */
.legal-doc { max-width: 74ch; margin: 0 auto; min-width: 0; }
.legal-lead { font-size: 1rem; line-height: 1.7; color: var(--text-muted); margin: 0 0 18px; overflow-wrap: anywhere; }
.legal-updated { display: block; font-size: .8rem; color: var(--text-faint); margin: 0 0 24px; overflow-wrap: anywhere; }

/* Table of contents. Numbered by CSS so the dictionary never carries "1." —
   inserting a section would otherwise mean renumbering every string after it. */
.legal-toc {
  border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--bg-card);
  padding: 18px 20px; margin: 0 0 28px; min-width: 0;
}
.legal-toc h2 { font: 800 .95rem/1.35 var(--font-head); margin: 0 0 10px; color: var(--text-main); overflow-wrap: anywhere; }
.legal-toc ol { margin: 0; padding: 0; list-style: none; counter-reset: legal-toc; }
.legal-toc li { counter-increment: legal-toc; display: flex; gap: 8px; padding: 4px 0; min-width: 0; }
.legal-toc li::before { content: counter(legal-toc) "."; color: var(--text-faint); font: 700 .85rem/1.6 var(--font-mono); flex-shrink: 0; }
.legal-toc a { font-size: .89rem; line-height: 1.6; color: var(--text-muted); min-width: 0; overflow-wrap: anywhere; }
.legal-toc a:hover { color: var(--cyan); }

/* Shown while any of the company details this document is legally required to
   state is still blank in /admin/settings. It disappears on its own the moment
   they are filled in — see the note in legal.js. */
.legal-todo {
  display: flex; align-items: flex-start; gap: 10px; min-width: 0;
  border: 1px solid var(--amber); border-radius: var(--radius-sm); background: var(--amber-dim);
  padding: 12px 14px; margin: 0 0 24px; font-size: .86rem; line-height: 1.6;
  color: var(--text-muted); overflow-wrap: anywhere;
}
.legal-todo svg { width: 17px; height: 17px; flex-shrink: 0; margin-top: 3px; color: var(--amber); }
.legal-todo p { margin: 0; min-width: 0; overflow-wrap: anywhere; }

.legal-section { margin: 0 0 30px; min-width: 0; scroll-margin-top: calc(var(--header-h) + 16px); }
.legal-section h2 {
  font: 800 1.08rem/1.35 var(--font-head); color: var(--text-main);
  margin: 0 0 12px; display: flex; gap: 10px; min-width: 0; overflow-wrap: anywhere;
}
.legal-section h2 .legal-num { color: var(--cyan); font-family: var(--font-mono); flex-shrink: 0; }

/* Tag selectors on purpose: the markup inside comes from the dictionary. */
.legal-body { font-size: .93rem; line-height: 1.75; color: var(--text-muted); min-width: 0; overflow-wrap: anywhere; }
.legal-body p { margin: 0 0 12px; overflow-wrap: anywhere; }
.legal-body p:last-child { margin-bottom: 0; }
.legal-body ul, .legal-body ol { margin: 0 0 12px; padding-left: 20px; }
.legal-body li { margin: 0 0 6px; overflow-wrap: anywhere; }
.legal-body strong { color: var(--text-main); font-weight: 600; }
.legal-body a { color: var(--cyan); overflow-wrap: anywhere; }
.legal-body a:hover { text-decoration: underline; }

/* The company details block. Rendered from /api/settings, never from copy —
   the L8 rule: a KvK number in a translation string is a number nobody updates. */
.legal-meta {
  display: grid; grid-template-columns: minmax(0, 12rem) minmax(0, 1fr); gap: 6px 16px;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-void);
  padding: 14px 16px; margin: 0 0 12px; font-size: .89rem; line-height: 1.65; min-width: 0;
}
.legal-meta dt { color: var(--text-faint); margin: 0; overflow-wrap: anywhere; }
.legal-meta dd { color: var(--text-main); margin: 0; overflow-wrap: anywhere; white-space: pre-line; }

/* The statutory model withdrawal form. It is quoted text, so it is boxed. */
.legal-callout {
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-void);
  padding: 16px 18px; margin: 0 0 12px; min-width: 0;
}
.legal-callout h3 { font: 800 .92rem/1.4 var(--font-head); color: var(--text-main); margin: 0 0 10px; overflow-wrap: anywhere; }

/* The other two documents, at the foot of each one. */
.legal-nav { display: flex; flex-wrap: wrap; gap: 10px 18px; border-top: 1px solid var(--border); padding-top: 18px; margin-top: 4px; min-width: 0; }
.legal-nav a { font-size: .89rem; color: var(--text-muted); max-width: 100%; overflow-wrap: anywhere; }
.legal-nav a:hover { color: var(--cyan); }

@media (max-width: 560px) {
  /* Two columns of a definition list do not survive 320px once the label is
     "Verwerkingsverantwoordelijke". Stack them and keep the label above. */
  .legal-meta { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .legal-meta dd { margin: 0 0 8px; }
  .legal-meta dd:last-child { margin-bottom: 0; }
  .legal-toc { padding: 14px 16px; }
  .legal-callout { padding: 14px 15px; }
}

/* ===== Responsive ===== */
@media (max-width: 1100px) {
  .stat-cards { grid-template-columns: repeat(2, 1fr); }
  .pick-grid.cols-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 940px) {
  .two-col { grid-template-columns: 1fr; }
  .select-layout { grid-template-columns: 1fr; }
  .selection-cart { order: -1; position: sticky; top: var(--header-h); z-index: 20; }
  .selection-cart-inner { padding: 16px 18px; }
  .cart-lines { max-height: 132px; }
  .pick-grid { grid-template-columns: repeat(2, 1fr); }
  .stepper .step-label { display: none; }
  .stepper li.is-current .step-label { display: inline; }
  /* Every `li` is `flex: 1` (basis 0) with `min-width: 0`, so an item is free to
     be laid out NARROWER than its own content — and the one label still on show
     is `white-space: nowrap`, so it cannot shrink to fit. Below 940px that made
     the current step's label run out of its own box and across the next step's
     number: "Categorie" rendered as "Cat(3)e", with the dot painting on top.
     Measured 28px of overlap at 320-480 and still 7px at 600.
     Giving the ONE visible label's item its content width fixes it; the others
     keep `flex: 1` and the connectors between them absorb the difference. */
  .stepper li.is-current { flex: 0 1 auto; min-width: max-content; }
}
@media (max-width: 640px) {
  .stat-cards { grid-template-columns: 1fr 1fr; }
  /* Device name + "vanaf €29,00" side by side is 2 lines each at 320px.
     Stack them instead, caret last, so nothing has to shrink below its text. */
  .pricelist-head { flex-wrap: wrap; gap: 6px 12px; }
  .pricelist-head-main { flex: 1 1 100%; order: 1; }
  .pricelist-from { order: 2; text-align: left; }
  .pricelist-caret { order: 3; margin-left: auto; }
  .pricelist-row { flex-direction: column; gap: 4px; }
  .pricelist-row-price { align-self: flex-start; }
  .pricelist-search { max-width: 100%; flex-basis: 100%; }
  .pick-grid, .pick-grid.cols-2, .pick-grid.cols-4 { grid-template-columns: 1fr; }
  .choice-grid { grid-template-columns: 1fr; }
  .form-grid { grid-template-columns: 1fr; }
  .detail-grid { grid-template-columns: 1fr; }
  .modal-overlay { padding: 12px; align-items: flex-end; }
  .modal-panel { max-height: calc(100vh - 24px); padding: 20px; border-radius: 14px; }
  .drawer { max-width: 100%; padding: 20px; }
  .toast-stack { left: 16px; right: 16px; bottom: 16px; }
  .toast { max-width: 100%; }
  .filter-row .grow-search { margin-left: 0; flex-basis: 100%; }
  .kanban { grid-auto-columns: minmax(230px, 1fr); }
}
@media (max-width: 420px) {
  .stat-cards { grid-template-columns: 1fr; }
  /* Six dots and five connectors plus the one visible label is 13px more than a
     320px screen has, now that the label takes real space instead of overflowing
     its own box. `.stepper` is `overflow-x: auto` so that only cost a short
     sideways scroll — but the sixth step falling off the edge is exactly the
     thing the stepper exists to prevent. Buy the room back from the connectors,
     which are decoration: 8px each, five of them, 40px for a 13px problem. */
  .stepper li:not(:last-child)::after { margin: 0 6px; min-width: 10px; }
}

/* ===== Repair qualities (the variant dropdown) =====================
   Four screen tiers, two battery grades and so on are separate catalogue rows
   sharing a variant_group. The customer sees ONE card with a <select>, so the
   choice reads as a quality rather than as four near-identical repairs to
   compare side by side.

   The select sits inside a .select-card, which is itself a <label> wrapping a
   checkbox — so the page has to stop its clicks from toggling that checkbox.
   Nothing here may be nowrap: the labels are catalogue data, the longest being
   "Origineel nieuw (Service Pack)", and NL runs ~25% longer than EN. */
.variant-row { display: flex; flex-direction: column; gap: 4px; margin-top: 10px; min-width: 0; }
.variant-row > span {
  font-size: .74rem; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-faint); overflow-wrap: anywhere;
}
.variant-row select { width: 100%; max-width: 100%; min-width: 0; font-size: .86rem; padding: 7px 9px; }

/* On /repair every quality is a sub-row under one heading rather than a
   dropdown: it is a price list, and seeing all four at once is the point. */
.pricelist-variants { display: flex; flex-direction: column; gap: 2px; margin-top: 6px; min-width: 0; }
.pricelist-variant {
  display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  font-size: .84rem; color: var(--text-muted); min-width: 0;
}
.pricelist-variant span:first-child { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.pricelist-variant span:last-child { flex: 0 0 auto; color: var(--text-main); font-weight: 700; overflow-wrap: anywhere; }

/* The workshop has to tell four rows called "Schermvervanging" apart. */
.catalog-row-variant {
  display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 999px;
  background: var(--cyan-dim); color: var(--cyan);
  font: 700 .7rem/1.6 var(--font-head); max-width: 100%; overflow-wrap: anywhere;
}

/* ===== Price import (retail CSV -> catalogue) =====================
   The dry-run report inside the import modal: a summary line, a per-column
   table of how many models each repair is priced for, and the errors. Every
   number here is free text from a spreadsheet, so nothing may be pinned to one
   line and every cell needs a wrap escape. */
.import-hint { font-size: .84rem; line-height: 1.55; color: var(--text-faint); margin: 0 0 14px; overflow-wrap: anywhere; }
.import-drop { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.import-file { font-size: .88rem; color: var(--text-muted); overflow-wrap: anywhere; }
.import-summary {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(112px, 1fr)); gap: 8px;
  margin: 14px 0 0; padding: 0; list-style: none; min-width: 0;
}
.import-summary li {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-void); padding: 9px 11px; min-width: 0;
}
.import-summary span { display: block; font-size: .72rem; color: var(--text-faint); overflow-wrap: anywhere; }
.import-summary strong { display: block; font: 800 1.05rem/1.3 var(--font-head); color: var(--text-main); overflow-wrap: anywhere; }
.import-summary li.is-new strong { color: var(--green); }
.import-summary li.is-warn strong { color: var(--amber); }
.import-report { max-height: 42vh; overflow-y: auto; margin-top: 14px; min-width: 0; }
.import-report h4 { font: 700 .85rem/1.4 var(--font-head); color: var(--text-main); margin: 14px 0 6px; }
.import-cols { display: flex; flex-direction: column; gap: 3px; margin: 0; padding: 0; list-style: none; }
.import-cols li {
  display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  font-size: .8rem; color: var(--text-muted); min-width: 0;
}
.import-cols li span:first-child { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.import-cols li span:last-child { flex: 0 0 auto; color: var(--text-faint); }
.import-cols li.is-empty span { color: var(--text-faint); }
.import-errors { display: flex; flex-direction: column; gap: 4px; margin: 0; padding: 0; list-style: none; }
.import-errors li { font-size: .8rem; color: var(--amber); overflow-wrap: anywhere; }

/* ===== Send-in shipping label (T10) =====================================
   Deliberately the LAST block in this file, because the @media print rules at
   the bottom have to win over the responsive @media blocks above them — a
   `max-width` query applies to print too (a printed page has a width), so
   `.stepper .step-label { display: none }` and friends are live while printing
   and the print block has to come after them to override anything it needs to.

   The sheet is drawn to look like a label on screen as well as on paper, so
   nobody has to open a print preview to find out whether it is right. The
   colours below come from tokens.css like everything else; the print-only ink
   and paper tokens exist because a printer forces white and the site's dark
   palette would come out as a black rectangle. */
/* A sub-heading inside a form panel — the wizard's contact and return-address
   groups. Exists so the return-address block did not have to copy the inline
   `style="font-size:1rem"` the contact heading still carries (U2). */
.form-subhead { font: 700 1rem/1.3 var(--font-head); color: var(--text-main); margin: 0 0 4px; max-width: 100%; overflow-wrap: anywhere; }

/* The card on /track. A label card and a quote card are the same object — a
   heading, an explanation and one action — so this is a modifier on
   `.quote-card` exactly as `.pay-card` is, rather than a third component. It
   only changes the accent, because a label is good news and an amber "attention"
   border would read as something owed. */
.label-card { border-color: var(--cyan); }

.label-shell { max-width: 760px; margin: 0 auto; display: grid; gap: 22px; min-width: 0; }
.label-intro h1 { margin: 0 0 10px; }
.label-intro p { color: var(--text-muted); margin: 0 0 14px; max-width: 60ch; overflow-wrap: anywhere; }
.label-steps { margin: 0 0 16px; padding-left: 1.25rem; color: var(--text-muted); display: grid; gap: 6px; min-width: 0; }
.label-steps li { line-height: 1.6; overflow-wrap: anywhere; }
.label-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; min-width: 0; }

/* The sheet itself. A6-ish proportions inside an A4 page, which is the shape a
   parcel label wants and the shape a printer can cut out without maths. */
.label-sheet {
  border: 2px solid var(--text-main); border-radius: var(--radius-sm);
  background: var(--bg-card); color: var(--text-main);
  padding: 20px 22px; display: grid; gap: 16px; min-width: 0;
}
.label-head {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: 6px 14px; border-bottom: 2px solid var(--text-main); padding-bottom: 10px; min-width: 0;
}
.label-brand { font: 800 1.15rem/1.2 var(--font-head); letter-spacing: .01em; max-width: 100%; overflow-wrap: anywhere; }
.label-kicker { font-size: .78rem; letter-spacing: .12em; text-transform: uppercase; color: var(--text-muted); max-width: 100%; overflow-wrap: anywhere; }
.label-caption {
  display: block; font-size: .72rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-faint); margin-bottom: 6px; max-width: 100%; overflow-wrap: anywhere;
}
.label-address { display: grid; gap: 2px; font-size: 1rem; line-height: 1.5; min-width: 0; }
.label-address span, .label-address strong { max-width: 100%; overflow-wrap: anywhere; }
.label-name { font: 700 1.05rem/1.4 var(--font-head); }
/* Decision 3 in label.js: an absent address line is something to write on. */
.label-blank { display: block; border-bottom: 1px solid var(--text-faint); height: 1.35em; max-width: 22rem; }
.label-to { border: 1px solid var(--border); border-radius: var(--radius-xs); padding: 12px 14px; min-width: 0; }
.label-from { min-width: 0; }
.label-ref {
  border-top: 1px dashed var(--border); border-bottom: 1px dashed var(--border);
  padding: 12px 0; display: grid; gap: 6px; justify-items: center; text-align: center; min-width: 0;
}
.label-ref-value { font: 800 1.6rem/1.1 var(--font-mono); letter-spacing: .06em; max-width: 100%; overflow-wrap: anywhere; }
/* The barcode is an inline SVG drawn server-side; it inherits currentColor and
   is allowed to shrink, because a label printed at 90% is still scannable. */
.label-code { display: block; max-width: 100%; }
.label-code svg { display: block; width: 100%; height: auto; max-width: 320px; margin: 0 auto; }
.label-code-text { font: 600 .78rem/1 var(--font-mono); letter-spacing: .22em; color: var(--text-muted); }
.label-foot {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 14px;
  border-top: 1px solid var(--border); padding-top: 10px; font-size: .8rem; color: var(--text-muted); min-width: 0;
}
.label-foot span { max-width: 100%; overflow-wrap: anywhere; }

@media (max-width: 560px) {
  .label-sheet { padding: 16px 16px; }
  .label-ref-value { font-size: 1.3rem; }
}

/* ----- Printing. Scoped to `body.is-print-page`, which only /label sets, so
   printing /track or /order still prints those pages as they are. Everything
   that is not the sheet goes: the site header, the footer, the skip link, the
   toast stack, and the on-screen instructions. */
@media print {
  .is-print-page { background: var(--print-paper); }
  .is-print-page,
  .is-print-page .label-sheet { color: var(--print-ink); }
  .is-print-page [data-site-header],
  .is-print-page [data-site-footer],
  .is-print-page .skip-link,
  .is-print-page .toast-stack,
  .is-print-page .label-intro,
  .is-print-page .loading-state,
  .is-print-page .alert { display: none !important; }
  /* The page wrappers exist to centre content on screen; on paper they only
     add margins the printer already owns. */
  .is-print-page .section { padding: 0 !important; }
  .is-print-page .container,
  .is-print-page .label-shell { max-width: none; margin: 0; padding: 0; gap: 0; }
  .is-print-page .label-sheet {
    border: 2px solid var(--print-ink); background: var(--print-paper);
    padding: 12mm; gap: 10mm; break-inside: avoid; page-break-inside: avoid;
  }
  .is-print-page .label-head,
  .is-print-page .label-sheet .label-name { border-color: var(--print-ink); }
  .is-print-page .label-head { border-bottom-color: var(--print-ink); }
  .is-print-page .label-kicker,
  .is-print-page .label-caption,
  .is-print-page .label-code-text,
  .is-print-page .label-foot { color: var(--print-ink-soft); }
  .is-print-page .label-to { border-color: var(--print-ink); }
  .is-print-page .label-ref { border-color: var(--print-ink-soft); }
  .is-print-page .label-foot { border-top-color: var(--print-ink-soft); }
  .is-print-page .label-blank { border-bottom-color: var(--print-ink-soft); max-width: 60%; }
  .is-print-page .label-code svg { max-width: 90mm; }
  @page { size: A4 portrait; margin: 12mm; }
}
