/*
 * Loondry UI theme for Bootstrap 5.3 (scoped, light + dark).
 * Load AFTER bootstrap.min.css and variables.css.
 * Everything applies only inside an element with class .loondry-ui.
 * Theme follows html[data-bs-theme], same switch used by variables.css.
 * Based on the design handoff "loondry-bootstrap-theme" (Camilla).
 */

/* ---------- Tokens: light ---------- */
.loondry-ui {
  --ld-font-sans: "Poppins", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  --ld-primary: #bfbdfd;
  --ld-primary-hover: #aaa7f5;
  --ld-primary-light: #f3f2ff;
  --ld-primary-border: #d9d7fe;
  --ld-primary-foreground: #28245f;
  --ld-on-primary: #ffffff;

  /* Surfaces follow the app variables so there is one source of truth */
  --ld-surface: var(--app-bg, #ffffff);
  --ld-neutral-50: #fafafa;
  --ld-neutral-100: #f5f5f5;
  --ld-neutral-200: #e5e5e5;
  --ld-neutral-300: #d4d4d4;
  --ld-neutral-400: #a3a3a3;
  --ld-neutral-500: #737373;
  --ld-neutral-600: #525252;
  --ld-neutral-700: #404040;
  --ld-neutral-800: #262626;
  --ld-neutral-900: #171717;
  --ld-neutral-950: #0a0a0a;

  --ld-success-bg: #ecfdf5;
  --ld-success-border: #a7f3d0;
  --ld-success-text: #047857;
  --ld-warning-bg: #fffbeb;
  --ld-warning-border: #fde68a;
  --ld-warning-text: #b45309;
  --ld-danger-bg: #fff1f2;
  --ld-danger-border: #fecdd3;
  --ld-danger-text: #be123c;
  --ld-danger-hover-bg: #ffe4e6;
  --ld-danger-hover-border: #fda4af;
  --ld-danger-hover-text: #9f1239;
  --ld-info-bg: #f0f9ff;
  --ld-info-border: #bae6fd;
  --ld-info-text: #0369a1;

  --ld-radius-sm: 8px;
  --ld-radius-md: 12px;
  --ld-radius-lg: 16px;
  --ld-radius-pill: 999px;

  /* Deliberate deviation from the handoff: card look measured on the reference app (1px gray-100 border, 20px radius, soft wide shadow, 24px padding) */
  --ld-card-border: var(--ld-neutral-200);
  --ld-card-radius: var(--ld-radius-lg);
  --ld-card-padding: 24px;
  --ld-card-shadow: none;
  --ld-text-subtle: var(--ld-neutral-500);
  --ld-shadow-hover: 0 4px 14px rgb(15 23 42 / 0.07);
  --ld-shadow-dropdown: 0 12px 32px rgb(15 23 42 / 0.12);
  --ld-shadow-modal: 0 24px 64px rgb(15 23 42 / 0.18);

  --ld-focus-ring: 0 0 0 3px rgb(191 189 253 / 0.35);
  --ld-transition: 150ms ease;
}

/* ---------- Tokens: dark (neutral scale is inverted) ---------- */
[data-bs-theme="dark"] .loondry-ui {
  --ld-primary-light: rgb(191 189 253 / 0.14);
  --ld-primary-border: rgb(191 189 253 / 0.45);
  --ld-primary-foreground: #d9d7fe;

  --ld-neutral-50: var(--app-bg-layout, #16181d);
  --ld-neutral-100: #1d2026;
  --ld-neutral-200: #2a2e36;
  --ld-neutral-300: #3a3f49;
  --ld-neutral-400: #8b93a1;
  --ld-neutral-500: #9aa1ad;
  --ld-neutral-600: #b4bac4;
  --ld-neutral-700: #cdd2da;
  --ld-neutral-800: #e4e7ec;
  --ld-neutral-900: #f3f4f6;
  --ld-neutral-950: #ffffff;

  --ld-success-bg: rgb(16 185 129 / 0.14);
  --ld-success-border: rgb(16 185 129 / 0.35);
  --ld-success-text: #6ee7b7;
  --ld-warning-bg: rgb(245 158 11 / 0.14);
  --ld-warning-border: rgb(245 158 11 / 0.35);
  --ld-warning-text: #fcd34d;
  --ld-danger-bg: rgb(244 63 94 / 0.14);
  --ld-danger-border: rgb(244 63 94 / 0.35);
  --ld-danger-text: #fda4af;
  --ld-danger-hover-bg: rgb(244 63 94 / 0.24);
  --ld-danger-hover-border: rgb(244 63 94 / 0.55);
  --ld-danger-hover-text: #fecdd3;
  --ld-info-bg: rgb(14 165 233 / 0.14);
  --ld-info-border: rgb(14 165 233 / 0.35);
  --ld-info-text: #7dd3fc;

  --bs-body-bg-rgb: 17, 18, 20;
  --bs-body-color-rgb: 205, 210, 218;
  --bs-emphasis-color-rgb: 243, 244, 246;
  --bs-secondary-color-rgb: 154, 161, 173;
  --bs-secondary-bg-rgb: 29, 32, 38;
  --bs-tertiary-bg-rgb: 22, 24, 29;

  --ld-card-border: var(--ld-neutral-200);
  --ld-card-shadow: none;
  --ld-shadow-hover: 0 4px 14px rgb(0 0 0 / 0.35);
  --ld-shadow-dropdown: 0 12px 32px rgb(0 0 0 / 0.5);
  --ld-shadow-modal: 0 24px 64px rgb(0 0 0 / 0.6);
  --ld-focus-ring: 0 0 0 3px rgb(191 189 253 / 0.3);
}

/* ---------- Base + bridge to Bootstrap variables ---------- */
.loondry-ui {
  --bs-body-font-family: var(--ld-font-sans);
  --bs-body-font-size: 14px;
  --bs-body-line-height: 1.5;
  --bs-body-color: var(--ld-neutral-700);
  --bs-body-bg: var(--ld-surface);
  --bs-emphasis-color: var(--ld-neutral-900);
  --bs-secondary-color: var(--ld-neutral-500);
  --bs-secondary-bg: var(--ld-neutral-100);
  --bs-tertiary-bg: var(--ld-neutral-50);
  --bs-border-color: var(--ld-neutral-200);
  /* rgb triplets: Bootstrap bg-body*, text-body* utilities read these (keep in sync with the tokens above) */
  --bs-body-bg-rgb: 255, 255, 255;
  --bs-body-color-rgb: 64, 64, 64;
  --bs-emphasis-color-rgb: 23, 23, 23;
  --bs-secondary-color-rgb: 115, 115, 115;
  --bs-secondary-bg-rgb: 245, 245, 245;
  --bs-tertiary-bg-rgb: 250, 250, 250;
  --bs-border-radius: var(--ld-radius-sm);
  --bs-border-radius-sm: var(--ld-radius-sm);
  --bs-border-radius-lg: var(--ld-radius-lg);
  --bs-link-color: var(--ld-primary-foreground);
  --bs-link-hover-color: var(--ld-primary-foreground);
  color: var(--ld-neutral-700);
  font-family: var(--ld-font-sans);
  font-size: 14px;
  font-weight: 400;
  line-height: 1.5;
}

.loondry-ui *,
.loondry-ui *::before,
.loondry-ui *::after {
  box-sizing: border-box;
}

/* ---------- Typography ---------- */
.loondry-ui h1,
.loondry-ui .ld-h1 {
  margin: 0;
  color: var(--ld-neutral-900);
  font-size: 28px;
  font-weight: 500;
  line-height: 34px;
  letter-spacing: -0.02em;
}

.loondry-ui h2,
.loondry-ui .ld-h2 {
  margin: 0;
  color: var(--ld-neutral-900);
  font-size: 22px;
  font-weight: 500;
  line-height: 28px;
  letter-spacing: -0.015em;
}

/* h5 = card title level (H3 scale), h6 = subsection level (H4 scale) */
.loondry-ui h3,
.loondry-ui h5,
.loondry-ui .ld-h3 {
  margin: 0;
  color: var(--ld-neutral-900);
  font-size: 17px;
  font-weight: 500;
  line-height: 24px;
}

.loondry-ui h4,
.loondry-ui h6,
.loondry-ui .ld-h4 {
  margin: 0;
  color: var(--ld-neutral-900);
  font-size: 14px;
  font-weight: 500;
  line-height: 20px;
}

/* Never below 13px for content (Bootstrap .small is .875em of the parent) */
.loondry-ui small,
.loondry-ui .small { font-size: 13px; line-height: 20px; }
.loondry-ui .ld-body { font-size: 14px; line-height: 24px; }
.loondry-ui .ld-body-compact { font-size: 13px; line-height: 20px; }
.loondry-ui .ld-text-secondary { color: var(--ld-neutral-500); font-size: 13px; line-height: 20px; }
.loondry-ui .ld-metric { color: var(--ld-neutral-900); font-size: 30px; font-weight: 500; line-height: 1; letter-spacing: -0.02em; }

/* ---------- Buttons (Bootstrap button variables, so hover/active/disabled stay consistent) ---------- */
.loondry-ui .btn {
  --bs-btn-padding-x: 20px;
  --bs-btn-padding-y: 0;
  --bs-btn-font-size: 14px;
  --bs-btn-font-weight: 500;
  --bs-btn-line-height: 20px;
  --bs-btn-border-radius: var(--ld-radius-md);
  min-height: 44px;
  /* d-flex and d-inline-flex are !important utilities: without this the label sits at the top of the min-height */
  align-items: center;
  font-family: var(--ld-font-sans);
  transition: background-color var(--ld-transition), border-color var(--ld-transition), color var(--ld-transition), box-shadow var(--ld-transition);
}

/* A column button keeps stretching its content (cards used as buttons) */
.loondry-ui .btn.flex-column { align-items: stretch; }

.loondry-ui .btn-sm { --bs-btn-padding-x: 16px; --bs-btn-font-size: 13px; min-height: 40px; }
.loondry-ui .btn-lg { --bs-btn-padding-x: 24px; --bs-btn-font-size: 16px; min-height: 48px; min-width: 140px; }

/* Open point: white on #bfbdfd is about 1.8:1 (below AA); kept as in the handoff until agreed with the designer */
.loondry-ui .btn-primary {
  --bs-btn-color: var(--ld-on-primary);
  --bs-btn-bg: var(--ld-primary);
  --bs-btn-border-color: var(--ld-primary);
  --bs-btn-hover-color: var(--ld-on-primary);
  --bs-btn-hover-bg: var(--ld-primary-hover);
  --bs-btn-hover-border-color: var(--ld-primary-hover);
  --bs-btn-active-color: var(--ld-on-primary);
  --bs-btn-active-bg: var(--ld-primary-hover);
  --bs-btn-active-border-color: var(--ld-primary-hover);
  --bs-btn-disabled-color: var(--ld-on-primary);
  --bs-btn-disabled-bg: var(--ld-primary);
  --bs-btn-disabled-border-color: var(--ld-primary);
  --bs-btn-focus-shadow-rgb: 191, 189, 253;
}

.loondry-ui .btn-secondary,
.loondry-ui .btn-outline-secondary {
  --bs-btn-color: var(--ld-neutral-900);
  --bs-btn-bg: var(--ld-surface);
  --bs-btn-border-color: var(--ld-neutral-200);
  --bs-btn-hover-color: var(--ld-neutral-900);
  --bs-btn-hover-bg: var(--ld-neutral-50);
  --bs-btn-hover-border-color: var(--ld-neutral-300);
  --bs-btn-active-color: var(--ld-neutral-900);
  --bs-btn-active-bg: var(--ld-neutral-100);
  --bs-btn-active-border-color: var(--ld-neutral-300);
  --bs-btn-disabled-color: var(--ld-neutral-900);
  --bs-btn-disabled-bg: var(--ld-surface);
  --bs-btn-disabled-border-color: var(--ld-neutral-200);
}

.loondry-ui .btn-danger {
  --bs-btn-color: var(--ld-danger-text);
  --bs-btn-bg: var(--ld-danger-bg);
  --bs-btn-border-color: var(--ld-danger-border);
  --bs-btn-hover-color: var(--ld-danger-hover-text);
  --bs-btn-hover-bg: var(--ld-danger-hover-bg);
  --bs-btn-hover-border-color: var(--ld-danger-hover-border);
  --bs-btn-active-color: var(--ld-danger-hover-text);
  --bs-btn-active-bg: var(--ld-danger-hover-bg);
  --bs-btn-active-border-color: var(--ld-danger-hover-border);
  --bs-btn-disabled-color: var(--ld-danger-text);
  --bs-btn-disabled-bg: var(--ld-danger-bg);
  --bs-btn-disabled-border-color: var(--ld-danger-border);
}

.loondry-ui .btn-outline-danger {
  --bs-btn-color: var(--ld-danger-text);
  --bs-btn-bg: transparent;
  --bs-btn-border-color: var(--ld-danger-border);
  --bs-btn-hover-color: var(--ld-danger-hover-text);
  --bs-btn-hover-bg: var(--ld-danger-bg);
  --bs-btn-hover-border-color: var(--ld-danger-hover-border);
  --bs-btn-active-color: var(--ld-danger-hover-text);
  --bs-btn-active-bg: var(--ld-danger-hover-bg);
  --bs-btn-active-border-color: var(--ld-danger-hover-border);
  --bs-btn-disabled-color: var(--ld-danger-text);
  --bs-btn-disabled-bg: transparent;
  --bs-btn-disabled-border-color: var(--ld-danger-border);
}

/* Lilac is a fill, not a text color: the text-primary utility maps to the AA-safe foreground */
.loondry-ui .text-primary { color: var(--ld-primary-foreground) !important; }

.loondry-ui .btn-link {
  --bs-btn-color: var(--ld-primary-foreground);
  --bs-btn-hover-color: var(--ld-primary-foreground);
  --bs-btn-active-color: var(--ld-primary-foreground);
  --bs-btn-padding-x: 0;
  --bs-btn-font-size: 14px;
  --bs-btn-border-radius: 0;
  min-height: auto;
  text-decoration: none;
}
.loondry-ui .btn-link:hover { text-decoration: underline; }
.loondry-ui .ld-icon-button { width: 40px; height: 40px; min-height: 40px; padding: 0; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; }
.loondry-ui .ld-icon-button-lg { width: 44px; height: 44px; min-height: 44px; }
.loondry-ui .btn:focus-visible { outline: none; box-shadow: var(--ld-focus-ring); }
.loondry-ui .btn:disabled,
.loondry-ui .btn.disabled { cursor: not-allowed; opacity: 0.45; }

/* ---------- Forms ---------- */
.loondry-ui .form-label {
  margin-bottom: 8px;
  color: var(--ld-neutral-700);
  font-size: 13px;
  font-weight: 500;
  line-height: 20px;
}

.loondry-ui .form-control,
.loondry-ui .form-select,
.loondry-ui .input-group-text {
  min-height: 44px;
  border-color: var(--ld-neutral-200);
  border-radius: var(--ld-radius-md);
  background-color: var(--ld-surface);
  color: var(--ld-neutral-950);
  font-family: var(--ld-font-sans);
  font-size: 15px;
  font-weight: 400;
  line-height: 20px;
}

.loondry-ui .input-group-text { background-color: var(--ld-neutral-50); color: var(--ld-neutral-500); }
.loondry-ui .form-control,
.loondry-ui .form-select { padding: 11px 14px; }
.loondry-ui .form-select { padding-right: 40px; }
/* Floating labels: keep Bootstrap's room for the floated label, the plain control padding would make it overlap the value */
.loondry-ui .form-floating > .form-control,
.loondry-ui .form-floating > .form-select { padding: 26px 14px 8px; }
.loondry-ui .form-floating > .form-select { padding-right: 40px; }
.loondry-ui .form-floating > label { padding: 1rem 14px; }
.loondry-ui .form-control::placeholder { color: var(--ld-neutral-400); opacity: 1; }
.loondry-ui .form-control:hover,
.loondry-ui .form-select:hover { border-color: var(--ld-neutral-300); }
.loondry-ui .form-control:focus,
.loondry-ui .form-select:focus {
  border-color: var(--ld-primary-border);
  background-color: var(--ld-surface);
  color: var(--ld-neutral-950);
  box-shadow: var(--ld-focus-ring);
}
.loondry-ui .form-control:disabled,
.loondry-ui .form-select:disabled { background-color: var(--ld-neutral-100); color: var(--ld-neutral-500); opacity: 1; }
.loondry-ui .form-text { margin-top: 6px; color: var(--ld-neutral-500); font-size: 13px; line-height: 20px; }
.loondry-ui .invalid-feedback { margin-top: 6px; color: var(--ld-danger-text); font-size: 13px; line-height: 20px; }
.loondry-ui .form-control.is-invalid,
.loondry-ui .form-select.is-invalid { border-color: var(--ld-danger-border); }
.loondry-ui textarea.form-control { min-height: 112px; resize: none; }
.loondry-ui .form-check-input { border-color: var(--ld-neutral-300); background-color: var(--ld-surface); }
.loondry-ui .form-check-input:checked { border-color: var(--ld-primary); background-color: var(--ld-primary); }
.loondry-ui .form-check-input:focus { border-color: var(--ld-primary-border); box-shadow: var(--ld-focus-ring); }
.loondry-ui .form-check-label { color: var(--ld-neutral-700); font-size: 14px; }

/* Buttons attached to a field (password eye, search, actions) take the control radius, not the pill; Bootstrap squares the inner corners */
.loondry-ui .input-group > .btn { --bs-btn-border-radius: var(--ld-radius-md); --bs-btn-padding-x: 16px; }

/* ---------- Search and compact filters ---------- */
.loondry-ui .ld-search { min-height: 44px; border-radius: var(--ld-radius-md); }
.loondry-ui .ld-filter.form-select,
.loondry-ui .ld-filter.form-control { min-height: 40px; padding-block: 9px; font-size: 13px; font-weight: 500; }
.loondry-ui .ld-filter-row .ld-filter.form-select { min-width: 160px; }
.loondry-ui .ld-filter-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

/* ---------- Cards and boxes ---------- */
.loondry-ui .card,
.loondry-ui .ld-card {
  --bs-card-bg: var(--ld-surface);
  --bs-card-border-color: var(--ld-card-border);
  --bs-card-border-radius: var(--ld-card-radius);
  --bs-card-inner-border-radius: calc(var(--ld-card-radius) - 1px);
  --bs-card-cap-bg: transparent;
  --bs-card-color: var(--ld-neutral-700);
  border: 1px solid var(--ld-card-border);
  border-radius: var(--ld-card-radius);
  background: var(--ld-surface);
  box-shadow: var(--ld-card-shadow);
}
.loondry-ui .card-header { padding: var(--ld-card-padding); border-bottom: 1px solid var(--ld-neutral-100); background: transparent; }
.loondry-ui .card-body { padding: var(--ld-card-padding); }
.loondry-ui .card-footer { padding: 0 var(--ld-card-padding) var(--ld-card-padding); border: 0; background: transparent; }
.loondry-ui .ld-subtitle { color: var(--ld-text-subtle); font-size: 14px; line-height: 20px; }
.loondry-ui .ld-card-interactive { transition: border-color var(--ld-transition), box-shadow var(--ld-transition); }
.loondry-ui .ld-card-interactive:hover { border-color: var(--ld-neutral-300); box-shadow: var(--ld-shadow-hover); }
/* Small read-only label for a person or tag: 13/500, neutral fill, pill. Controls with a value use the removable chip instead */
.loondry-ui .ld-chip { display: inline-flex; align-items: center; gap: 8px; max-width: 100%; padding: 6px 12px; border: 1px solid var(--ld-neutral-200); border-radius: var(--ld-radius-pill); background: var(--ld-neutral-50); color: var(--ld-neutral-700); font-size: 13px; font-weight: 500; line-height: 20px; }
/* Initials of a person or organization: light fill, never white on lilac (D9) */
.loondry-ui .ld-avatar { display: inline-flex; width: 56px; height: 56px; flex-shrink: 0; align-items: center; justify-content: center; border-radius: 50%; background: var(--ld-primary-light); color: var(--ld-primary-foreground); font-size: 22px; font-weight: 500; line-height: 1; }
.loondry-ui .ld-avatar-sm { width: 40px; height: 40px; font-size: 15px; }
.loondry-ui .min-w-0 { min-width: 0; }
/* Icon box colours: two classes, so they win over the base .ld-icon-box rule declared further down */
.loondry-ui .ld-icon-box.ld-icon-box-warning { background: var(--ld-warning-bg); color: var(--ld-warning-text); }
.loondry-ui .ld-icon-box.ld-icon-box-success { background: var(--ld-success-bg); color: var(--ld-success-text); }
.loondry-ui .ld-icon-box.ld-icon-box-danger { background: var(--ld-danger-bg); color: var(--ld-danger-text); }
.loondry-ui .ld-icon-box.badge-red { background: var(--ld-danger-bg); color: var(--ld-danger-text); }
.loondry-ui .ld-icon-box.badge-yellow { background: var(--ld-warning-bg); color: var(--ld-warning-text); }
.loondry-ui .ld-icon-box.badge-light-grey { background: var(--ld-neutral-100); color: var(--ld-neutral-500); }
.loondry-ui .ld-icon-box.ld-icon-box-muted { background: var(--ld-neutral-100); color: var(--ld-neutral-500); }
.loondry-ui .ld-kpi-card { padding: 24px; }
.loondry-ui .ld-kpi-label { color: var(--ld-neutral-600); font-size: 14px; font-weight: 400; line-height: 20px; }
.loondry-ui .ld-kpi-hint { margin-top: 8px; color: var(--ld-text-subtle); font-size: 14px; line-height: 20px; }
.loondry-ui .ld-icon-box { display: inline-flex; width: 40px; height: 40px; align-items: center; justify-content: center; border-radius: 12px; background: var(--ld-primary-light); color: var(--ld-primary-foreground); }

/* Heading block above a page section: use the SectionHeader component, never a bare h-tag */
.loondry-ui .ld-section-header { margin-bottom: 24px; flex-wrap: wrap; }
/* The title keeps at least 14rem: a wide action (button with a label) moves under it instead of squeezing it */
.loondry-ui .ld-section-header-text { flex: 1 1 14rem; min-width: 0; }
.loondry-ui .ld-section-header-eyebrow { color: var(--ld-neutral-500); font-size: 13px; line-height: 20px; }
.loondry-ui .ld-section-header-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; flex-shrink: 0; }

/* Nested panel: a bordered 16px box that groups a form block inside a page section or modal (no resting shadow) */
.loondry-ui .ld-panel { padding: 16px; border: 1px solid var(--ld-neutral-200); border-radius: var(--ld-radius-lg); background: var(--ld-surface); }
@media (min-width: 768px) { .loondry-ui .ld-panel { padding: 24px; } }
.loondry-ui .ld-panel-muted { background: var(--ld-neutral-50); }
/* Field label above a read-only value: small caps line like the table header */
.loondry-ui .ld-label { color: var(--ld-neutral-500); font-size: 11px; font-weight: 600; line-height: 16px; letter-spacing: 0.04em; text-transform: uppercase; }
/* Detail pages on a phone: label and value pairs in one panel (ld-facts), label left and amount right (ld-sum), lines as a bordered list (ld-line-list) */
.loondry-ui .ld-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 16px; margin: 0; }
.loondry-ui .ld-facts > div { min-width: 0; }
.loondry-ui .ld-facts .ld-fact-wide { grid-column: 1 / -1; }
.loondry-ui .ld-facts dd { margin: 2px 0 0; font-weight: 500; overflow-wrap: anywhere; }
.loondry-ui .ld-sum { display: flex; flex-direction: column; gap: 8px; margin: 0; }
.loondry-ui .ld-sum > div { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; }
.loondry-ui .ld-sum dt { color: var(--ld-neutral-500); font-weight: 400; }
.loondry-ui .ld-sum dd { margin: 0; font-weight: 500; white-space: nowrap; }
.loondry-ui .ld-sum .ld-sum-total { padding-top: 12px; border-top: 1px solid var(--ld-neutral-200); }
.loondry-ui .ld-sum .ld-sum-total dt { color: inherit; font-weight: 500; }
.loondry-ui .ld-sum .ld-sum-total dd { font-size: 17px; font-weight: 500; }
.loondry-ui .ld-line-list { display: flex; flex-direction: column; margin: 0; padding: 0; list-style: none; border: 1px solid var(--ld-neutral-200); border-radius: var(--ld-radius-lg); background: var(--ld-surface); overflow: hidden; }
.loondry-ui .ld-line-list > li { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 12px 16px; }
.loondry-ui .ld-line-list > li + li { border-top: 1px solid var(--ld-neutral-200); }
/* Single-column settings page */
.loondry-ui .ld-page-narrow { max-width: 960px; }
/* Two-column page (main content plus side panel) */
.loondry-ui .ld-page-wide { max-width: 1200px; }
/* Card holding an irreversible action */
.loondry-ui .card.ld-card-danger { border-color: var(--ld-danger-border); }
/* Address picker map inside a form: room for the autocomplete and the map */
.loondry-ui .ld-map-field { min-height: 25rem; }
/* Selectable option card (2 to 4 options with a title and a description). Selected: .active plus aria-pressed */
.loondry-ui .ld-option { display: flex; flex-direction: column; gap: 4px; width: 100%; padding: 16px; border: 1px solid var(--ld-neutral-200); border-radius: var(--ld-radius-lg); background: var(--ld-surface); color: var(--ld-neutral-900); text-align: left; transition: border-color var(--ld-transition), background-color var(--ld-transition); }
.loondry-ui .ld-option:hover:not(:disabled) { border-color: var(--ld-neutral-300); }
.loondry-ui .ld-option.active { border-color: var(--ld-primary-border); background: var(--ld-primary-light); }
.loondry-ui .ld-option:focus-visible { outline: none; box-shadow: var(--ld-focus-ring); }
.loondry-ui .ld-option:disabled { cursor: not-allowed; opacity: 0.45; }

/* ---------- Tabs and segmented controls ---------- */
.loondry-ui .nav-tabs { gap: 32px; border-bottom-color: var(--ld-neutral-200); }
.loondry-ui .nav-tabs .nav-link { margin-bottom: -1px; padding: 4px 4px 12px; border: 0; border-bottom: 2px solid transparent; border-radius: 0; color: var(--ld-neutral-500); font-size: 14px; font-weight: 500; }
.loondry-ui .nav-tabs .nav-link:hover { color: var(--ld-neutral-800); }
.loondry-ui .nav-tabs .nav-link.active { border-bottom-color: var(--ld-primary); background: transparent; color: var(--ld-neutral-900); font-weight: 600; }
.loondry-ui .ld-segmented { display: inline-flex; align-items: center; padding: 4px; border: 1px solid var(--ld-neutral-200); border-radius: 8px; background: var(--ld-surface); }
.loondry-ui .ld-segmented .btn { --bs-btn-padding-x: 12px; --bs-btn-font-size: 13px; --bs-btn-bg: transparent; --bs-btn-border-color: transparent; --bs-btn-color: var(--ld-neutral-500); --bs-btn-hover-bg: transparent; --bs-btn-hover-border-color: transparent; --bs-btn-hover-color: var(--ld-neutral-800); --bs-btn-active-bg: var(--ld-neutral-100); --bs-btn-active-border-color: transparent; --bs-btn-active-color: var(--ld-neutral-900); min-height: 32px; border-radius: 6px; }
/* a, span and label styled as buttons do not center their text like a button element does */
.loondry-ui :is(a, span, label).btn { display: inline-flex; align-items: center; justify-content: center; }
.loondry-ui .ld-segmented .btn.active { background: var(--ld-neutral-100); color: var(--ld-neutral-900); }

/* Special-case segmented switch that keeps its own shape (calendar view switch). Selected state is a light primary tint with AA text, never white on primary. */
.loondry-ui .ld-segmented-box { display: inline-flex; align-items: center; gap: 4px; padding: 4px; border: 1px solid var(--ld-neutral-200); border-radius: var(--ld-radius-md); background: var(--ld-surface); }
.loondry-ui .ld-segmented-box .btn { --bs-btn-padding-x: 0; --bs-btn-bg: transparent; --bs-btn-border-color: transparent; --bs-btn-color: var(--ld-neutral-500); --bs-btn-hover-bg: var(--ld-neutral-100); --bs-btn-hover-border-color: transparent; --bs-btn-hover-color: var(--ld-neutral-900); display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; min-height: 32px; border-radius: var(--ld-radius-sm); }
.loondry-ui .ld-segmented-box .btn.active,
.loondry-ui .ld-segmented-box .btn.active:hover { border-color: transparent; background: var(--ld-primary-light); color: var(--ld-primary-foreground); }

/* Control radius (12px) for boxes that group controls; Bootstrap rounded-* has no 12px step */
.loondry-ui .ld-rounded-control { border-radius: var(--ld-radius-md) !important; }

/* Pill tab: outlined pill, light primary selected state (text keeps AA contrast) */
.loondry-ui .ld-pill-tab.active,
.loondry-ui .ld-pill-tab.active:hover { border-color: var(--ld-primary-border); background: var(--ld-primary-light); color: var(--ld-primary-foreground); }

/* ---------- Badges and semantic states ---------- */
/* Poppins sits high in its line box: 1px more on top than at the bottom centers the text in the pill */
.loondry-ui .badge { padding: 5px 10px 3px; border-radius: var(--ld-radius-pill); font-size: 11px; font-weight: 500; line-height: 16px; }
/* Bootstrap lifts a badge by 1px inside a button: a badge looks the same wherever it is */
.loondry-ui .btn .badge { position: static; top: auto; }
.loondry-ui .ld-status-success { border: 1px solid var(--ld-success-border); background: var(--ld-success-bg); color: var(--ld-success-text); }
.loondry-ui .ld-status-warning { border: 1px solid var(--ld-warning-border); background: var(--ld-warning-bg); color: var(--ld-warning-text); }
.loondry-ui .ld-status-danger { border: 1px solid var(--ld-danger-border); background: var(--ld-danger-bg); color: var(--ld-danger-text); }
.loondry-ui .ld-calendar-highlight { border-color: var(--ld-warning-border) !important; background: var(--ld-warning-bg); }
.loondry-ui .ld-status-info { border: 1px solid var(--ld-info-border); background: var(--ld-info-bg); color: var(--ld-info-text); }

/* Task status badges (shared classes from statusBadges.css) remapped to the semantic palette, Host only */
.loondry-ui {
  --badge-completed-bg: var(--ld-success-bg); --badge-completed-color: var(--ld-success-text); --badge-completed-border: var(--ld-success-border);
  --badge-pending-bg: var(--ld-warning-bg); --badge-pending-color: var(--ld-warning-text); --badge-pending-border: var(--ld-warning-border);
  --badge-with-laundry-bg: var(--ld-warning-bg); --badge-with-laundry-color: var(--ld-warning-text); --badge-with-laundry-border: var(--ld-warning-border);
  --badge-not-assigned-bg: var(--ld-danger-bg); --badge-not-assigned-color: var(--ld-danger-text); --badge-not-assigned-border: var(--ld-danger-border);
  --badge-in-progress-bg: var(--ld-info-bg); --badge-in-progress-color: var(--ld-info-text); --badge-in-progress-border: var(--ld-info-border);
  --badge-reminder-bg: var(--ld-info-bg); --badge-reminder-color: var(--ld-info-text); --badge-reminder-border: var(--ld-info-border);
  --badge-assigned-bg: var(--ld-primary-light); --badge-assigned-color: var(--ld-primary-foreground); --badge-assigned-border: var(--ld-primary-border);
  --badge-canceled-bg: var(--ld-neutral-100); --badge-canceled-color: var(--ld-neutral-500); --badge-canceled-border: var(--ld-neutral-200);
}
.loondry-ui .badge.badge-light-green { --bs-badge-color: var(--ld-success-text); border: 1px solid var(--ld-success-border); background-color: var(--ld-success-bg); color: var(--ld-success-text); }
.loondry-ui .badge.badge-grey,
.loondry-ui .badge.badge-light-grey { --bs-badge-color: var(--ld-neutral-500); border: 1px solid var(--ld-neutral-200); background-color: var(--ld-neutral-100); color: var(--ld-neutral-500); }
.loondry-ui .badge.badge-purple { --bs-badge-color: var(--ld-primary-foreground); border: 1px solid var(--ld-primary-border); background-color: var(--ld-primary-light); color: var(--ld-primary-foreground); }

/* Primary tinted badge and highlighted surface (current item in a group) */
.loondry-ui .ld-badge-primary { background: var(--ld-primary-light); color: var(--ld-primary-foreground); }
.loondry-ui .ld-highlight { background: var(--ld-primary-light); border-color: var(--ld-primary-border) !important; }
.loondry-ui .ld-progress-neutral .progress-bar { background-color: var(--ld-neutral-300); }

/* ---------- Tables ---------- */
.loondry-ui .table {
  --bs-table-color: var(--ld-neutral-600);
  --bs-table-bg: transparent;
  --bs-table-border-color: var(--ld-neutral-100);
  --bs-table-hover-color: var(--ld-neutral-800);
  --bs-table-hover-bg: color-mix(in srgb, var(--ld-neutral-50) 65%, transparent);
  margin-bottom: 0;
  font-size: 13px;
  vertical-align: middle;
}
.loondry-ui .table > :not(caption) > * > * { padding: 14px 16px; border-bottom-color: var(--ld-neutral-100); }
.loondry-ui .table thead th { padding-block: 12px; background: var(--ld-neutral-100); color: var(--ld-neutral-500); font-size: 11px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap; }
.loondry-ui .ld-table-shell { overflow-x: auto; border: 1px solid var(--ld-neutral-200); border-radius: var(--ld-radius-lg); background: var(--ld-surface); }

/* Host list tables: the shared laundryTable.css look (bold header, shadow, lilac hover) brought to the table spec; scoped so Laundry and Cleaner keep theirs */
.loondry-ui .table-container { border: 1px solid var(--ld-neutral-200); border-radius: var(--ld-radius-lg); background: var(--ld-surface); box-shadow: none; }
.loondry-ui .table-container table.items-table[theme="loondry"] thead { background: transparent; }
.loondry-ui .table-container table.items-table[theme="loondry"] thead th { padding: 12px 16px; border-bottom: 1px solid var(--ld-neutral-100); background: var(--ld-neutral-100); color: var(--ld-neutral-500); font-size: 11px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap; }
.loondry-ui .table-container table.items-table[theme="loondry"] tbody td { padding: 14px 16px; border-bottom: 1px solid var(--ld-neutral-100); background: var(--ld-surface); color: var(--ld-neutral-600); font-size: 13px; }
.loondry-ui .table-container table.items-table[theme="loondry"] tbody tr:hover td { background: var(--ld-neutral-50); color: var(--ld-neutral-800); }
/* List table frame and base (ServerGrid and the other tables inside .table-container) */
.loondry-ui .table-container { overflow: hidden; }
.loondry-ui .table-container table.items-table { width: 100%; margin-bottom: 0; border-collapse: separate; border-spacing: 0; }
.loondry-ui .table-container table.items-table tbody tr { cursor: pointer; }
/* QuickGrid pads the page with empty rows: they stay hidden */
.loondry-ui .table-container table.items-table[theme="loondry"] tbody tr:has(td:empty) { display: none !important; }
.loondry-ui .table-container .dropdown-menu { z-index: 3000; }
/* Sortable headers are buttons: they take the header's font and color, and the primary color on hover */
.loondry-ui .table-container table.items-table thead th .col-title { font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit; }
.loondry-ui .table-container table.items-table thead th button.col-title:hover,
.loondry-ui .table-container table.items-table thead th button.col-title:focus-visible { color: var(--ld-primary-foreground); }
/* Sort chevron: dimmed on every sortable header, darker on the sorted one, flipped when descending */
.loondry-ui .table-container table.items-table th .sort-indicator {
  width: .7rem; height: .7rem; background-color: var(--ld-neutral-400); background-image: none !important;
  -webkit-mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 15l7-7 7 7"/></svg>');
  mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 15l7-7 7 7"/></svg>');
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: contain; mask-size: contain; transform: none !important; opacity: 1;
}
.loondry-ui .table-container table.items-table th.col-sort-asc .sort-indicator,
.loondry-ui .table-container table.items-table th.col-sort-desc .sort-indicator { background-color: var(--ld-primary-foreground); }
.loondry-ui .table-container table.items-table th.col-sort-desc .sort-indicator { transform: rotate(180deg) !important; }
/* Actions column: narrow and centered; its button is always visible (laundryTable.css used to show it on row hover only,
   which touch screens never get) and round on hover and while its menu is open */
.loondry-ui .table-container th.col-actions, .loondry-ui .table-container td.col-actions { width: 64px; min-width: 64px; max-width: 64px; text-align: center; padding-left: 0; padding-right: 0; }
.loondry-ui .table-container td.col-actions .dropdown { position: relative; }
.loondry-ui .table-container td.col-actions .btn:hover,
.loondry-ui .table-container td.col-actions .btn:focus-visible,
.loondry-ui .table-container td.col-actions .btn.show { border-radius: 50%; background-color: var(--ld-neutral-100); }
/* A narrow list column (status, numbers): as wide as its content, the spare width goes to the other columns */
.loondry-ui .table-container table.items-table .ld-col-fit { width: 1%; white-space: nowrap; }
/* List table footer (TablePager): the header's neutral strip at the bottom, rows per page left, range and arrows right */
.loondry-ui .ld-table-footer { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 16px; padding: 8px 16px; border-top: 1px solid var(--ld-neutral-200); border-radius: 0 0 var(--ld-radius-lg) var(--ld-radius-lg); background: var(--ld-neutral-100); color: var(--ld-neutral-500); font-size: 13px; font-weight: 500; line-height: 20px; }
.loondry-ui .ld-table-footer .form-select { width: auto; min-height: 32px; padding-block: 4px; border-radius: var(--ld-radius-sm); background-color: var(--ld-surface); font-size: 13px; font-weight: 500; }
.loondry-ui .ld-table-footer .ld-icon-button { width: 32px; height: 32px; min-height: 32px; color: var(--ld-neutral-600); }
.loondry-ui .ld-table-footer .ld-icon-button:disabled { border-color: transparent; background: transparent; color: var(--ld-neutral-300); }

/* Loading, empty and scroll helpers of the list tables (ServerGrid and the other pages), unprefixed as they were: pages override them with weaker selectors */
.loading-overlay { position: absolute; inset: 0; z-index: 20; display: flex; align-items: center; justify-content: center; background: var(--app-bg); backdrop-filter: blur(1px); }
.empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 360px; text-align: center; background-color: var(--app-bg); }
.hover-scroll-x { width: 100%; min-height: 200px; overflow-x: auto; overflow-y: visible; background-color: var(--app-bg-layout); }

/* Helpers moved as they were from laundryTable.css (kept unprefixed: pages override them with weaker selectors) */
.page-title { font-size: 1.75rem; font-weight: 600; color: var(--ld-neutral-900); }
.pointer-events-none { pointer-events: none; }

/* Details offcanvas width: full screen on phones, then a side panel that grows with the screen */
.offcanvas.details-offcanvas { --bs-offcanvas-width: 100vw; }
@media (min-width: 768px) { .offcanvas.details-offcanvas { --bs-offcanvas-width: 600px; } }
@media (min-width: 1200px) { .offcanvas.details-offcanvas { --bs-offcanvas-width: 544px; } }
@media (min-width: 1600px) { .offcanvas.details-offcanvas { --bs-offcanvas-width: 744px; } }
@media (min-width: 2000px) { .offcanvas.details-offcanvas { --bs-offcanvas-width: min(744px, 60vw); } }

/* ---------- Alerts and overlays ---------- */
.loondry-ui .alert { padding: 14px 16px; border-radius: var(--ld-radius-md); font-size: 13px; line-height: 20px; }
.loondry-ui .alert-warning { border-color: var(--ld-warning-border); background: var(--ld-warning-bg); color: var(--ld-warning-text); }
.loondry-ui .alert-danger { border-color: var(--ld-danger-border); background: var(--ld-danger-bg); color: var(--ld-danger-text); }
.loondry-ui .alert-info { border-color: var(--ld-info-border); background: var(--ld-info-bg); color: var(--ld-info-text); }
.loondry-ui .alert-success { border-color: var(--ld-success-border); background: var(--ld-success-bg); color: var(--ld-success-text); }
.loondry-ui .alert-secondary { border-color: var(--ld-neutral-200); background: var(--ld-neutral-50); color: var(--ld-neutral-700); }
.loondry-ui .dropdown-menu { --bs-dropdown-bg: var(--ld-surface); --bs-dropdown-border-color: var(--ld-neutral-200); --bs-dropdown-color: var(--ld-neutral-700); padding: 8px; border-radius: var(--ld-radius-md); box-shadow: var(--ld-shadow-dropdown); }
.loondry-ui .dropdown-item { min-height: 40px; padding: 9px 12px; border-radius: var(--ld-radius-sm); color: var(--ld-neutral-700); font-size: 13px; }
.loondry-ui .dropdown-item:hover,
.loondry-ui .dropdown-item:focus { background: var(--ld-neutral-100); color: var(--ld-neutral-900); }
.loondry-ui .dropdown-item.text-danger:hover,
.loondry-ui .dropdown-item.text-danger:focus { background: var(--ld-danger-bg); }
.loondry-ui .modal-content { --bs-modal-bg: var(--ld-surface); border: 1px solid var(--ld-neutral-200); border-radius: var(--ld-radius-lg); box-shadow: var(--ld-shadow-modal); }
.loondry-ui .modal-header { padding: 20px; border-bottom-color: var(--ld-neutral-100); }
.loondry-ui .modal-body { padding: 20px; }
.loondry-ui .modal-footer { padding: 16px 20px 20px; border-top: 0; }

@media (max-width: 767.98px) {
  .loondry-ui .form-control,
  .loondry-ui .form-select,
  .loondry-ui textarea.form-control { font-size: 16px; }
  .loondry-ui .ld-kpi-card { padding: 18px; }
  .loondry-ui .ld-filter-row > * { flex: 1 1 160px; }
}

/* ---------- Last opened item: stays marked after its popup closes (openedFocus.js) ---------- */
.loondry-ui .is-last-opened:not(tr) {
  outline: 2px solid var(--ld-primary-hover);
  outline-offset: 2px;
}

/* A table row only gets the side bar: no tint. */
.loondry-ui tr.is-last-opened > :first-child {
  box-shadow: inset 3px 0 0 var(--ld-primary-hover);
}

@media (prefers-reduced-motion: reduce) {
  .loondry-ui *,
  .loondry-ui *::before,
  .loondry-ui *::after { scroll-behavior: auto; transition-duration: 0.01ms; animation-duration: 0.01ms; animation-iteration-count: 1; }
}

@media (forced-colors: active) {
  .loondry-ui .btn:focus-visible,
  .loondry-ui .form-control:focus,
  .loondry-ui .form-select:focus { outline: 2px solid CanvasText; outline-offset: 2px; box-shadow: none; }
}

/* ---------- App building blocks (Loondry.Components/Shared/App): list row, empty state, skeleton, sheet, action bar, fab ---------- */
.loondry-ui .ld-list { overflow: hidden; border: 1px solid var(--ld-neutral-200); border-radius: var(--ld-radius-lg); background: var(--ld-surface); }
.loondry-ui .ld-list-row { display: flex; width: 100%; min-height: 56px; align-items: center; gap: 12px; padding: 12px 16px; border: 0; border-top: 1px solid var(--ld-neutral-100); background: transparent; color: var(--ld-neutral-700); text-align: left; text-decoration: none; }
.loondry-ui .ld-list > .ld-list-row:first-child { border-top: 0; }
.loondry-ui a.ld-list-row:hover,
.loondry-ui button.ld-list-row:hover:not(:disabled) { background: var(--ld-neutral-50); color: var(--ld-neutral-900); }
.loondry-ui a.ld-list-row:active,
.loondry-ui button.ld-list-row:active:not(:disabled) { background: var(--ld-neutral-100); }
.loondry-ui .ld-list-row:focus-visible { outline: none; box-shadow: inset var(--ld-focus-ring); }
.loondry-ui button.ld-list-row:disabled { cursor: not-allowed; opacity: 0.45; }
.loondry-ui .ld-list-row-text { display: flex; flex: 1 1 auto; flex-direction: column; }
.loondry-ui .ld-list-row-title { color: var(--ld-neutral-900); font-size: 14px; font-weight: 500; line-height: 20px; }
.loondry-ui .ld-list-row-subtitle { color: var(--ld-neutral-500); font-size: 13px; line-height: 20px; }
.loondry-ui .ld-list-row-chevron { color: var(--ld-neutral-400); font-size: 14px; } /* ui-audit-ignore: icon glyph */

.loondry-ui .ld-empty { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 32px 16px; text-align: center; }

.loondry-ui .ld-skeleton { display: flex; flex-direction: column; gap: 12px; }
.loondry-ui .ld-skeleton-block { display: block; border-radius: var(--ld-radius-sm); background: var(--ld-neutral-100); animation: ld-skeleton-pulse 1.4s ease-in-out infinite; }
.loondry-ui .ld-skeleton-line { height: 14px; width: 100%; }
.loondry-ui .ld-skeleton-line-short { width: 60%; }
.loondry-ui .ld-skeleton-icon { width: 40px; height: 40px; flex-shrink: 0; border-radius: var(--ld-radius-md); }
.loondry-ui .ld-skeleton-row { display: flex; align-items: center; gap: 12px; padding: 12px 16px; border: 1px solid var(--ld-neutral-200); border-radius: var(--ld-radius-lg); }
.loondry-ui .ld-skeleton-text { display: flex; flex: 1 1 auto; flex-direction: column; gap: 8px; }
.loondry-ui .ld-skeleton-card { display: flex; flex-direction: column; gap: 12px; padding: var(--ld-card-padding); border: 1px solid var(--ld-card-border); border-radius: var(--ld-card-radius); }
.loondry-ui .ld-skeleton-label { height: 11px; width: 35%; }
.loondry-ui .ld-skeleton-value { height: 22px; width: 50%; }
.loondry-ui .ld-skeleton-control { height: 40px; width: 100%; border-radius: var(--ld-radius-md); }
.loondry-ui .ld-skeleton-stat { display: flex; align-items: center; gap: 12px; padding: 16px; border: 1px solid var(--ld-card-border); border-radius: var(--ld-card-radius); }
.loondry-ui .ld-skeleton-panel { display: flex; flex-direction: column; gap: 16px; padding: 16px; border: 1px solid var(--ld-neutral-200); border-radius: var(--ld-radius-lg); }
.loondry-ui .ld-skeleton-pair,
.loondry-ui .ld-skeleton-field { display: flex; flex-direction: column; gap: 8px; }
.loondry-ui.maui-app .ld-skeleton-control { height: 44px; }
@keyframes ld-skeleton-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
@media (prefers-reduced-motion: reduce) { .loondry-ui .ld-skeleton-block { animation: none; } }

/* Live state (task in progress, sync running): one slow ring in the colour of the text around it (a status badge), the only pulse allowed in pages (D32) */
.loondry-ui .ld-live-pulse { position: relative; display: inline-block; width: 8px; height: 8px; flex-shrink: 0; border-radius: 50%; background: currentColor; }
.loondry-ui .ld-live-pulse::after { content: ""; position: absolute; inset: 0; border-radius: 50%; background: currentColor; animation: ld-live-ring 1.6s ease-out infinite; }
@keyframes ld-live-ring { from { opacity: 0.5; transform: scale(1); } to { opacity: 0; transform: scale(2.6); } }
@media (prefers-reduced-motion: reduce) { .loondry-ui .ld-live-pulse::after { animation: none; } }

/* Stat tiles of a home summary: icon box beside label, number and hint */
.loondry-ui .ld-stat-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.loondry-ui .ld-stat-tile { display: grid; min-width: 0; grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "icon label" "icon value" "icon hint"; align-items: center; column-gap: 12px; padding: 16px; border: 1px solid var(--ld-card-border); border-radius: var(--ld-card-radius); background: var(--ld-surface); }
.loondry-ui .ld-stat-tile .ld-icon-box { grid-area: icon; }
.loondry-ui .ld-stat-label { grid-area: label; min-width: 0; color: var(--ld-neutral-600); font-size: 13px; line-height: 20px; }
.loondry-ui .ld-stat-value { grid-area: value; min-width: 0; color: var(--ld-neutral-900); font-size: 22px; font-weight: 500; line-height: 28px; }
.loondry-ui .ld-stat-subtitle { grid-area: hint; min-width: 0; color: var(--ld-text-subtle); font-size: 13px; line-height: 20px; }
.loondry-ui .ld-icon-box.ld-icon-box-info { background: var(--ld-info-bg); color: var(--ld-info-text); }

/* Sheet: a centred dialog by default, docked to the bottom in the app. Above the layout like modals (1090 backdrop, 1100 panel) */
.loondry-ui .ld-sheet-backdrop { position: fixed; inset: 0; z-index: 1090; background: rgb(15 23 42 / 0.45); }
.loondry-ui .ld-sheet { position: fixed; top: 50%; left: 50%; z-index: 1100; display: flex; width: min(480px, calc(100vw - 32px)); max-height: calc(100dvh - 64px); flex-direction: column; transform: translate(-50%, -50%); border: 1px solid var(--ld-neutral-200); border-radius: var(--ld-radius-lg); background: var(--ld-surface); box-shadow: var(--ld-shadow-modal); }
.loondry-ui .ld-sheet-handle { display: none; }
.loondry-ui .ld-sheet-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 16px 0 20px; }
.loondry-ui .ld-sheet-body { min-height: 0; overflow-y: auto; padding: 16px 20px; }
.loondry-ui .ld-sheet-footer { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; padding: 0 20px 20px; }

/* Action bar and fab: in flow on the web, over the content in the app (see the app block) */
.loondry-ui .ld-action-bar { position: sticky; bottom: 0; z-index: 10; display: flex; gap: 8px; padding: 12px 0; background: var(--ld-surface); border-top: 1px solid var(--ld-neutral-200); }
.loondry-ui .ld-action-bar > .btn { flex: 1 1 0; }
.loondry-ui .ld-action-bar.flex-column > .btn { flex: 0 0 auto; }
.loondry-ui .ld-action-bar-spacer { display: none; }
/* From the sm width up the single action sits at the end of the bar instead of filling it (settings save) */
@media (min-width: 576px) {
  .loondry-ui .ld-action-bar-end { justify-content: flex-end; }
  .loondry-ui .ld-action-bar-end > .btn { flex: 0 0 auto; }
}
.loondry-ui .ld-fab { position: fixed; right: 24px; bottom: 24px; z-index: 10; display: inline-flex; width: var(--ld-app-fab-height, 56px); height: var(--ld-app-fab-height, 56px); align-items: center; justify-content: center; border: 0; border-radius: 50%; background: var(--ld-primary); color: var(--ld-primary-foreground); box-shadow: var(--ld-shadow-dropdown); font-size: 20px; text-decoration: none; } /* ui-audit-ignore: icon glyph */
.loondry-ui .ld-fab:hover { background: var(--ld-primary-hover); color: var(--ld-primary-foreground); }
.loondry-ui .ld-fab:focus-visible { outline: none; box-shadow: var(--ld-focus-ring), var(--ld-shadow-dropdown); }

/* ---------- MAUI app (body.maui-app): touch targets, safe area, app shell, bottom nav (D17, D21, D22) ---------- */
.loondry-ui.maui-app {
  --ld-app-gutter: 16px;
  --ld-app-bg: var(--app-bg-layout, var(--ld-neutral-50));
  --ld-safe-top: env(safe-area-inset-top, 0px);
  --ld-safe-bottom: env(safe-area-inset-bottom, 0px);
  --ld-app-nav-height: 76px;
  --ld-app-nav-total-height: calc(var(--ld-app-nav-height) + var(--ld-safe-bottom));
  --ld-app-nav-bg: var(--ld-surface);
  --ld-app-nav-border: var(--ld-neutral-200);
  --ld-app-nav-color: var(--ld-neutral-500);
  --ld-app-nav-active-color: var(--ld-primary-foreground);
  --ld-app-content-bottom: calc(var(--ld-app-nav-total-height) + var(--ld-app-gutter));
  /* Extra room a page keeps, on top of --ld-app-content-bottom, for a bar fixed over the bottom nav */
  --ld-app-floating-gap: 12px;
  --ld-app-fab-height: 56px;
  --ld-app-fab-reserve: calc(var(--ld-app-floating-gap) + var(--ld-app-fab-height) + var(--ld-app-gutter));
  --ld-app-action-bar-reserve: 96px;
  /* Motion (D32): the only durations and curves of the app; the web keeps --ld-transition */
  --ld-motion-fast: 120ms;
  --ld-motion-base: 200ms;
  --ld-motion-enter: 280ms;
  --ld-motion-exit: 200ms;
  --ld-ease-out: cubic-bezier(0.2, 0, 0, 1);
  --ld-ease-in: cubic-bezier(0.3, 0, 1, 1);
  -webkit-tap-highlight-color: transparent;
}

/* 44px touch targets on every control that the web theme keeps at 40px */
.loondry-ui.maui-app .btn-sm,
.loondry-ui.maui-app .ld-filter.form-select,
.loondry-ui.maui-app .ld-filter.form-control,
.loondry-ui.maui-app .list-group-item-action { min-height: 44px; }
.loondry-ui.maui-app .ld-icon-button { width: 44px; height: 44px; min-height: 44px; }
.loondry-ui.maui-app .dropdown-item { display: flex; align-items: center; min-height: 44px; }
.loondry-ui.maui-app .nav-tabs .nav-link { min-height: 44px; }

/* No hover state left behind after a tap */
@media (hover: none) {
  .loondry-ui.maui-app .btn:hover:not(:active):not(.active):not([aria-pressed="true"]):not(.btn-check:checked + .btn) { border-color: var(--bs-btn-border-color); background-color: var(--bs-btn-bg); color: var(--bs-btn-color); }
  .loondry-ui.maui-app .dropdown-item:hover:not(:active):not(.active) { background: transparent; color: var(--ld-neutral-700); }
}

/* Safe area: status bar band (iOS) and overlays clear the notch and the home indicator */
.loondry-ui.maui-app .status-bar-safe-area { background-color: var(--ld-app-bg); }
.loondry-ui.maui-app .modal { padding-top: var(--ld-safe-top); padding-bottom: var(--ld-safe-bottom); }
.loondry-ui.maui-app .offcanvas-bottom { padding-bottom: var(--ld-safe-bottom); }
.loondry-ui.maui-app .offcanvas-top { padding-top: var(--ld-safe-top); }
.loondry-ui.maui-app .offcanvas-start,
.loondry-ui.maui-app .offcanvas-end { padding-top: var(--ld-safe-top); padding-bottom: var(--ld-safe-bottom); }

/* A long modal scrolls inside the screen instead of growing past it (fullscreen modals already fill it) */
.loondry-ui.maui-app .modal-dialog:not([class*="modal-fullscreen"]) .modal-content { max-height: calc(100dvh - var(--ld-safe-top) - var(--ld-safe-bottom) - 1rem); overflow: hidden; }
.loondry-ui.maui-app .modal-dialog:not([class*="modal-fullscreen"]) .modal-body { min-height: 0; overflow-y: auto; }

/* The app top bar owns the back of a page title: the inline one stays only where no bar exists (the header marks it) */
.loondry-ui.maui-app .ld-header-back-in-bar { display: none !important; }
/* Page actions in the bar (AppBarActions) are icon buttons of 44px: the text label is for the web */
.loondry-ui.maui-app .app-top-bar-actions .btn { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; height: 44px; padding: 0 12px; }
.loondry-ui.maui-app .app-top-bar-actions .btn:has(.ld-bar-label) { width: 44px; padding: 0; }
.loondry-ui.maui-app .app-top-bar-actions .ld-bar-label { display: none !important; }
.loondry-ui.maui-app .app-top-bar-actions .btn > i { margin: 0 !important; }
/* The back and the secondary actions of the top bar are 44px squares with a thin border and 14px corners (D29) */
.loondry-ui.maui-app .app-top-bar-back,
.loondry-ui.maui-app .app-top-bar-actions .btn:not(.btn-primary):not(.btn-danger):not(.ld-sheet .btn) {
  --bs-btn-bg: var(--ld-surface);
  --bs-btn-hover-bg: var(--ld-surface);
  --bs-btn-active-bg: var(--ld-neutral-100);
  --bs-btn-border-color: var(--ld-neutral-300);
  --bs-btn-hover-border-color: var(--ld-neutral-300);
  --bs-btn-active-border-color: var(--ld-neutral-300);
  --bs-btn-color: var(--ld-neutral-900);
  --bs-btn-hover-color: var(--ld-neutral-900);
  --bs-btn-active-color: var(--ld-neutral-900);
  border: 1px solid var(--ld-neutral-300) !important;
  border-radius: 14px;
}
/* Back buttons in the app are tonal: a plain surface circle vanishes on the page background (white on near white, near black on near black) */
.loondry-ui.maui-app .ld-back-tonal,
.loondry-ui.maui-app .ld-section-header [data-testid="page-back"] {
  --bs-btn-color: var(--ld-primary-foreground);
  --bs-btn-bg: var(--ld-primary-light);
  --bs-btn-border-color: var(--ld-primary);
  --bs-btn-hover-color: var(--ld-primary-foreground);
  --bs-btn-hover-bg: var(--ld-primary-light);
  --bs-btn-hover-border-color: var(--ld-primary-hover);
  --bs-btn-active-color: var(--ld-primary-foreground);
  --bs-btn-active-bg: var(--ld-primary-border);
  --bs-btn-active-border-color: var(--ld-primary-hover);
}

/* Phone sizing (D27): the web theme sizes are for desktop screens */
.loondry-ui.maui-app { --ld-card-padding: 16px; }
.loondry-ui.maui-app h1,
.loondry-ui.maui-app .ld-h1 { font-size: 24px; line-height: 30px; }
.loondry-ui.maui-app .btn-lg { min-width: 0; }
.loondry-ui.maui-app .modal-header,
.loondry-ui.maui-app .modal-body { padding: 16px; }
.loondry-ui.maui-app .modal-footer { padding: 12px 16px 16px; }
/* Tabs scroll sideways instead of wrapping */
.loondry-ui.maui-app .nav-tabs { flex-wrap: nowrap; gap: 24px; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; }
.loondry-ui.maui-app .nav-tabs::-webkit-scrollbar { display: none; }
.loondry-ui.maui-app .nav-tabs .nav-link { white-space: nowrap; }
/* A wide list table scrolls inside its frame */
.loondry-ui.maui-app .table-container { overflow-x: auto; }

/* Touch feedback: a pressed card, option or row answers at once (hover does not exist on touch) */
.loondry-ui.maui-app :is(.ld-card-interactive, .ld-option:not(:disabled), a.card, a.ld-card, .list-group-item-action):active { transform: scale(0.985); transition: transform var(--ld-motion-fast) var(--ld-ease-out); }
.loondry-ui.maui-app .list-group-item-action:active { background: var(--ld-neutral-100); }
.loondry-ui.maui-app :is(.btn, .nav-link, .list-group-item-action, .bottom-nav) { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }

/* Native feel: a long press selects nothing and shows no link preview / URL. Fields and anything marked
   .ld-selectable (addresses, codes the user may copy) keep selection. */
.loondry-ui.maui-app { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; touch-action: manipulation; }
.loondry-ui.maui-app :is(a, img) { -webkit-touch-callout: none; -webkit-user-drag: none; }
.loondry-ui.maui-app :is(input, textarea, [contenteditable="true"], .ld-selectable, .ld-selectable *) { -webkit-user-select: text; user-select: text; }

/* Hover rules that would stick after a tap are reset on touch screens (the .btn and .dropdown-item resets are above) */
@media (hover: none) {
  .loondry-ui.maui-app .ld-card-interactive:hover { border-color: var(--ld-card-border); box-shadow: none; }
  .loondry-ui.maui-app .ld-option:hover:not(.active) { border-color: var(--ld-neutral-200); }
  .loondry-ui.maui-app .nav-tabs .nav-link:hover:not(.active) { color: var(--ld-neutral-500); }
  .loondry-ui.maui-app .form-control:hover:not(:focus),
  .loondry-ui.maui-app .form-select:hover:not(:focus) { border-color: var(--ld-neutral-200); }
  .loondry-ui.maui-app .btn-link:hover { text-decoration: none; }
  .loondry-ui.maui-app .table-container table.items-table[theme="loondry"] tbody tr:hover td { background: var(--ld-surface); color: var(--ld-neutral-600); }
  .loondry-ui.maui-app .table-container td.col-actions .btn:hover:not(.show):not(:focus-visible) { background-color: transparent; }
}

@media (prefers-reduced-motion: reduce) {
  .loondry-ui.maui-app :is(.ld-card-interactive, .ld-option, a.card, a.ld-card, .list-group-item-action):active { transform: none; }
}

/* Bottom toasts clear the bottom nav, like the WebApp mobile bar does (app.css of the WebApp) */
.loondry-ui.maui-app:has(.bottom-nav) :is(.tabiot-toast-bottom-right, .tabiot-toast-bottom-left, .tabiot-toast-bottom-center).tabiot-toast-container { bottom: calc(var(--ld-app-nav-total-height) + 8px); }

/* Sheet docked to the bottom, over the bottom nav */
.loondry-ui.maui-app .ld-sheet { top: auto; right: 0; bottom: 0; left: 0; width: 100%; max-height: calc(100dvh - var(--ld-safe-top) - 48px); transform: none; border-bottom: 0; border-radius: var(--ld-radius-lg) var(--ld-radius-lg) 0 0; padding-bottom: var(--ld-safe-bottom); animation: ld-sheet-up var(--ld-motion-enter) var(--ld-ease-out); }
.loondry-ui.maui-app .ld-sheet-handle { display: block; width: 40px; height: 4px; margin: 8px auto 0; border-radius: var(--ld-radius-pill); background: var(--ld-neutral-300); }
.loondry-ui.maui-app .ld-sheet-header { padding: 8px 8px 0 16px; }
.loondry-ui.maui-app .ld-sheet-body { padding: 8px 16px 16px; }
.loondry-ui.maui-app .ld-sheet-footer { flex-direction: column-reverse; padding: 0 16px 16px; }
.loondry-ui.maui-app .ld-sheet-footer > .btn { width: 100%; }
@keyframes ld-sheet-up { from { transform: translateY(100%); } to { transform: none; } }

/* App dialog (AppDialog, D31): the kinds on top of the sheet. Leaving slides down and the scrim fades. */
.loondry-ui .ld-dialog-footer { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
.loondry-ui.maui-app .ld-sheet:focus { outline: none; }
.loondry-ui.maui-app .ld-sheet-grip { flex-shrink: 0; touch-action: none; }
.loondry-ui.maui-app .ld-sheet-backdrop { animation: ld-scrim-in var(--ld-motion-enter) linear both; }
.loondry-ui.maui-app .ld-sheet-backdrop.is-closing { animation: ld-scrim-out var(--ld-motion-exit) linear both; }
/* AppDialog waits --ld-motion-exit (200ms, ExitDuration) before it removes the markup */
.loondry-ui.maui-app .ld-sheet.is-closing { animation: ld-sheet-down var(--ld-motion-exit) var(--ld-ease-in) both; }
.loondry-ui.maui-app .ld-dialog-sheet .ld-sheet-footer,
.loondry-ui.maui-app .ld-dialog-detail .ld-sheet-footer { padding-top: 12px; border-top: 1px solid var(--ld-neutral-100); }
/* Actions are buttons, same gutter as the Cancel in the footer */
.loondry-ui.maui-app .ld-dialog-actions .ld-sheet-body { padding: 0 16px 8px; }
.loondry-ui.maui-app .ld-dialog-actions .ld-list { display: flex; flex-direction: column; gap: 8px; border: 0; border-radius: 0; background: transparent; }
/* Header of a former offcanvas shown in a sheet: stays on top while the body scrolls */
.loondry-ui.maui-app .ld-app-offcanvas-head { position: sticky; top: -8px; z-index: 1; margin: 0 -16px 12px; padding: 12px 16px 12px; border-bottom: 1px solid var(--ld-neutral-100); background: var(--ld-surface); }
/* Team member sheet: the summary header scrolls with the content, to leave room to it at half height */
.loondry-ui.maui-app .ld-sheet.member-drawer .ld-app-offcanvas-head { position: static; }
.loondry-ui.maui-app .ld-dialog-detail { max-height: none; transition: height var(--ld-motion-enter) var(--ld-ease-out); }
.loondry-ui.maui-app .ld-dialog-detail.is-half { height: 55dvh; }
.loondry-ui.maui-app .ld-dialog-detail.is-full { height: calc(100dvh - var(--ld-safe-top) - 48px); }
.loondry-ui.maui-app .ld-dialog-detail .ld-sheet-body { flex: 1 1 auto; }
/* Full screen: a page of its own over everything, bar with the close on the left */
.loondry-ui.maui-app .ld-dialog-full { top: 0; height: 100dvh; max-height: none; border: 0; border-radius: 0; padding-top: var(--ld-safe-top); background: var(--ld-app-bg); }
.loondry-ui.maui-app .ld-dialog-full .ld-sheet-body { flex: 1 1 auto; padding: 0 16px 16px; overscroll-behavior: contain; }
.loondry-ui.maui-app .ld-dialog-full .ld-sheet-footer { flex-direction: row; padding: 12px 16px 16px; border-top: 1px solid var(--ld-neutral-200); background: var(--ld-surface); }
.loondry-ui.maui-app .ld-dialog-full .ld-sheet-footer > .btn { flex: 1 1 0; width: auto; }
.loondry-ui.maui-app .ld-dialog-bar { position: sticky; top: 0; z-index: 1; display: flex; align-items: center; gap: 4px; min-height: 56px; margin: 0 -16px 8px; padding: 0 4px; border-bottom: 1px solid var(--ld-neutral-200); background: var(--ld-app-bg); }
.loondry-ui.maui-app .ld-dialog-full > .ld-dialog-bar { margin: 0; }
/* The laundry settings columns scroll inside the web layout; in the app the page scrolls as a whole */
.loondry-ui.maui-app .settings-fill,
.loondry-ui.maui-app .settings-scroll-column { height: auto !important; overflow-y: visible !important; }
/* A full screen dialog scrolls as a whole: the capped inner list of a modal (assignments) takes the height of its content */
.loondry-ui.maui-app .ld-dialog-full .pick-list { max-height: none; overflow: visible; }
.loondry-ui.maui-app .ld-dialog-bar .ld-icon-button { --bs-btn-bg: transparent; --bs-btn-hover-bg: transparent; }
.loondry-ui.maui-app .ld-dialog-bar-title { flex: 1 1 auto; min-width: 0; margin: 0; color: var(--ld-neutral-900); font-size: 17px; font-weight: 500; line-height: 24px; }
html.keyboard-open .loondry-ui.maui-app .ld-dialog-full { height: auto; max-height: none; }
/* The discard question sits over its dialog */
.loondry-ui.maui-app .ld-sheet-backdrop.ld-dialog-nested { z-index: 1110; }
.loondry-ui.maui-app .ld-sheet.ld-dialog-nested { z-index: 1120; }
/* A sheet opened from the top bar (the page actions menu) lives inside it: the bar rises over the page's fixed bars while it is open */
.loondry-ui.maui-app .app-top-bar:has(.ld-sheet) { z-index: 1100; }
@keyframes ld-sheet-down { from { transform: none; } to { transform: translateY(100%); } }
@keyframes ld-scrim-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes ld-scrim-out { from { opacity: 1; } to { opacity: 0; } }
/* Reduced motion: nothing slides, overlays and pages fade (these beat the global 0.01ms rule by specificity) */
@media (prefers-reduced-motion: reduce) {
  .loondry-ui.maui-app .ld-sheet { animation: ld-scrim-in var(--ld-motion-base) linear both; }
  .loondry-ui.maui-app .ld-sheet.is-closing { animation: ld-scrim-out var(--ld-motion-exit) linear both; }
  .loondry-ui.maui-app .ld-dialog-detail { transition: none; }
}

/* Action bar and fab sit above the bottom nav (when there is one) and inside the gutter */
.loondry-ui.maui-app .ld-action-bar { position: fixed; right: 0; bottom: var(--ld-safe-bottom); left: 0; padding: 12px var(--ld-app-gutter); border-top: 1px solid var(--ld-neutral-200); }
.loondry-ui.maui-app:has(.bottom-nav) .ld-action-bar { bottom: var(--ld-app-nav-total-height); }
.loondry-ui.maui-app .ld-action-bar-spacer { display: block; height: var(--ld-app-action-bar-reserve); }
.loondry-ui.maui-app .ld-fab { right: var(--ld-app-gutter); bottom: calc(var(--ld-safe-bottom) + var(--ld-app-gutter)); }
.loondry-ui.maui-app:has(.bottom-nav) .ld-fab { bottom: calc(var(--ld-app-nav-total-height) + var(--ld-app-floating-gap)); }

/* On-screen keyboard (keyboard.js sets html.keyboard-open and --ld-keyboard-height): the bottom nav gets out of the way and
   everything pinned to the bottom clears the keyboard when it overlays the page */
.loondry-ui.maui-app .app-shell { height: calc(100dvh - var(--ld-keyboard-height, 0px)); }
html.keyboard-open .loondry-ui.maui-app .bottom-nav { display: none; }
html.keyboard-open .loondry-ui.maui-app .app-content.has-bottom-nav { padding-bottom: calc(var(--ld-app-gutter) + var(--ld-safe-bottom)); }
html.keyboard-open .loondry-ui.maui-app .ld-action-bar { bottom: var(--ld-keyboard-height, 0px); }
html.keyboard-open .loondry-ui.maui-app .ld-fab { bottom: calc(var(--ld-keyboard-height, 0px) + var(--ld-app-gutter)); }
html.keyboard-open .loondry-ui.maui-app .ld-sheet { bottom: var(--ld-keyboard-height, 0px); padding-bottom: 0; max-height: calc(100dvh - var(--ld-keyboard-height, 0px) - var(--ld-safe-top) - 24px); }

/* Page transitions (D32): navDirection.js marks the new page (the shell recreates .app-content on every navigation).
   Forward slides in from the right, back from the left, a bottom nav tab fades. Only on entry: nothing leaves. */
.loondry-ui.maui-app .app-content.ld-enter-push { animation: ld-page-push var(--ld-motion-enter) var(--ld-ease-out) backwards; }
.loondry-ui.maui-app .app-content.ld-enter-pop { animation: ld-page-pop var(--ld-motion-enter) var(--ld-ease-out) backwards; }
.loondry-ui.maui-app .app-content.ld-enter-tab { animation: ld-page-fade var(--ld-motion-base) var(--ld-ease-out) backwards; }
@keyframes ld-page-push { from { opacity: 0; transform: translateX(24px); } to { opacity: 1; transform: none; } }
@keyframes ld-page-pop { from { opacity: 0; transform: translateX(-24px); } to { opacity: 1; transform: none; } }
@keyframes ld-page-fade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .loondry-ui.maui-app .app-content:is(.ld-enter-push, .ld-enter-pop, .ld-enter-tab) { animation: ld-page-fade var(--ld-motion-base) linear backwards; }
}

/* Pull to refresh (pullRefresh.js draws the indicator): a round chip with a ring that spins while the page reloads */
.ld-ptr { position: fixed; top: calc(var(--ld-safe-top, 0px) + 8px); left: 50%; z-index: 30; display: flex; width: 40px; height: 40px; align-items: center; justify-content: center; border: 1px solid var(--ld-neutral-200); border-radius: 50%; background: var(--ld-surface); opacity: 0; transform: translate(-50%, -48px); pointer-events: none; }
.ld-ptr-ring { width: 20px; height: 20px; border: 3px solid var(--ld-neutral-200); border-top-color: var(--ld-primary-foreground); border-radius: 50%; }
.ld-ptr.is-loading { transition: transform var(--ld-motion-base, 200ms) var(--ld-ease-out, ease), opacity var(--ld-motion-base, 200ms) linear; }
.ld-ptr.is-loading .ld-ptr-ring { animation: ld-ptr-spin 0.8s linear infinite; }
@keyframes ld-ptr-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .ld-ptr.is-loading .ld-ptr-ring { animation-duration: 2s; } }

/* Shared pages wrap themselves in .container: in the app the shell already gives the 16px gutter */
.loondry-ui.maui-app .app-content .container { max-width: none; padding-left: 0; padding-right: 0; }

/* Detail pages (charge documents): the page stack already spaces its blocks, so a header adds no margin of its own, and section titles are card titles */
.loondry-ui.maui-app .ld-detail { gap: 16px !important; }
.loondry-ui.maui-app .ld-detail > .ld-section-header { margin-bottom: 0; }
.loondry-ui.maui-app .ld-detail section > .ld-section-header { margin-bottom: 12px; }
.loondry-ui.maui-app .ld-detail section > .ld-section-header .ld-h2 { font-size: 17px; line-height: 24px; }
