.modal-overlay {
  position: fixed; inset: 0;
  background: var(--overlay-modal);
  display: flex; align-items: center; justify-content: center;
  z-index: 100;
}
.modal {
  background: var(--surface-raised);
  border-radius: var(--r-sm);
  box-shadow: 0 12px 32px var(--shadow-modal);
  padding: 22px;
  width: min(520px, 92vw);
  max-height: 88vh;
  overflow: auto;
}
.modal h2 {
  font-size: var(--fs-lg);
  margin-bottom: 14px;
}
.modal label {
  display: block;
  margin: 10px 0;
}
.modal label > span {
  display: block;
  font-size: var(--fs-sm);
  color: var(--text-caption);
  margin-bottom: 3px;
}
.modal input,
.modal select,
.modal textarea {
  width: 100%;
  padding: 7px 9px;
  border: 1px solid var(--border-input);
  border-radius: var(--r-xs);
  font: inherit;
  background: var(--surface-raised);
  color: var(--text);
}
.modal textarea {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  resize: vertical;
}
.modal input[readonly] {
  background: var(--surface-muted);
  color: var(--text-muted);
}
/* Display-only field (a value computed from a data source) — looks like a disabled input. */
.modal .modal-static {
  padding: 7px 9px;
  border: 1px solid var(--border-input);
  border-radius: var(--r-xs);
  background: var(--surface-muted);
  color: var(--text-secondary);
  min-height: 34px;
}
/* inline checkbox + caption, overriding the generic `.modal input { width: 100% }` */
.modal label.modal-checkbox {
  display: flex;
  align-items: center;
  gap: 8px;
}
.modal label.modal-checkbox > span {
  display: inline;
  margin: 0;
  color: inherit;
  font-size: inherit;
}
.modal label.modal-checkbox > input[type="checkbox"] {
  width: auto;
  margin: 0;
  flex: 0 0 auto;
}
.field-hint {
  display: block;
  font-size: var(--fs-xs);
  color: var(--text-muted);
  margin-top: 3px;
}
/* Accent picker: the label, the preset swatches, and the palette button all sit on ONE inline row
   (only dropping the swatches under the label on a very narrow modal). The high-specificity selectors
   beat the generic `.modal label > span { display: block }`, which would otherwise stack the field span
   (and the palette under the swatches). */
.modal label.accent-label { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px; margin: 12px 0; }
.modal label.accent-label .accent-field { display: flex; align-items: center; gap: 10px; margin: 0; }
.modal label.accent-label .accent-swatches { display: flex; gap: 10px; margin: 0; }
.accent-sw, .accent-custom-btn {
  width: 24px; height: 24px; padding: 0; border-radius: 50%; border: none;
  background: var(--surface-muted); color: var(--text-muted); cursor: pointer;
  display: grid; place-items: center; font-size: 13px; line-height: 1;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
  transition: transform 0.12s ease;
}
.accent-sw:hover, .accent-custom-btn:hover { transform: scale(1.12); }
.accent-custom-btn { margin-left: 4px; }
.accent-custom-btn .lucide { width: 14px; height: 14px; }
/* Selected ring sits OUTSIDE the swatch (offset outline), so it never eats the colour or its neighbours. */
.accent-sw.sel, .accent-custom-btn.sel { outline: 2px solid var(--text-strong); outline-offset: 2px; }
fieldset.param-group {
  margin: 12px 0;
  padding: 10px 12px 4px;
  border: 1px solid var(--border-list);
  border-radius: var(--r-sm);
}
fieldset.param-group legend {
  font-size: var(--fs-sm);
  color: var(--text-caption);
  padding: 0 4px;
}
fieldset.param-group label > span {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-mono);
}

.modal.job-links { width: min(560px, 94vw); }
.modal.job-links section { margin: 14px 0; }
.modal.job-links section > h3 {
  font-size: var(--fs-sm);
  color: var(--text-caption);
  margin-bottom: 6px;
}
.job-links-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border-list);
  border-radius: var(--r-sm);
}
.job-links-list li { border-bottom: 1px solid var(--list-divider); }
.job-links-list li:last-child { border-bottom: none; }
.job-link-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 10px;
}
.job-link-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.job-link-on {
  flex: 0 0 auto;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.job-link-actions {
  flex: 0 0 auto;
  display: inline-flex;
  gap: 4px;
}
.job-link-row.job-link-paused .job-link-name,
.job-link-row.job-link-paused .job-link-on { opacity: 0.5; }
.job-link-empty {
  padding: 8px 10px;
  font-size: var(--fs-sm);
}
.job-links-add-row {
  display: flex;
  align-items: flex-end;
  gap: 10px;
}
.job-links-add-row label { flex: 1 1 auto; margin: 0; }
/* Inherits the unified primary recipe (button.primary); only the inline icon+label layout is local. */
.job-links-add-row .job-links-pick-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.job-links-add-row .job-links-pick-btn .lucide { width: 15px; height: 15px; stroke-width: 2.75; }

.user-groups-list {
  list-style: none;
  margin: 0 0 8px;
  padding: 0;
}
.user-group-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 2px;
}
.user-group-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-group-empty { padding: 4px 2px; }
.user-groups-add {
  display: flex;
  align-items: center;
  gap: 8px;
}
.user-groups-add .user-groups-pick { flex: 1 1 auto; }
.user-groups-add .user-groups-add-btn {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.user-groups-add .user-groups-add-btn .lucide { width: 15px; height: 15px; }

/* sticky category badge as a group header in the job chooser, kept visible while scrolling */
.job-pick-list .job-pick-cat {
  position: sticky;
  top: 0;
  padding: 6px 10px 5px;
  background: var(--surface-raised);
  border-bottom: 1px solid var(--list-divider);
}

/* relative wrapper so the map-icon button can sit absolutely inside the bbox field */
.modal-bbox-wrap {
  position: relative;
  display: block;
}
.modal-bbox-wrap input {
  /* right padding clears the icon button */
  width: 100%;
  padding-right: 34px;
}
.modal-bbox-wrap .modal-bbox-pick {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: var(--r-xs);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.modal-bbox-wrap .modal-bbox-pick:hover {
  background: var(--accent-soft-bg);
  color: var(--accent-hover);
}
.modal-bbox-wrap .modal-bbox-pick .lucide { width: 16px; height: 16px; }

/* Data-source field: a summary line + a "Choose…" button that opens the source picker. */
.modal-databind .modal-databind-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
}
.modal-databind .modal-databind-summary {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
}
.modal-databind .modal-databind-pick {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 12px;
  background: var(--surface);
  border: 1px solid var(--border-input);
  border-radius: var(--r-sm);
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
}
.modal-databind .modal-databind-pick:hover {
  border-color: var(--accent);
  color: var(--text-strong);
}
.modal-databind .modal-databind-pick .lucide { width: 15px; height: 15px; }

/* Icon field: a preview + name button that opens the searchable icon picker. */
.modal-iconpick .modal-iconpick-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  height: 38px;
  padding: 0 12px;
  background: var(--surface-raised);
  border: 1px solid var(--border-input);
  border-radius: var(--r-xs);
  color: var(--text);
  cursor: pointer;
  text-align: left;
}
.modal-iconpick .modal-iconpick-btn:hover { border-color: var(--accent); color: var(--text-strong); }
.modal-iconpick .modal-iconpick-preview { display: inline-flex; }
.modal-iconpick .modal-iconpick-preview .lucide { width: 18px; height: 18px; }
.modal-iconpick .modal-iconpick-name { font-size: var(--fs-sm); color: var(--text-secondary); }

/* Icon picker: a category accordion (or a name/tag search) over all Lucide icons, SVGs rendered lazily.
   Opens above a configure modal, so it sits one layer up rather than relying on DOM order. */
.icon-picker-overlay { z-index: 101; }
.icon-picker { width: min(620px, 94vw); display: flex; flex-direction: column; padding: 16px; }
.icon-picker-head { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
.icon-picker-head .icon-picker-search { flex: 1; }
.icon-picker-close {
  flex: none; width: 30px; height: 30px;
  border: 1px solid var(--border-input); border-radius: var(--r-xs);
  background: var(--surface); color: var(--text-secondary); cursor: pointer;
}
.icon-picker-close:hover { color: var(--text-strong); border-color: var(--accent); }
/* Scroll containers — the accordion and the flat results pane each scroll on their own. */
.icon-picker-cats, .icon-picker-results { max-height: 58vh; overflow-y: auto; padding: 2px; }
.icon-picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(46px, 1fr));
  gap: 6px;
}
.icon-cat { border-bottom: 1px solid var(--border); }
.icon-cat > summary {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 4px; cursor: pointer;
  font-size: var(--fs-sm); color: var(--text-strong);
  list-style: none;
}
.icon-cat > summary::-webkit-details-marker { display: none; }
.icon-cat > summary::before {
  content: "›"; display: inline-block; width: 12px;
  color: var(--text-muted); transition: transform .12s;
}
.icon-cat[open] > summary::before { transform: rotate(90deg); }
.icon-cat-name { flex: 1; }
.icon-cat-n { font-size: var(--fs-xs); color: var(--text-muted); }
.icon-cat > .icon-picker-grid { padding: 4px 2px 12px; }
.icon-picker .icon-cell {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 1; padding: 0;
  background: var(--surface); border: 1px solid var(--border-input);
  border-radius: var(--r-xs); color: var(--text-secondary); cursor: pointer;
  /* Skip layout/paint of off-screen cells — the browser only works on what's actually visible. */
  content-visibility: auto;
  contain-intrinsic-size: 46px;
}
.icon-picker .icon-cell:hover { color: var(--text-strong); border-color: var(--accent); background: var(--accent-soft-bg); }
.icon-picker .icon-cell.sel { border-color: var(--accent); color: var(--accent); outline: 1px solid var(--accent); }
.icon-picker .icon-cell .lucide { width: 20px; height: 20px; }
.icon-picker-empty { grid-column: 1 / -1; padding: 28px 8px; text-align: center; color: var(--text-muted); font-size: var(--fs-sm); }
.icon-picker-foot { margin-top: 10px; font-size: var(--fs-sm); color: var(--text-muted); text-align: right; }

/* Source picker (dashboards) — cascading layer → asset → aggregate → region + live preview. */
.dh-sp { width: min(520px, 92vw); }
.dh-sp .dh-sp-modes {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 12px;
}
.dh-sp .dh-sp-modes label {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}
/* Generic modal styling stretches inputs to 100% — keep the radio its natural size so its label
   sits beside it instead of being pushed to the far edge. */
.dh-sp .dh-sp-modes input[type="radio"] {
  width: auto;
  flex: 0 0 auto;
  margin: 0;
}
.dh-sp .dh-sp-row {
  display: grid;
  grid-template-columns: 120px 1fr;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}
.dh-sp .dh-sp-row > span { color: var(--text-secondary); font-size: var(--fs-sm); }
.dh-sp .dh-sp-row select { width: 100%; }
.dh-sp .dh-sp-preview {
  margin-top: 4px;
  padding: 10px 12px;
  background: var(--surface-sunken, var(--surface));
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-secondary);
}
.dh-sp .dh-sp-preview strong { margin-left: 8px; color: var(--text-strong); font-size: var(--fs-lg); }

/* Table editor — breakdown level + a list of named data columns. */
.dh-te { width: min(560px, 94vw); }
.dh-me { width: min(620px, 94vw); }
.dh-te .dh-te-colhead { margin: 12px 0 6px; font-size: var(--fs-sm); color: var(--text-secondary); }
/* One control row per column/layer: the name stretches to fill, pushing the fixed controls to the
   right edge; the source summary sits as a small line beneath. */
.dh-te .dh-te-col {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 8px;
}
.dh-te .dh-te-row1 { display: flex; align-items: center; gap: 8px; }
.dh-te .dh-te-name { flex: 1 1 auto; min-width: 0; width: auto; }
/* Space between layers, no extra backing — a generous gap separates one layer's row from the next. */
.dh-me .dh-te-col { margin-bottom: 22px; }
/* Row selects must override the modal's blanket select{width:100%}. */
.dh-te .dh-te-align, .dh-me .dh-me-cmap { flex: 0 0 auto; width: auto; min-width: 96px; height: 30px; padding: 0 8px;
  background: var(--surface); color: var(--text); border: 1px solid var(--border-input); border-radius: var(--r-sm);
  font-size: var(--fs-sm); cursor: pointer; }
.dh-te .dh-te-src {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}
.dh-te .dh-te-pick {
  flex: 0 0 auto;
  height: 30px;
  padding: 0 10px;
  background: var(--surface);
  border: 1px solid var(--border-input);
  border-radius: var(--r-sm);
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
}
.dh-te .dh-te-pick:hover { border-color: var(--accent); color: var(--text-strong); }
.dh-te .dh-te-rm {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  background: transparent;
  border: 1px solid var(--border-input);
  border-radius: var(--r-sm);
  color: var(--text-muted);
  cursor: pointer;
}
.dh-te .dh-te-rm:hover { color: var(--danger); border-color: var(--danger-border); }
.dh-te .dh-te-add {
  margin-top: 4px;
  height: 32px;
  padding: 0 12px;
  background: var(--surface);
  border: 1px dashed var(--border-input);
  border-radius: var(--r-sm);
  color: var(--text-secondary);
  cursor: pointer;
}
.dh-te .dh-te-add:hover { border-color: var(--accent); color: var(--text-strong); }

.bbox-picker-modal {
  width: min(900px, 90vw);
  max-width: 90vw;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.bbox-picker-header h2 {
  margin: 0 0 4px;
  font-size: var(--fs-lg);
}
.bbox-picker-header .hint {
  font-size: var(--fs-sm);
}
.bbox-picker-header kbd {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  padding: 1px 6px;
  background: var(--accent-soft-bg);
  border: 1px solid var(--border-input);
  border-bottom-width: 2px;
  border-radius: var(--r-xs);
}
.bbox-picker-map {
  width: 100%;
  height: 480px;
  border: 1px solid var(--border-list);
  border-radius: var(--r-xs);
  overflow: hidden;
}
.bbox-picker-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.bbox-picker-value {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-mono);
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bbox-picker-value em {
  color: var(--text-muted);
  font-style: italic;
}
.bbox-picker-buttons {
  display: inline-flex;
  gap: 6px;
}
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 18px;
}
/* pushes the trailing buttons right while a leading action (e.g. "Open catalog") stays left */
.modal-actions-spacer { flex: 1 1 auto; }
.modal-actions button {
  padding: 7px 13px;
  font-size: var(--fs-sm);
  border: 1px solid var(--pill-border);
  background: var(--pill-bg);
  color: var(--pill-fg);
  border-radius: var(--r-sm);
}
.modal-actions button.primary {
  background: var(--accent);
  color: var(--accent-fg);
  border-color: var(--accent-hover);
}
.modal-actions button.danger {
  background: transparent;
  color: var(--danger);
  border-color: var(--danger-border);
}
.modal-actions button:hover {
  background: var(--pill-hover-bg);
  color: var(--pill-hover-fg);
  border-color: var(--pill-hover-border);
}
.modal-actions button.primary:hover {
  background: var(--accent-hover);
  color: var(--accent-fg);
  border-color: var(--accent-active);
}
.modal-actions button.danger:hover { background: var(--danger-bg); color: var(--danger-hover); }

.logs-modal {
  width: min(900px, 96vw);
  display: flex;
  flex-direction: column;
  padding: 0;
  height: 70vh;
}
.run-summary-modal {
  width: min(560px, 94vw);
  padding: 0;
  display: flex;
  flex-direction: column;
}
.run-summary-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--divider);
}
.run-summary-head h2 { font-size: var(--fs-md); margin: 0; flex: 1; }
/* The badge's default align-self:flex-start suits a column; centre it in this header row. */
.run-summary-head .ai-badge { align-self: center; }
.run-summary-body {
  padding: 14px 16px;
  max-height: 60vh;
  overflow-y: auto;
}
.run-summary-text {
  margin: 0;
  font-size: var(--fs-sm);
  line-height: 1.55;
  color: var(--text);
  white-space: pre-wrap;
}
.logs-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--divider);
}
.logs-header h2 { font-size: var(--fs-md); margin: 0; flex: 1; }
.logs-header code { font-size: var(--fs-xs); color: var(--text-muted); }
.logs-state {
  font-size: var(--fs-xs);
  padding: 2px 8px;
  border-radius: var(--r-pill);
  background: var(--logstate-bg);
  color: var(--logstate-fg);
}
.logs-state.state-running    { background: var(--pill-running-bg);   color: var(--pill-running-fg); }
.logs-state.state-succeeded  { background: var(--pill-succeeded-bg); color: var(--pill-succeeded-fg); }
.logs-state.state-failed,
.logs-state.state-cancelled  { background: var(--pill-failed-bg);    color: var(--pill-failed-fg); }
.logs-close {
  -webkit-appearance: none;
  appearance: none;
  border: 1px solid var(--pill-border);
  background: var(--pill-bg);
  color: var(--pill-fg);
  padding: 7px 13px;
  border-radius: var(--r-sm);
  font: inherit;
  font-size: var(--fs-sm);
  cursor: pointer;
}
.logs-close:hover { background: var(--pill-hover-bg); color: var(--pill-hover-fg); border-color: var(--pill-hover-border); }
.logs-pane {
  flex: 1;
  margin: 0;
  padding: 12px 16px;
  background: var(--bg-terminal);
  color: var(--text-terminal);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: var(--lh-relaxed);
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
}

