/* ---- Muted text -----------------------------------------------------------
   Bootstrap's --bs-secondary-color is what "muted" normally means, but several
   bootswatch themes define it as a low-contrast translucent gray: Minty resolves
   it to rgba(136,136,136,.75), which is 2.44:1 on white — unreadable, and it is
   used for most of this app's small print.

   So muted is defined once here, derived from --bs-emphasis-color-rgb, which
   Bootstrap flips with the color mode (near-black on light themes, near-white on
   dark). Fading that keeps the visual hierarchy while staying legible in every
   theme. Anything that wants secondary text uses this. */
:root {
  --pm-muted-color: rgba(var(--bs-emphasis-color-rgb, 33, 37, 41), 0.82);
}

/* Bootstrap's own .text-muted utility resolves to --bs-secondary-color too, and
   it is all over the markup, so it is pointed at the same definition. This is a
   deliberate override of a theme's choice — 2.44:1 is not a style decision. */
.text-muted {
  color: var(--pm-muted-color) !important;
}

html,
body {
  height: 100%;
}

body {
  background: var(--bs-body-bg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.navbar,
.navbar .container-fluid {
  position: relative;
  overflow: visible;
  z-index: 1100;
}

#toastContainer {
  z-index: 11000 !important;
}

#toastContainer .toast {
  position: relative;
  z-index: 11001;
}

.modal-backdrop {
  z-index: 1190;
}

.modal {
  z-index: 1200;
}

/* Bootstrap's tooltip default (1080) sits BELOW the raised .modal above, so any
   tooltip inside a modal rendered behind it. Keep it above the modal but below
   #toastContainer (11000). Triggers inside a modal should also carry
   data-bs-container="body" so a scrollable modal body or .table-responsive
   (overflow: auto) can't clip the tooltip. */
.tooltip {
  z-index: 1210;
}

.app-shell {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  background: linear-gradient(
    180deg,
    var(--bs-body-bg) 0%,
    var(--bs-secondary-bg, var(--bs-tertiary-bg, var(--bs-body-bg))) 100%
  );
  padding-bottom: 0.5rem;
}

.view-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  padding: 0.5rem 0.25rem 0;
}

#viewProjects {
  overflow: auto;
}

#viewProjectDetail {
  overflow: hidden;
}

.section-card {
  border: 2px solid var(--bs-border-color, var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.12)));
  box-shadow: 0 8px 18px rgba(0, 0, 0, 0.06);
  border-radius: 0;
  background: linear-gradient(
    180deg,
    rgba(var(--bs-primary-rgb, 13, 110, 253), 0.03) 0%,
    var(--bs-card-bg, var(--bs-body-bg)) 100%
  );
  overflow: hidden;
  position: relative;
}

.section-card-header {
  cursor: pointer;
  align-items: center;
  background: var(--bs-secondary-bg, var(--bs-card-bg));
  border-bottom: 2px solid var(--bs-border-color, var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.12)));
  padding-top: 0.85rem;
  padding-bottom: 0.85rem;
}

.section-toggle-btn {
  min-width: 2.5rem;
}

/* Excel download icon on the Home list sections and the dashboard task widgets (2026-09-18). */
.section-excel-btn {
  min-width: 2.2rem;
}
.dashboard-excel-link {
  color: var(--bs-secondary-color, #6c757d);
  text-decoration: none;
  line-height: 1;
  font-size: 1rem;
}
.dashboard-excel-link:hover,
.dashboard-excel-link:focus-visible {
  color: var(--bs-success, #198754);
}

.section-title {
  font-size: 1.3rem;
  line-height: 1.2;
}

.section-card-header .btn-link {
  text-decoration: none;
  align-items: center;
}

.section-card-header .btn-link:hover,
.section-card-header .btn-link:focus {
  text-decoration: none;
}

.filter-card .btn-link {
  text-decoration: none;
}

.filter-card .btn-link:hover,
.filter-card .btn-link:focus {
  text-decoration: none;
}

.filter-card {
  background: transparent;
  box-shadow: 0 8px 18px rgba(0, 0, 0, 0.08);
  border-radius: 0;
}

.filter-card .card-header {
  background: transparent;
  border-bottom: 0;
  border-radius: 0;
}

.filter-card .card-body {
  background: transparent;
  border-top: 1px solid var(--bs-border-color, var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.12)));
  border-radius: 0;
  max-height: min(44vh, 420px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.task-note-entry {
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.08));
  background: var(--bs-card-bg, var(--bs-body-bg));
  border-radius: 0.5rem;
  padding: 0.65rem 0.75rem;
  align-items: flex-start;
}

.task-note-avatar {
  width: 34px;
  height: 34px;
  min-width: 34px;
  flex: 0 0 34px;
  border-radius: 50%;
  overflow: hidden;
}

.task-note-text {
  white-space: normal;
}

.task-note-deleted .task-note-text {
  opacity: 0.7;
  text-decoration: line-through;
}

.task-note-inline {
  display: block;
}

.task-view-multiline {
  white-space: pre-wrap;
}

#taskModal .form-label,
#viewTaskModal .form-label {
  font-weight: 600;
}

.task-title-input {
  flex-wrap: nowrap;
}

.task-title-input .form-control,
.task-title-input .form-control-plaintext {
  min-width: 0;
}

#taskNewNoteInput {
  min-height: 70px;
  max-width: 520px;
}

.note-editor {
  min-height: 70px;
}

.note-mention-menu {
  position: fixed;
  z-index: 2005;
  max-height: 220px;
  overflow-y: auto;
}

.note-mention-menu .list-group-item {
  border-left: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.08));
  border-right: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.08));
}

.note-editor-toolbar .note-color-swatch {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 1px solid var(--bs-border-color);
}

/* Keep the formatting toolbar buttons clearly visible across all themes. The
   default outline-secondary nearly disappears on dark themes (e.g. superhero)
   where the secondary color is close to the body background, so give them a
   theme-aware raised surface + border + body-color icons. */
.note-editor-toolbar .btn {
  --bs-btn-bg: var(--bs-tertiary-bg);
  --bs-btn-color: var(--bs-body-color);
  --bs-btn-border-color: var(--bs-border-color);
  --bs-btn-hover-bg: var(--bs-secondary-bg);
  --bs-btn-hover-color: var(--bs-emphasis-color);
  --bs-btn-hover-border-color: var(--bs-border-color);
  --bs-btn-active-bg: var(--bs-secondary-bg);
  --bs-btn-active-color: var(--bs-emphasis-color);
  --bs-btn-active-border-color: var(--bs-border-color);
}

.task-note-text p {
  margin-bottom: 0.25rem;
}

.task-note-text ul,
.task-note-text ol {
  margin-bottom: 0;
  padding-left: 1.25rem;
}

#taskAddNoteBtn {
  min-width: 140px;
  white-space: nowrap;
}

.project-section-body {
  min-height: 0;
}

.projects-sticky-controls {
  position: sticky;
  top: 0;
  z-index: 3;
  background: transparent;
  border-bottom: 0;
  padding-top: 0.5rem;
  padding-bottom: 0.85rem;
  box-shadow: none;
}

.filter-card-compact .card-header {
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}

.filter-card-compact .card-body {
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
}

.kanban-column {
  --kanban-column-width: var(--kanban-col-min, 280px);
  background: var(--bs-secondary-bg, var(--bs-card-bg, #f8f9fa));
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.08));
  border-radius: 0.75rem;
  padding: 0.75rem;
  min-height: 200px;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-width: var(--kanban-col-min, 280px);
  max-width: var(--kanban-col-max, 100%);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08);
  color: var(--bs-body-color);
}

.task-card {
  cursor: pointer;
  transition: box-shadow 0.6s ease, background-color 0.6s ease;
  width: 100%;
}

.task-progress-gauge {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

.task-progress-gauge-svg {
  width: 56px;
  height: 30px;
}

.task-progress-gauge--sm .task-progress-gauge-svg {
  width: 46px;
  height: 26px;
}

.task-progress-gauge-track {
  fill: none;
  stroke-width: 8;
  stroke-linecap: round;
}

.task-progress-gauge-needle {
  stroke: var(--bs-emphasis-color, #2c3e50);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

.task-progress-gauge-center {
  fill: var(--bs-emphasis-color, #2c3e50);
}

.task-progress-gauge-label {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--pm-muted-color);
}

.gantt-label .task-progress-gauge-label {
  font-size: 0.7rem;
}

.task-card-highlight {
  background-color: rgba(13, 110, 253, 0.12);
  box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.35), 0 12px 26px rgba(13, 110, 253, 0.18);
}

.project-card {
  cursor: pointer;
  transition: box-shadow 0.12s ease;
  border: 2px solid var(--bs-border-color, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.18));
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.12);
}

.project-card:hover {
  box-shadow: 0 14px 32px rgba(0, 0, 0, 0.14);
  border-color: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.25);
}

.project-card .btn-group {
  gap: 6px;
}

.project-card .btn-group .btn {
  margin-left: 0;
}

.favorite-toggle {
  border: 1px solid rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.08);
  background: transparent;
  color: #f0ad4e;
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: none !important;
  padding: 0;
}

.favorite-toggle:hover,
.favorite-toggle:focus {
  background: rgba(250, 191, 38, 0.18);
  border-color: rgba(240, 173, 78, 0.8);
  color: #d35400;
}

.favorite-toggle-active {
  background: #f6c344;
  border-color: #f3b935;
  color: #1f2937;
}

.favorite-toggle i {
  pointer-events: none;
}

}

.project-lead-user {
  border-left: 4px solid var(--bs-primary, #0d6efd);
  background: var(--bs-primary-bg-subtle, rgba(13, 110, 253, 0.12));
  color: var(--bs-emphasis-color, var(--bs-body-color));
  box-shadow: inset 0 0 0 1px var(--bs-border-color-translucent, rgba(255, 255, 255, 0.12));
}

.project-lead-user .text-muted,
.project-lead-user .text-secondary {
  color: var(--bs-emphasis-color, var(--bs-body-color)) !important;
}

.project-card-highlight {
  box-shadow: 0 0 0 4px rgba(13, 110, 253, 0.35), 0 0.6rem 1.2rem rgba(0, 0, 0, 0.08);
  background: rgba(13, 110, 253, 0.08);
  transition: box-shadow 4.8s ease, background-color 4.8s ease, transform 0.12s ease;
}

.project-card-highlight.project-card-highlight-fade {
  box-shadow: 0 0 0 0 rgba(13, 110, 253, 0), 0 0.6rem 1.2rem rgba(0, 0, 0, 0.08);
  background: rgba(255, 255, 255, 1);
}

.task-card-head .fa-flag {
  cursor: help;
}

.task-card:active {
  cursor: move;
}

.task-card:hover {
  box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.08);
}

.task-card .btn-outline-secondary {
  box-shadow: none !important;
  border: none !important;
  background: transparent !important;
  padding: 4px;
  color: var(--pm-muted-color);
}

.task-card .btn-outline-secondary:hover,
.task-card .btn-outline-secondary:focus {
  color: var(--bs-primary, #0d6efd);
  background: transparent;
  box-shadow: none;
}

.task-card .task-title-wrap {
  min-width: 0;
}

.task-type-icon {
  color: currentColor;
  flex-shrink: 0;
}

/* Custom (non-Font Awesome) task-type icons. Painted as a CSS mask so the glyph
   inherits the task type's color exactly like a Font Awesome <i> does and scales
   with font-size. mbi-sawblade replaced fa-wrench for Shop Order (Rich, 2026-09-05):
   12 raked teeth and a wide arbor hole, tuned to still read as a blade at 14px. */
.mbi-icon {
  display: inline-block;
  width: 1.2em;
  height: 1.2em;
  vertical-align: -0.235em;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: contain; mask-size: contain;
}
.mbi-sawblade {
  -webkit-mask-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20512%20512%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M506.0%2C256.0L451.0%2C275.5Q408.9%2C322.2%20472.5%2C381.0L415.2%2C370.4Q355.3%2C389.7%20381.0%2C472.5L336.7%2C434.6Q275.1%2C421.5%20256.0%2C506.0L236.5%2C451.0Q189.8%2C408.9%20131.0%2C472.5L141.6%2C415.2Q122.3%2C355.3%2039.5%2C381.0L77.4%2C336.7Q90.5%2C275.1%206.0%2C256.0L61.0%2C236.5Q103.1%2C189.8%2039.5%2C131.0L96.8%2C141.6Q156.7%2C122.3%20131.0%2C39.5L175.3%2C77.4Q236.9%2C90.5%20256.0%2C6.0L275.5%2C61.0Q322.2%2C103.1%20381.0%2C39.5L370.4%2C96.8Q389.7%2C156.7%20472.5%2C131.0L434.6%2C175.3Q421.5%2C236.9%20506.0%2C256.0ZM302%2C256A46%2C46%200%201%200%20210%2C256A46%2C46%200%201%200%20302%2C256Z%22%2F%3E%3C%2Fsvg%3E");
  mask-image: url("data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20512%20512%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20d%3D%22M506.0%2C256.0L451.0%2C275.5Q408.9%2C322.2%20472.5%2C381.0L415.2%2C370.4Q355.3%2C389.7%20381.0%2C472.5L336.7%2C434.6Q275.1%2C421.5%20256.0%2C506.0L236.5%2C451.0Q189.8%2C408.9%20131.0%2C472.5L141.6%2C415.2Q122.3%2C355.3%2039.5%2C381.0L77.4%2C336.7Q90.5%2C275.1%206.0%2C256.0L61.0%2C236.5Q103.1%2C189.8%2039.5%2C131.0L96.8%2C141.6Q156.7%2C122.3%20131.0%2C39.5L175.3%2C77.4Q236.9%2C90.5%20256.0%2C6.0L275.5%2C61.0Q322.2%2C103.1%20381.0%2C39.5L370.4%2C96.8Q389.7%2C156.7%20472.5%2C131.0L434.6%2C175.3Q421.5%2C236.9%20506.0%2C256.0ZM302%2C256A46%2C46%200%201%200%20210%2C256A46%2C46%200%201%200%20302%2C256Z%22%2F%3E%3C%2Fsvg%3E");
}

.task-type-request {
  color: var(--bs-primary, #0d6efd);
}

.task-type-issue {
  color: var(--bs-danger, #dc3545);
}

.task-type-custom {
  color: var(--bs-success, #198754);
}

.task-type-delivery {
  color: var(--bs-success, #198754);
}

.task-type-install {
  color: #795548;
}

.task-type-punch {
  color: #6f42c1;
}

.task-card .task-card-type {
  font-size: 0.8em;
}

.task-watchers-icon {
  color: var(--bs-secondary, #6c757d);
  display: inline-flex;
  align-items: center;
  cursor: pointer;
}

.task-watchers-icon.is-watching {
  color: var(--bs-primary, #0d6efd);
}

.task-watchers-icon.is-not-watching {
  color: var(--bs-secondary, #6c757d);
}

.task-watchers-icon.task-watchers-icon-disabled {
  opacity: 0.65;
}

.task-watch-toggle:disabled {
  opacity: 0.6;
  pointer-events: none;
}

.task-title-input .task-type-icon {
  color: var(--bs-body-color);
}

.task-title-type {
  gap: 0.35rem;
  margin-right: 0.35rem;
}

.custom-type-icon-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.custom-type-icon-btn {
  width: 2rem;
  height: 2rem;
  border: 1px solid var(--bs-border-color, #ced4da);
  border-radius: 0.375rem;
  background: var(--bs-body-bg, #fff);
  color: var(--pm-muted-color);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, color 0.15s ease;
}

.custom-type-icon-btn:hover,
.custom-type-icon-btn:focus {
  color: var(--bs-primary, #0d6efd);
  border-color: var(--bs-primary, #0d6efd);
  outline: 0;
}

.custom-type-icon-btn.active {
  color: var(--bs-primary, #0d6efd);
  border-color: var(--bs-primary, #0d6efd);
  box-shadow: 0 0 0 0.12rem rgba(13, 110, 253, 0.18);
}

.task-card .task-title {
  min-width: 0;
  display: block;
  width: 100%;
  max-width: clamp(120px, calc(var(--kanban-column-width, 280px) - 160px), 300px);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.task-description-block {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.task-card-custom-fields {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 0.75rem;
  align-items: center;
}

.task-card-custom-field {
  display: inline-flex;
  gap: 0.25rem;
  max-width: 100%;
  overflow-wrap: anywhere;
}

.task-checklist-inline {
  list-style: none;
  margin: 0.25rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.task-checklist-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.85rem;
}

.task-checklist-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0;
}

.task-checklist-item.readonly {
  padding: 0.2rem 0;
}

.task-checklist-input {
  flex: 1;
  min-width: 140px;
}

.task-checklist-controls {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
}

.task-checklist-drag {
  cursor: move;
  padding: 0 0.25rem;
  color: var(--pm-muted-color);
}

.task-checklist-item.dragging .task-checklist-drag {
  cursor: move;
}

.task-checklist-item.drag-over {
  background: var(--bs-secondary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.04));
  border-radius: 0.35rem;
}

.task-checklist-remove {
  padding: 0 0.25rem;
}

.task-checklist-text.completed {
  text-decoration: line-through;
  color: var(--pm-muted-color);
}

.task-checklist-remove {
  padding: 0 0.25rem;
}

.project-details-label {
  font-weight: 700;
}

.project-custom-field-actions {
  flex-shrink: 0;
}

.project-custom-field-drag {
  cursor: move;
  color: var(--pm-muted-color);
  padding: 0 0.25rem;
}

.project-custom-field-item.dragging .project-custom-field-drag {
  cursor: move;
}

.project-custom-field-item.dragging {
  opacity: 0.55;
}

.project-custom-field-item.drag-over {
  background: var(--bs-secondary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.04));
}

/* Project Information widget (per-project Dashboard tab): a full-width label/value
   grid that reflows from four columns down to one on narrow screens. */
.project-info-grid {
  display: grid;
  gap: 0.5rem 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.project-info-item {
  min-width: 0;
}

.project-info-label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--pm-muted-color);
}

.project-info-value {
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* Foreman phone/email: secondary detail beside the name, so they sit a step
   below the value text. The fa-xs icons are em-sized and shrink with it. */
.project-info-contact {
  font-size: 0.8125rem;
  font-weight: 500;
}

/* Project Types settings tab: category header rows with their types nested under
   them, so the list reads the same way the grouped Project Type dropdown does. */
.project-category-row {
  background: var(--bs-secondary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.04));
}

.project-category-row .fw-semibold {
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 0.875rem;
}

.project-type-child {
  padding-left: 2.25rem;
}

/* Application Settings tabstrip: one horizontally scrolling row instead of a
   wrapping block, so adding tabs never eats the modal body's vertical space.
   The chevrons flanking the strip are the scroll affordance, which is why the
   native scrollbar is hidden (it would sit between the tabs and their content). */
.admin-tabstrip {
  display: flex;
  align-items: stretch;
  border-bottom: 1px solid var(--bs-border-color, #dee2e6);
}

.admin-tabstrip-list.nav-tabs {
  flex: 1 1 auto;
  flex-wrap: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
  border-bottom: 0;
  scroll-behavior: smooth;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.admin-tabstrip-list.nav-tabs::-webkit-scrollbar {
  display: none;
}

.admin-tabstrip-list .nav-item {
  flex: 0 0 auto;
}

.admin-tabstrip-list .nav-link {
  white-space: nowrap;
  margin-bottom: 0;
}

.admin-tabstrip-nav {
  flex: 0 0 auto;
  align-self: stretch;
  border: 0;
  background: transparent;
  color: var(--pm-muted-color);
  padding: 0 0.5rem;
  line-height: 1;
}

.admin-tabstrip-nav:hover:not(:disabled) {
  color: var(--bs-body-color, #212529);
}

.admin-tabstrip-nav:disabled {
  opacity: 0.25;
  cursor: default;
}

/* Application Settings modal layout: with modal-dialog-scrollable on the dialog the
   modal is capped to the viewport and the header + footer (Save/Close) stay pinned.
   Here we make the body a flex column so the tab strip stays put too and ONLY the
   active tab's content scrolls vertically — rather than the whole page scrolling. */
#adminSettingsModal .modal-body {
  display: flex;
  flex-direction: column;
  overflow: hidden; /* the body itself never scrolls */
}
#adminSettingsModal .modal-body > .admin-tabstrip {
  flex: 0 0 auto; /* tab strip stays visible */
}
#adminSettingsModal .modal-body > .tab-content {
  flex: 1 1 auto;
  min-height: 0; /* let the flex child shrink so its own overflow can take over */
  /* Explicit overflow-x: hidden — otherwise overflow-x defaults to visible, which CSS
     forces to `auto` the moment overflow-y is auto, so the vertical scrollbar's width
     spawns a phantom horizontal scrollbar. Hidden clips the harmless .row gutter instead. */
  overflow-x: hidden;
  overflow-y: auto; /* only the current tab's content scrolls */
}
/* The global `.tab-content > .tab-pane.active` rule (for the board/detail views) makes the
   active pane a fixed-height flex item with overflow:hidden, which would CLIP a tall Settings
   tab so nothing scrolls. Here the active pane grows to its natural height and the scrolling
   .tab-content above it takes over. */
#adminSettingsModal .modal-body > .tab-content > .tab-pane.active,
#adminSettingsModal .modal-body > .tab-content > .tab-pane.show {
  flex: 0 0 auto;
  overflow: visible;
}

/* A Details section a role-limited viewer isn't granted (item 6). Dedicated class so it never
   fights the Other/Misc d-none toggles applied to some of the same section wrappers. */
.role-hidden-section { display: none !important; }

.project-dashboard {
  padding-bottom: 1rem;
  overflow-x: auto;
}

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

.dashboard-widget-wide {
  grid-column: span 2;
}

/* Hard row break + full row: the Pending Change Requests widget sits LAST on
   both dashboards, alone on its own row, spanning the grid's full width. */
.dashboard-widget-break {
  grid-column: 1 / -1;
}

/* Late / Upcoming / Done side by side on one full-width row (both dashboards);
   stacks to a single column on narrow screens. The widgets inside keep their
   normal look — this wrapper only owns the 3-across placement. */
.dashboard-widget-row-3 {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem;
}

.dashboard-task-main {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-width: 0;
}

.dashboard-task-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  align-items: center;
}

.dashboard-assignee-avatar {
  display: inline-flex;
}

/* All three home-dash task widgets (Late / Upcoming / Recently Completed)
   share this layout. .dashboard-task-link is a Bootstrap .btn (text-align:
   center by default), so without the left override a stretched title button
   centers its text and shows a phantom left gap — Late looked indented while
   Upcoming (which had these rules as a -upcoming variant) did not. */
.dashboard-list-item {
  align-items: flex-start;
  justify-content: space-between;
}

.dashboard-list-item .dashboard-task-link {
  text-align: left;
}

/* Direct-to-edit pencils on calendar pills / agenda rows (leftmost in the
   meta row, ahead of the status badge, so narrow Timeline bars keep it visible). */
.calendar-task-pill .calendar-task-edit,
.calendar-list-row .calendar-task-edit,
.gantt-bar .calendar-task-edit {
  margin-right: 0.2rem;
  opacity: 0.65;
  cursor: pointer;
}
.calendar-task-pill:hover .calendar-task-edit,
.calendar-list-row:hover .calendar-task-edit,
.gantt-bar:hover .calendar-task-edit,
.calendar-task-edit:focus-visible {
  opacity: 1;
}

@media (max-width: 991px) {
  .dashboard-widget-wide {
    grid-column: span 1;
  }

  .dashboard-widget-break {
    grid-column: 1 / -1;
  }

  .dashboard-widget-row-3 {
    grid-template-columns: 1fr;
  }

  html,
  body {
    height: auto;
    min-height: 100%;
  }

  body {
    overflow-y: auto;
  }

  .app-shell,
  .view-panel,
  #viewProjects,
  #tabBoard,
  .kanban-board-wrapper,
  .tab-content,
  .tab-content > .tab-pane.active,
  .tab-content > .tab-pane.show {
    overflow: visible;
    min-height: auto;
  }

  .projects-sticky-controls {
    position: static;
  }

  .filter-card,
  .filter-card .card-body,
  .section-card,
  .section-card .card-body {
    overflow: visible;
  }

  #kanbanBoard,
  #homeKanbanBoard {
    --kanban-gap: 0;
    --kanban-col-min: 100vw;
    --kanban-col-max: 100vw;
    --kanban-col-target: 100vw;
    padding: 0 0 1rem;
    width: 100vw;
    max-width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    overflow-x: auto;
    overflow-y: visible;
    scroll-snap-type: x mandatory;
    scroll-padding-left: 0;
    scroll-behavior: smooth;
    overscroll-behavior-x: contain;
    touch-action: pan-x;
    -webkit-overflow-scrolling: touch;
  }

  #kanbanBoard > [class*='col-'],
  #homeKanbanBoard > [class*='col-'] {
    flex: 0 0 100vw;
    width: 100vw;
    min-width: 100vw;
    max-width: 100vw;
    scroll-snap-align: start;
    scroll-snap-stop: always;
    padding-left: 0.25rem;
    padding-right: 0.25rem;
  }

  .kanban-column {
    min-width: 100%;
    max-width: 100%;
  }

  .kanban-tasks {
    max-height: none;
    overflow: visible;
  }

  #viewProjectDetail > .d-flex:first-child {
    flex-direction: column;
    align-items: stretch !important;
    gap: 0.75rem;
  }

  #viewProjectDetail > .d-flex:first-child > div:first-child {
    min-width: 0;
  }

  #detailTitle {
    flex-wrap: wrap;
  }

  #detailActions {
    display: flex;
    flex-wrap: wrap;
    width: 100%;
  }

  #detailActions .btn,
  #detailActions > span,
  #detailActions > span .btn {
    width: 100%;
  }

  #detailTabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    padding-bottom: 0.25rem;
    -webkit-overflow-scrolling: touch;
  }

  #detailTabs .nav-item {
    flex: 0 0 auto;
  }

  #detailTabs .nav-link {
    white-space: nowrap;
  }
}

.dashboard-widget {
  background: var(--bs-card-bg, var(--bs-body-bg));
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.12));
  box-shadow: 0 8px 18px rgba(0, 0, 0, 0.06);
  border-radius: 0.75rem;
  padding: 0.85rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-height: 140px;
}

.dashboard-widget-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
/* Collapsible widget headers (Project/Financial Information): the whole header is the
   toggle, so show a pointer and highlight the title on hover. */
.dashboard-widget-header-toggle {
  cursor: pointer;
}
.dashboard-widget-header-toggle:hover .dashboard-widget-title {
  color: var(--bs-primary, #0d6efd);
}

/* A collapsed widget shows its summary INLINE on the header row (wrapping) and
   drops the 140px min-height so it takes only the space it needs. Scoped to the
   collapsed modifier so the ~12 fixed-height stat widgets keep their uniform size. */
.dashboard-widget-collapsed {
  min-height: 0;
}
.dashboard-widget-collapsed .dashboard-widget-header {
  flex-wrap: wrap;
  align-items: baseline;
}
.dashboard-widget-summary {
  flex: 1 1 auto;
  min-width: 0;
}
/* Full-width row inside .project-info-grid (for long free-text like lien reqs). */
.project-info-item-full {
  grid-column: 1 / -1;
}
.lien-req-clamp {
  white-space: pre-wrap;
}
.lien-req-peek:not(.expanded) .lien-req-clamp {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* "Assigned to me" quick filter: muted while off, highlighted while it is
   narrowing the list (List View section headers and dashboard widgets alike). */
.mine-filter-btn {
  color: var(--pm-muted-color);
  text-decoration: none;
  white-space: nowrap;
}

.mine-filter-btn:hover,
.mine-filter-btn:focus-visible {
  color: var(--bs-primary, #0d6efd);
}

.mine-filter-btn.active {
  color: var(--bs-primary, #0d6efd);
  font-weight: 600;
}

.dashboard-widget-action {
  color: var(--pm-muted-color);
}

.dashboard-widget-action:hover,
.dashboard-widget-action:focus {
  color: var(--bs-body-color);
}

.dashboard-widget-title {
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.dashboard-stat {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
}

.dashboard-stat-value {
  font-size: 1.6rem;
  font-weight: 700;
}

.dashboard-stat-label {
  font-size: 0.85rem;
  color: var(--pm-muted-color);
}

.dashboard-stat-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.35rem 1rem;
}

.dashboard-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  background: var(--bs-tertiary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05));
  font-size: 0.75rem;
  font-weight: 600;
}
.dashboard-chip-link {
  border: 0;
  cursor: pointer;
  font-family: inherit;
  color: var(--bs-body-color, inherit);
}
.dashboard-chip-link:hover,
.dashboard-chip-link:focus {
  text-decoration: underline;
  background: var(--bs-secondary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.12));
}

.dashboard-bar-chart {
  display: flex;
  align-items: flex-end;
  gap: 0.5rem;
  height: 160px;
}

.dashboard-bar-wrap {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  min-width: 0;
  height: 100%;
}

.dashboard-bar-slot {
  flex: 1;
  width: 100%;
  display: flex;
  align-items: flex-end;
}

.dashboard-bar {
  width: 100%;
  border-radius: 0.5rem 0.5rem 0 0;
  background: linear-gradient(
    180deg,
    rgba(var(--bs-primary-rgb, 13, 110, 253), 0.9),
    rgba(var(--bs-primary-rgb, 13, 110, 253), 0.35)
  );
  min-height: 6px;
}

.dashboard-bar-label {
  font-size: 0.7rem;
  text-align: center;
  color: var(--pm-muted-color);
  min-height: 2.2em;
  line-height: 1.1;
}

.dashboard-bar-count {
  font-size: 0.75rem;
  font-weight: 600;
}

.dashboard-progress {
  height: 0.6rem;
}

.dashboard-list {
  list-style: none;
  padding-left: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.dashboard-list-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  background: var(--bs-tertiary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.04));
  padding: 0.35rem 0.5rem;
  border-radius: 0.5rem;
}

.dashboard-pager {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 0.35rem;
}

.dashboard-metric-link,
.dashboard-task-link {
  font-weight: 600;
  color: var(--bs-primary);
  text-decoration: none;
}

.dashboard-task-link {
  font-weight: 400;
}

.dashboard-metric-link:hover,
.dashboard-task-link:hover {
  text-decoration: underline;
}

.dashboard-metric-link-inline {
  display: inline;
}

.traffic-lights {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.35rem;
}

.traffic-light {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--bs-secondary-bg, #ced4da);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.18);
}

.traffic-light.is-active {
  transform: scale(1.25);
  box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.18), 0 0 10px currentColor;
  outline: 2px solid rgba(255, 255, 255, 0.6);
  outline-offset: 2px;
}

.traffic-light-green {
  background: #198754;
  color: var(--bs-success, #198754);
}

.traffic-light-yellow {
  background: #f6c344;
  color: #f6c344;
}

.traffic-light-red {
  background: #dc3545;
  color: var(--bs-danger, #dc3545);
}

.badge-status-completed {
  background-color: #198754;
  color: #fff;
}

.badge-status-cancelled {
  background-color: #fd7e14;
  color: #fff;
}

.badge-status-inprogress {
  background-color: #343a40;
  color: #fff;
}

.badge-status-planned {
  background-color: #e9ecef;
  color: #1f2937;
}

.badge-status-onhold {
  background-color: #f6c344;
  color: #1f2937;
}

.task-collapsed .task-details {
  display: none;
}

.task-card .edit-collapsed {
  visibility: visible;
}

.task-card:not(.task-collapsed) .edit-collapsed {
  display: none;
}

.badge-flagged {
  background-color: #e67e22;
}

.task-soon {
  border-left: 5px solid #f1c40f;
}

.task-due-today {
  border-left-color: #c2185b;
}

.task-upcoming-label {
  color: #f1c40f;
}

.task-due-today-label {
  color: #c2185b;
}

.task-late {
  border-left: 5px solid #e74c3c;
}

.task-order {
  font-size: 0.85rem;
  color: var(--pm-muted-color);
}

.attachment-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  margin: 2px;
  border-radius: 999px;
  background: var(--bs-tertiary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05));
}

.blocker-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  margin: 2px 4px 2px 0;
  border-radius: 10px;
  background: var(--bs-tertiary-bg, rgba(255, 0, 0, 0.05));
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05));
}

.blocker-chip .remove-blocker {
  border: none;
  background: transparent;
  color: var(--bs-danger, #dc3545);
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.blocker-chip .remove-blocker:hover,
.blocker-chip .remove-blocker:focus {
  color: var(--bs-danger, #a71d2a);
}

.task-tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.task-tag-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  border-radius: 999px;
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.12));
  background: var(--bs-tertiary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.04));
  font-size: 0.75rem;
}

/* Task tag color strip. A thin band across the top of a task card, striped and
   repeating when the task carries several colored tags (the way TeamUp draws
   it). The gradient itself is inline — it is per-task data, not a style — and
   this rule only owns the geometry.

   It is drawn ONLY when at least one of the task's tags carries a color, so an
   uncolored task keeps the card it has always had rather than gaining an empty
   gray band. inherit on the radii lets it sit flush inside the card's own
   rounding without knowing what that rounding is. */
.task-tag-strip {
  height: var(--pm-tag-strip-height);
  flex: 0 0 auto;
  border-top-left-radius: inherit;
  border-top-right-radius: inherit;
  /* A card whose body has its own background would otherwise paint over the
     strip's bottom edge on sub-pixel layouts. */
  position: relative;
  z-index: 1;
}

/* Compact surfaces (calendar pills, agenda/list rows, dashboard widget lines,
   Gantt bars) get the smaller band; a card gets the full one. Both were doubled
   on 2026-09-04 — at the original 6px/3px the individual colors in a striped
   band were too thin to read, which is the whole point of the band. */
:root {
  --pm-tag-strip-height: 12px;
  --pm-tag-strip-height-compact: 6px;
}

/* A calendar pill is a fraction of a card's height and already carries a status
   color down its left edge, so its strip is thinner and rides inside the pill's
   own rounding. */
.calendar-task-pill .task-tag-strip {
  height: var(--pm-tag-strip-height-compact);
  margin-bottom: 2px;
  border-radius: 2px;
}

/* The kanban card's strip sits above a body with its own padding; without this
   the band would inherit the gap and float. */
.task-card > .task-tag-strip {
  margin-bottom: 0;
}

/* ROW surfaces. A dashboard widget line, a calendar list row and a Gantt bar are
   all horizontal flex boxes, where an in-flow strip would be a thin vertical
   sliver rather than a band. These get an absolutely positioned band across the
   top instead, and `pm-tag-striped` makes the room for it so it never paints
   over the row's own text. */
.task-tag-strip-row,
.task-tag-strip-bar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--pm-tag-strip-height-compact);
  border-top-left-radius: inherit;
  border-top-right-radius: inherit;
  pointer-events: none;
  z-index: 1;
}

.dashboard-list-item.pm-tag-striped {
  position: relative;
  padding-top: calc(0.35rem + var(--pm-tag-strip-height-compact));
}

.calendar-list-row.pm-tag-striped {
  position: relative;
  padding-top: calc(0.4rem + var(--pm-tag-strip-height-compact));
}

/* A Gantt bar is already absolutely positioned and vertically centered by a
   transform, so it must NOT gain padding — that would resize it and move every
   bar off its row. The band overlays the top of the bar instead, clipped to the
   bar's pill rounding. */
.gantt-bar.pm-tag-striped {
  overflow: hidden;
}

/* "No color" for a tag, in the slot a color picker would occupy. A DISABLED
   color input still paints its value, so an uncolored tag would look as though
   somebody had chosen that color on purpose; hatching reads as absence. */
.task-tag-noswatch {
  display: inline-block;
  width: 2.6rem;
  height: calc(1.5em + 0.5rem + 2px);
  border: 1px solid var(--bs-border-color, #dee2e6);
  border-radius: 0.25rem;
  background-image: repeating-linear-gradient(
    45deg,
    transparent 0 3px,
    var(--bs-secondary-bg, #e9ecef) 3px 6px
  );
}

.task-tag-line {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}

.task-tag-remove {
  border: none;
  background: transparent;
  color: var(--pm-muted-color);
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.task-tag-remove:hover,
.task-tag-remove:focus {
  color: var(--bs-body-color);
}

.blocker-indicator {
  font-size: 1.05rem;
  line-height: 1;
  cursor: help;
}

/* Blocker / Blocks entries open the task read-only — they read as links, not
   buttons, wherever a dependency is listed. */
.related-task-link {
  text-align: left;
  text-decoration: none;
  vertical-align: baseline;
}

.related-task-link:hover,
.related-task-link:focus-visible {
  text-decoration: underline;
}

/* On board cards the blocker / blocks indicators ARE the control that pins the
   board to the task's dependency chain — so they click, they don't just inform.
   The icon keeps its own status color; only the affordance changes. */
.blocker-indicator.task-related-filter {
  cursor: pointer;
  vertical-align: baseline;
  text-decoration: none;
}

.blocker-indicator.task-related-filter:hover,
.blocker-indicator.task-related-filter:focus-visible {
  filter: brightness(1.15);
  transform: scale(1.1);
}

/* The "board is pinned to a dependency chain" chip in the filter bar — it is the
   only sign the filter is on, so it reads as an active state, not a link. */
.related-filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  border: 1px solid var(--bs-warning-border-subtle, #ffe69c);
  background: var(--bs-warning-bg-subtle, #fff3cd);
  color: var(--bs-warning-text-emphasis, #664d03);
  font-weight: 600;
  white-space: nowrap;
  max-width: 32rem;
}

.related-filter-chip span {
  overflow: hidden;
  text-overflow: ellipsis;
}

.related-filter-chip:hover,
.related-filter-chip:focus-visible {
  border-color: var(--bs-warning, #ffc107);
  background: var(--bs-warning-bg-subtle, #fff3cd);
  color: var(--bs-warning-text-emphasis, #664d03);
}

.blocker-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.blocker-pill {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--bs-tertiary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.03));
}

.kanban-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.5rem;
  position: sticky;
  top: 0;
  background: var(--bs-dark-bg-subtle, var(--bs-secondary-bg, var(--bs-card-bg, #fff)));
  color: var(--bs-body-color);
  z-index: 1;
  padding-bottom: 0.25rem;
  border-bottom: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.2));
  border-radius: 0.5rem;
  padding: 0.35rem 0.5rem;
}

.kanban-header strong {
  color: var(--bs-emphasis-color, var(--bs-body-color));
}

.kanban-header .kanban-count-badge {
  background: var(--bs-primary, #0d6efd);
  color: #fff;
  border: 1px solid var(--bs-primary-border-subtle, var(--bs-primary, #0d6efd));
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
  font-weight: 700;
}

.kanban-tasks {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
}

#kanbanBoard,
#homeKanbanBoard {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-start;
  --kanban-gap: 0.75rem;
  gap: var(--kanban-gap);
  margin-left: 0;
  margin-right: 0;
  padding: 0.25rem var(--kanban-gap);
  --kanban-col-min: 280px;
  --kanban-col-max: 100%;
  --kanban-col-target: calc((100% - (var(--kanban-gap) * 3)) / 4);
  flex: 1;
  min-height: 0;
  overflow-x: auto;
  overflow-y: auto;
}

#kanbanBoard.row,
#homeKanbanBoard.row {
  --bs-gutter-x: 0;
  --bs-gutter-y: 0;
}

#kanbanBoard > [class*='col-'],
#homeKanbanBoard > [class*='col-'] {
  --kanban-column-width: clamp(var(--kanban-col-min), var(--kanban-col-target), var(--kanban-col-max));
  display: flex;
  flex: 0 0 var(--kanban-column-width);
  max-width: var(--kanban-column-width);
  width: var(--kanban-column-width);
  min-width: var(--kanban-col-min);
  padding-left: 0;
  padding-right: 0;
}

.column-drop-target {
  color: var(--bs-primary, #0d6efd);
  border-color: rgba(13, 110, 253, 0.4);
  background: rgba(13, 110, 253, 0.05);
  transition: all 0.15s ease;
}

.column-drop-target.active,
.column-drop-target:hover,
.column-drop-target:focus {
  color: #fff;
  background: var(--bs-primary, #0d6efd);
  border-color: var(--bs-primary, #0d6efd);
  box-shadow: 0 0.25rem 0.75rem rgba(13, 110, 253, 0.35);
}

.gantt-board-wrapper {
  --gantt-label-width: 320px;
  display: flex;
  flex-direction: column;
  border: 1px dashed var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05));
  background: var(--bs-secondary-bg, var(--bs-card-bg, #f8f9fa));
  border-radius: 0.85rem;
  padding: 0.85rem;
  color: var(--bs-body-color);
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.gantt-scroll {
  min-width: 100%;
}

.gantt-grid {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  flex: 1;
  min-height: 0;
  overflow: auto;
  position: relative;
}

.gantt-grid::before {
  content: "";
  position: absolute;
  inset: 0 auto 18px 0;
  width: calc(var(--gantt-label-width, 320px) + 12px);
  background: var(--bs-secondary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.04));
  pointer-events: none;
  z-index: 1;
}

.gantt-empty-message {
  margin-left: calc(var(--gantt-label-width, 320px) + 16px);
  max-width: 620px;
  position: relative;
  z-index: 2;
}

.gantt-grid.gantt-compact {
  --gantt-label-width: 230px;
  gap: 0.35rem;
}

.gantt-row {
  display: grid;
  grid-template-columns: var(--gantt-label-width, 320px) 1fr;
  gap: 0.75rem;
  align-items: stretch;
}

.gantt-header {
  position: sticky;
  top: 0;
  left: 0;
  z-index: 8;
  background: var(--bs-secondary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.04));
  padding-top: 0.25rem;
  padding-bottom: 0.35rem;
}

.gantt-label {
  position: sticky;
  left: 0;
  z-index: 4;
}

.task-list-container {
  min-height: 120px;
}

.task-list-card {
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.08));
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.06);
}

.task-list-card .badge {
  font-weight: 700;
}

.task-list-card .task-due-label {
  color: var(--pm-muted-color);
}

.task-list-card .task-checklist-summary i {
  color: var(--bs-success, #198754);
}

.task-list-card-late .task-due-label {
  color: var(--bs-danger);
  font-weight: 700;
}

.task-list-card-soon .task-due-label {
  color: var(--bs-warning);
  font-weight: 700;
}

.task-list-card-due-today .task-due-label {
  color: #c2185b;
  font-weight: 700;
}

.task-list-type {
  color: var(--bs-primary);
}

.task-list-title {
  max-width: 46rem;
}

.task-calendar-container {
  min-height: 420px;
}

.calendar-view-shell {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  min-height: 0;
}

.calendar-toolbar {
  position: sticky;
  top: 0;
  z-index: 5;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.1));
  border-radius: 0.65rem;
  background: var(--bs-body-bg, #fff);
  box-shadow: 0 8px 18px rgba(0, 0, 0, 0.06);
}

.calendar-period-title {
  min-width: 16rem;
  text-align: right;
}

.calendar-day-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(148px, 1fr));
  gap: 0.5rem;
  min-width: 980px;
}

.calendar-weekday {
  padding: 0.35rem 0.5rem;
  color: var(--pm-muted-color);
  font-size: 0.8rem;
  font-weight: 800;
  text-transform: uppercase;
}

.calendar-day-cell {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  min-height: 138px;
  padding: 0.55rem;
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.12));
  border-radius: 0.5rem;
  background: var(--bs-body-bg, #fff);
}

.calendar-day-outside {
  background: var(--bs-secondary-bg, #f8f9fa);
  opacity: 0.72;
}

.calendar-day-today {
  border-color: var(--bs-primary, #0d6efd);
  box-shadow: inset 0 0 0 1px var(--bs-primary, #0d6efd);
}

.calendar-day-header,
.calendar-year-month-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  font-weight: 800;
}

.calendar-day-count {
  color: var(--pm-muted-color);
  font-size: 0.8rem;
}

.calendar-day-tasks,
.calendar-year-task-list {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-width: 0;
}

.calendar-task-pill {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.05rem;
  width: 100%;
  min-width: 0;
  padding: 0.35rem 0.45rem;
  border: 0;
  border-left: 4px solid var(--calendar-task-color, var(--bs-primary, #0d6efd));
  border-radius: 0.35rem;
  background: color-mix(in srgb, var(--calendar-task-color, #0d6efd) 12%, var(--bs-body-bg, #fff));
  color: var(--bs-emphasis-color, #212529);
  text-align: left;
  line-height: 1.15;
}

.calendar-task-pill:hover,
.calendar-task-pill:focus {
  background: color-mix(in srgb, var(--calendar-task-color, #0d6efd) 20%, var(--bs-body-bg, #fff));
  outline: 2px solid color-mix(in srgb, var(--calendar-task-color, #0d6efd) 55%, transparent);
}

.calendar-task-title,
.calendar-task-project {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.calendar-task-title {
  font-size: 0.82rem;
  font-weight: 700;
}

.calendar-task-project {
  color: var(--pm-muted-color);
  font-size: 0.72rem;
}

.calendar-task-attach {
  margin-left: 0.25rem;
  opacity: 0.75;
  font-size: 0.78em;
}

/* Compact meta row shared by every calendar card (grid pills, list rows, and
   timeline bars): status badge + priority dot + assignee avatar, kept on one
   line so the extra indicators don't grow the card's height. */
.calendar-task-meta {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  flex-wrap: wrap;
  min-width: 0;
  margin-top: 0.05rem;
}
.calendar-task-priority {
  width: 0.62rem;
  height: 0.62rem;
  border-radius: 50%;
  flex: 0 0 auto;
  display: inline-block;
  border: 1px solid rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.22);
}
/* Subtle "assigned via a role" indicator next to the assignee avatar. */
.task-role-indicator {
  color: var(--pm-muted-color);
  font-size: 0.78em;
  opacity: 0.85;
  flex: 0 0 auto;
}
.calendar-task-priority.priority-high {
  background: #e53935;
}
.calendar-task-priority.priority-medium {
  background: #ffc107;
}
.calendar-task-priority.priority-low {
  background: #4caf50;
}
.calendar-task-assignee-slot {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
}
.calendar-task-assignee-slot .current-user-avatar {
  width: 18px;
  height: 18px;
  font-size: 0.56rem;
  border-width: 1px;
  box-shadow: none;
}
.calendar-task-unassigned {
  color: var(--pm-muted-color);
  font-size: 0.72rem;
  line-height: 1;
}

.calendar-more-count {
  color: var(--pm-muted-color);
  font-size: 0.78rem;
  font-weight: 700;
}

.calendar-year-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(220px, 1fr));
  gap: 0.75rem;
}

.calendar-year-month {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-height: 180px;
  padding: 0.75rem;
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.12));
  border-radius: 0.55rem;
  background: var(--bs-body-bg, #fff);
}

.gantt-grid.calendar-grid-mode {
  display: block;
}

.gantt-grid.calendar-grid-mode::before {
  display: none;
}

/* The grid scrolls horizontally inside this wrapper; the shell (and its sticky
   toolbar) stay at container width so the date/view header doesn't scroll off. */
.calendar-grid-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.gantt-timeline-toolbar {
  flex: 0 0 auto;
}

.gantt-scroll-pane,
.calendar-timeline-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
}

.gantt-toolbar-zoom .btn-group {
  align-items: stretch;
}

.gantt-toolbar-zoom .gantt-zoom-input {
  width: 76px;
  min-height: 31px;
  border-radius: 0;
  border-left: 0;
  border-right: 0;
}

.gantt-grid.gantt-timeline-full::before {
  display: none;
}

.gantt-grid.gantt-timeline-full {
  overflow: hidden;
}

.gantt-grid.gantt-timeline-full .gantt-empty-message {
  margin-left: 0;
}

.gantt-grid.gantt-timeline-full .gantt-row,
.calendar-timeline-content .gantt-row {
  grid-template-columns: minmax(0, 1fr);
  gap: 0.5rem;
}

.gantt-grid.gantt-timeline-full .gantt-label,
.gantt-grid.gantt-timeline-full .gantt-detail {
  display: none !important;
}

.gantt-grid.gantt-timeline-full .gantt-header {
  position: relative;
  top: auto;
  left: auto;
  z-index: 4;
}

.gantt-grid.gantt-timeline-full .gantt-row-timeline {
  min-height: 60px;
}

.calendar-timeline-shell {
  min-width: 0;
  gap: 0.75rem;
}

.calendar-timeline-content {
  min-width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.calendar-timeline-content .gantt-header {
  position: relative;
  top: auto;
  left: auto;
  z-index: 4;
  padding: 0;
  background: transparent;
}

.calendar-timeline-content .gantt-timeline {
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.12));
  border-radius: 0.5rem;
  background: var(--bs-body-bg, #fff);
  box-shadow: 0 6px 14px rgba(0, 0, 0, 0.04);
}

.calendar-timeline-content .gantt-date-row {
  min-height: 50px;
  border-radius: 0.5rem;
  background: var(--bs-body-bg, #fff);
  align-items: center;
}

.calendar-timeline-content .gantt-date-cell {
  height: auto;
  min-height: 50px;
  padding: 0.4rem 0.25rem;
  transform: none;
  align-items: center;
  color: var(--pm-muted-color);
  font-size: 0.75rem;
  font-weight: 800;
  text-shadow: none;
  text-transform: uppercase;
}

.calendar-timeline-content .gantt-date-cell.gantt-date-today {
  color: var(--bs-primary, #0d6efd);
  background: var(--bs-primary-bg-subtle, rgba(13, 110, 253, 0.1));
  border-bottom: 2px solid var(--bs-primary, #0d6efd);
}

.calendar-timeline-content .gantt-row-timeline {
  min-height: 58px;
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.12));
  border-radius: 0.5rem;
  background-color: var(--bs-body-bg, #fff);
  background-image: linear-gradient(
    to right,
    var(--bs-border-color-translucent, rgba(0, 0, 0, 0.08)) 1px,
    transparent 1px
  );
  box-shadow: 0 6px 14px rgba(0, 0, 0, 0.04);
}

.calendar-timeline-task-pill {
  min-height: 36px;
  padding: 0.38rem 0.55rem;
  border: 1px solid color-mix(in srgb, var(--calendar-task-color, #0d6efd) 35%, var(--bs-border-color, #dee2e6));
  border-left: 4px solid var(--calendar-task-color, var(--bs-primary, #0d6efd));
  border-radius: 0.35rem;
  background: color-mix(in srgb, var(--calendar-task-color, #0d6efd) 12%, var(--bs-body-bg, #fff)) !important;
  color: var(--bs-emphasis-color, #212529) !important;
  box-shadow: none;
  text-shadow: none;
}

.calendar-timeline-task-pill:hover,
.calendar-timeline-task-pill:focus {
  background: color-mix(in srgb, var(--calendar-task-color, #0d6efd) 20%, var(--bs-body-bg, #fff)) !important;
  outline: 2px solid color-mix(in srgb, var(--calendar-task-color, #0d6efd) 55%, transparent);
}

.calendar-timeline-task-pill .gantt-bar-title {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.05rem;
  max-width: 100%;
  line-height: 1.15;
}

.calendar-timeline-task-pill .gantt-bar-title-text {
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--bs-emphasis-color, #212529);
}

.calendar-timeline-task-pill .gantt-bar-dates {
  color: var(--pm-muted-color);
  font-size: 0.72rem;
  font-weight: 700;
  opacity: 1;
}

.gantt-bar-project {
  font-size: 0.78rem;
  opacity: 0.82;
}

@media (max-width: 991px) {
  .calendar-toolbar {
    align-items: stretch !important;
  }

  .calendar-period-title {
    min-width: 0;
    width: 100%;
    text-align: left;
  }

  .calendar-day-grid {
    min-width: 760px;
  }

  .calendar-year-grid {
    grid-template-columns: repeat(2, minmax(220px, 1fr));
  }
}

.gantt-header .gantt-label {
  z-index: 9;
  background: var(--bs-secondary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.04));
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.08));
  box-shadow: 0 8px 18px rgba(0, 0, 0, 0.06);
}

.gantt-label {
  background: var(--bs-secondary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.04));
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.2));
  border-radius: 0 0.85rem 0.85rem 0;
  padding: 0.65rem 0.85rem;
  box-shadow: 0 6px 14px rgba(0, 0, 0, 0.08);
  color: var(--bs-emphasis-color, var(--bs-body-color));
  height: 100%;
}

.gantt-label,
.gantt-label .gantt-label-title,
.gantt-label .gantt-label-title-text,
.gantt-label .gantt-label-meta,
.gantt-label .badge,
.gantt-label .btn {
  color: var(--bs-emphasis-color, var(--bs-body-color));
}

.gantt-label .gantt-label-meta,
.gantt-label .gantt-label-title-text {
  opacity: 1;
  color: var(--bs-emphasis-color, var(--bs-body-color));
}

.gantt-label .gantt-label-meta,
.gantt-label .gantt-label-meta .text-muted,
.gantt-label .gantt-label-meta .text-secondary,
.gantt-label .text-muted,
.gantt-label .text-secondary {
  color: var(--bs-emphasis-color, var(--bs-body-color)) !important;
  opacity: 0.92;
}

.gantt-label .gantt-label-title {
  align-items: center;
  min-height: 56px;
}

.gantt-grid.gantt-compact .gantt-label {
  padding: 0.4rem 0.55rem;
}

.gantt-grid.gantt-compact .gantt-label .gantt-label-title {
  min-height: 38px;
}

.gantt-label .badge {
  background: var(--bs-primary-bg-subtle, var(--bs-secondary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.08)));
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.15));
  color: var(--bs-primary-text-emphasis, var(--bs-emphasis-color));
}

.gantt-label .btn {
  background: var(--bs-secondary-bg, var(--bs-body-bg));
  border-color: var(--bs-border-color, var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.2)));
  color: var(--bs-emphasis-color, var(--bs-body-color));
  box-shadow: none;
}

.gantt-label .btn-outline-primary {
  color: var(--bs-primary, #0d6efd);
  border-color: var(--bs-primary, #0d6efd);
}

.gantt-label .btn:hover,
.gantt-label .btn:focus {
  background: var(--bs-primary-bg-subtle, var(--bs-body-bg, var(--bs-secondary-bg)));
  color: var(--bs-emphasis-color, var(--bs-body-color));
}

.gantt-label .btn-outline-primary:hover,
.gantt-label .btn-outline-primary:focus {
  color: var(--bs-primary, #0d6efd);
}

.gantt-label .gantt-header-action {
  color: var(--bs-primary, #0d6efd);
  border: none;
}

.gantt-label .gantt-header-action i {
  color: inherit;
}

.gantt-label .gantt-header-action:hover,
.gantt-label .gantt-header-action:focus {
  color: var(--bs-primary, #0d6efd);
}

.gantt-zoom-controls {
  gap: 0.35rem;
}

.gantt-zoom-input {
  width: 88px;
}

.gantt-label-name {
  min-width: 0;
}

.gantt-label-title-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.gantt-grid.gantt-compact .gantt-label {
  padding: 0.5rem 0.65rem;
}

.gantt-label .gantt-type-icon,
.gantt-bar .gantt-type-icon {
  font-size: 0.8em;
}

.gantt-bar .task-type-request,
.gantt-bar .task-type-issue {
  color: currentColor;
}

.gantt-grid.gantt-compact .gantt-label-meta,
.gantt-grid.gantt-compact .gantt-label-actions,
.gantt-grid.gantt-compact .gantt-label .status-badge {
  display: none !important;
}

.gantt-timeline {
  overflow: hidden;
  position: relative;
}

.gantt-header .gantt-timeline {
  height: 100%;
}

.gantt-date-row {
  display: flex;
  gap: 0;
  position: relative;
  z-index: 1;
  background: var(--bs-secondary-bg, var(--bs-body-bg, #f8f9fa));
  border-radius: 0.5rem;
  height: 100%;
  align-items: flex-end;
  min-height: 72px;
}

.gantt-date-cell {
  min-width: var(--gantt-day-width, 64px);
  max-width: var(--gantt-day-width, 64px);
  flex: 0 0 var(--gantt-day-width, 64px);
  text-align: center;
  color: var(--bs-emphasis-color, var(--bs-body-color));
  border-bottom: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05));
  padding: 0.35rem 0.15rem 0.75rem;
  font-weight: 600;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
  transform: rotate(-45deg);
  transform-origin: left bottom;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.1;
  height: 68px;
}

.gantt-date-cell.gantt-date-past {
  background: transparent;
  color: var(--bs-body-color);
  opacity: 1;
}

.gantt-date-cell.gantt-date-today {
  background: transparent;
  border-bottom: none;
  color: var(--bs-primary, #0d6efd);
}

.gantt-row-timeline {
  position: relative;
  min-height: 56px;
  height: 100%;
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05));
  border-radius: 12px;
  background-image: linear-gradient(
    to right,
    var(--bs-border-color, rgba(255, 255, 255, 0.15)) 1px,
    transparent 1px
  );
  background-size: var(--gantt-day-width, 64px) 100%;
  background-color: var(--bs-secondary-bg, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.04));
  color: var(--bs-emphasis-color, var(--bs-body-color));
}

.gantt-grid.gantt-compact .gantt-row-timeline {
  min-height: 42px;
}

.gantt-bar {
  color: #fff;
  border: 1px solid rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.18);
  box-shadow: 0 8px 18px rgba(0, 0, 0, 0.18);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
  min-width: 0;
}

.gantt-bar {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  align-content: center;
  gap: 0.6rem;
  padding: 8px 12px;
  border-radius: 999px;
  color: #fff;
  box-shadow: 0 10px 22px rgba(0, 0, 0, 0.12);
  font-weight: 600;
}

.gantt-grid.gantt-compact .gantt-bar {
  padding: 6px 10px;
  gap: 0.45rem;
}

.gantt-bar .gantt-bar-dates {
  font-size: 0.85rem;
  opacity: 0.9;
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

.gantt-bar-title {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  max-width: 240px;
  align-self: center;
  min-width: 0;
}

.gantt-bar-title-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.gantt-bar-past {
  position: absolute;
  inset: 0 auto 0 0;
  background: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.12);
  border-radius: inherit;
  pointer-events: none;
}

.gantt-bar.status-todo {
  background: var(--bs-secondary, #6c757d);
}

.gantt-bar.status-inprogress {
  background: var(--bs-primary, #0d6efd);
}

.gantt-bar.status-testing {
  background: #6f42c1;
}

.gantt-bar.status-done {
  background: #198754;
}

.gantt-bar.status-cancelled {
  background: #fd7e14;
}

.gantt-past-overlay {
  position: absolute;
  inset: 0 auto 0 0;
  background: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.045);
  pointer-events: none;
  z-index: 0;
}

.gantt-today-line {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--bs-primary, #0d6efd);
  opacity: 0.7;
  z-index: 2;
  pointer-events: none;
}

.badge.bg-priority-high {
  background-color: #E53935;
  color: #fff;
}

.progress-bar.bg-priority-high {
  background-color: #E53935;
}

.badge.bg-priority-medium {
  background-color: #FFC107;
  color: #1f1f1f;
}

.progress-bar.bg-priority-medium {
  background-color: #FFC107;
}

.badge.bg-priority-low {
  background-color: #4CAF50;
  color: #fff;
}

.progress-bar.bg-priority-low {
  background-color: #4CAF50;
}

.filter-card-header {
  cursor: pointer;
}

.filter-action-btn i {
  margin-right: 0.2rem;
}

/* These read as a toolbar of actions sitting beside the pill toggles, so the
   link underline was just noise across the whole bar. The hover color change
   still marks them as clickable. */
.filter-action-btn,
.filter-action-btn:hover,
.filter-action-btn:focus,
.filter-action-btn:focus-visible {
  text-decoration: none;
}

/* "Clear all filters" is an ACTION, not a toggle, so it stays a link rather than
   joining the pills — a box would imply it has an on state. It sits muted at
   rest so the accent color means one thing in this bar: a filter is on. */
.filter-card-header .filter-action-btn {
  /* --bs-secondary-color is translucent on some themes and landed at 4.3:1. An
     action link has to be legible; fading the emphasis color keeps it secondary
     next to the bold labels without dropping below the threshold. Deliberately
     not `opacity`, which fades the element after the color is computed and so
     hides the real contrast from any audit. */
  color: rgba(var(--bs-emphasis-color-rgb, 33, 37, 41), 0.85);
}

.filter-card-header .filter-action-btn:hover,
.filter-card-header .filter-action-btn:focus-visible {
  color: var(--bs-primary, #0d6efd);
}

.current-user-avatar {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background-color: var(--bs-primary-bg-subtle);
  color: var(--bs-primary-text-emphasis);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  text-transform: uppercase;
  background-size: cover;
  background-position: center;
  border: 3px solid var(--bs-body-bg);
  box-shadow: 0 0 0 2px var(--bs-border-color-translucent, rgba(0, 0, 0, 0.12));
  background-clip: padding-box;
}

.current-user-avatar.avatar-sm {
  width: 32px;
  height: 32px;
  font-size: 0.85rem;
}

.current-user-avatar.avatar-initials {
  background-image: none;
}

.gantt-print-mode nav,
.gantt-print-mode #detailTabs,
.gantt-print-mode #boardFilters,
.gantt-print-mode #ganttFilters,
.gantt-print-mode #ganttFiltersHeader,
.gantt-print-mode .gantt-filters-card,
.gantt-print-mode #sharedFiltersCard,
.gantt-print-mode #detailActions,
.gantt-print-mode .navbar,
.gantt-print-mode #viewProjects,
.gantt-print-mode #viewProjectDetail > .d-flex:first-of-type {
  display: none !important;
}

.gantt-print-mode .gantt-grid::before {
  display: none;
}

.gantt-print-mode .gantt-label {
  display: none !important;
}

.gantt-print-mode .gantt-row {
  grid-template-columns: 0 1fr;
  page-break-inside: avoid;
}

.gantt-print-mode body,
.gantt-print-mode .gantt-board-wrapper,
.gantt-print-mode .gantt-grid {
  background: #fff;
  overflow: visible !important;
  height: auto !important;
  max-height: none !important;
}

.gantt-print-mode .gantt-scroll {
  overflow: visible !important;
  width: auto !important;
  min-width: 0 !important;
  height: auto !important;
}

.gantt-print-mode .gantt-board-wrapper {
  display: block;
}

.gantt-print-mode .gantt-grid {
  display: block;
}

.gantt-print-mode .gantt-row {
  break-inside: avoid;
}

.gantt-print-mode .gantt-date-cell {
  font-size: 8pt;
  transform: rotate(-45deg);
  transform-origin: 50% 100%;
  max-width: var(--gantt-day-width, 64px);
  flex: 0 0 var(--gantt-day-width, 64px);
  overflow: hidden;
  text-overflow: ellipsis;
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
  height: 50px;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  white-space: nowrap;
}

.modal-body {
  position: relative;
}

#taskModal .modal-dialog,
#viewTaskModal .modal-dialog {
  margin: 1rem auto;
  height: calc(100vh - 2rem);
  max-height: calc(100vh - 2rem);
  display: flex;
}

#taskModal .modal-content,
#viewTaskModal .modal-content {
  display: flex;
  flex-direction: column;
  max-height: 100%;
  height: 100%;
  min-height: 0;
}

#taskModal form,
#viewTaskModal form {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}

#taskModal .modal-header,
#taskModal .modal-footer,
#viewTaskModal .modal-header,
#viewTaskModal .modal-footer {
  flex-shrink: 0;
}

#taskModal .modal-header,
#viewTaskModal .modal-header {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bs-modal-bg);
  border-bottom: 1px solid var(--bs-border-color);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08);
}

#taskModal .modal-body,
#viewTaskModal .modal-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  width: 100%;
  margin-top: 1px;
  padding-top: var(--bs-modal-padding);
  padding-right: calc(var(--bs-modal-padding) + 1.25rem);
  padding-bottom: calc(var(--bs-modal-padding) + 0.75rem);
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  scrollbar-color: rgba(0, 0, 0, 0.45) rgba(0, 0, 0, 0.08);
}

#taskModal .modal-body::-webkit-scrollbar,
#viewTaskModal .modal-body::-webkit-scrollbar {
  width: 12px;
}

#taskModal .modal-body::-webkit-scrollbar-track,
#viewTaskModal .modal-body::-webkit-scrollbar-track {
  margin-top: 0;
  margin-bottom: 0;
  background-color: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.08);
  border-radius: 999px;
}

#taskModal .modal-body::-webkit-scrollbar-thumb,
#viewTaskModal .modal-body::-webkit-scrollbar-thumb {
  background-color: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.45);
  border-radius: 999px;
  border: 3px solid transparent;
}

#taskChatModal .modal-dialog {
  margin: 1rem auto;
  height: calc(100vh - 2rem);
  max-height: calc(100vh - 2rem);
  display: flex;
}

#taskChatModal .modal-content {
  display: flex;
  flex-direction: column;
  max-height: 100%;
  height: 100%;
  min-height: 0;
}

#taskChatModal form {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}

#taskChatModal .modal-header,
#taskChatModal .modal-footer {
  flex-shrink: 0;
}

#taskChatModal .modal-header {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bs-modal-bg);
  border-bottom: 1px solid var(--bs-border-color);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08);
}

#taskChatModal .modal-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  width: 100%;
  margin-top: 1px;
  padding-top: var(--bs-modal-padding);
  padding-right: calc(var(--bs-modal-padding) + 1.25rem);
  padding-bottom: calc(var(--bs-modal-padding) + 0.75rem);
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  scrollbar-color: rgba(0, 0, 0, 0.45) rgba(0, 0, 0, 0.08);
}

#taskChatModal .modal-body::-webkit-scrollbar {
  width: 12px;
}

#taskChatModal .modal-body::-webkit-scrollbar-track {
  margin-top: 0;
  margin-bottom: 0;
  background-color: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.08);
  border-radius: 999px;
}

#taskChatModal .modal-body::-webkit-scrollbar-thumb {
  background-color: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.45);
  border-radius: 999px;
  border: 3px solid transparent;
}

.modal-toast-container {
  position: absolute;
  top: 0.35rem;
  left: 0.5rem;
  right: 0.5rem;
  z-index: 1060;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.35rem;
}

.modal-toast-container .toast {
  pointer-events: auto;
  transition: opacity 1.2s ease;
}

.gantt-print-header {
  margin-bottom: 0.5rem;
}

.gantt-detail {
  grid-column: 1 / span 1;
  margin-top: -0.25rem;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.12));
  border-left: 4px solid var(--bs-primary, #0d6efd);
  background: var(--bs-body-bg, #fff);
  border-radius: 0.75rem;
  position: sticky;
  left: 0;
  z-index: 6;
  width: calc(var(--gantt-label-width, 320px));
  max-width: calc(var(--gantt-label-width, 320px));
  color: var(--bs-body-color, #212529);
  opacity: 1;
  visibility: visible;
}

.gantt-detail .text-muted,
.gantt-detail .text-secondary {
  color: var(--pm-muted-color);
  opacity: 0.9;
}

#kanbanBoard,
#homeKanbanBoard {
  min-height: 400px;
}

#kanbanBoard .col-md-3,
#homeKanbanBoard .col-md-3 {
  display: block;
  height: auto;
}

.kanban-tasks {
  padding-right: 4px;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

/* Lazy-load marker at the bottom of a column: more cards materialize as it
   scrolls into range (see attachKanbanLazyLoader). */
.kanban-scroll-sentinel {
  min-height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.25rem;
}

.board-section {
  display: block;
}

#tabBoard,
#tabGantt {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

#tabProperties {
  overflow: auto;
}

@media (max-width: 991px) {
  #kanbanBoard,
  #homeKanbanBoard {
    width: 100vw !important;
    max-width: 100vw !important;
    min-height: calc(100vh - 260px);
    margin-left: calc(50% - 50vw) !important;
    margin-right: calc(50% - 50vw) !important;
    padding: 0 0 1rem !important;
    gap: 0 !important;
    overflow-x: auto !important;
    overflow-y: hidden !important;
    scroll-snap-type: x mandatory !important;
    scroll-padding-left: 0;
    scroll-behavior: smooth;
    overscroll-behavior-x: contain;
    touch-action: pan-x;
  }

  #kanbanBoard > [class*='col-'],
  #homeKanbanBoard > [class*='col-'] {
    flex: 0 0 100vw !important;
    width: 100vw !important;
    min-width: 100vw !important;
    max-width: 100vw !important;
    scroll-snap-align: start;
    scroll-snap-stop: always;
    padding-left: 0.25rem;
    padding-right: 0.25rem;
  }

  .kanban-column {
    width: 100% !important;
    min-width: 100% !important;
    max-width: 100% !important;
    height: calc(100vh - 320px);
    min-height: 420px;
  }

  .kanban-tasks {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
    overflow-y: auto !important;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
  }
}

/* Adjacent-status arrows on task cards: only useful when the board shows a
   single status column at a time (the <=991px snap-scroll mode above), so they
   stay hidden on wider layouts where columns sit side by side. */
.task-status-arrows {
  display: none;
}

@media (max-width: 991px) {
  #kanbanBoard .task-status-arrows {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.5rem;
  }

  #kanbanBoard .task-status-arrow {
    max-width: 48%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

.kanban-board-wrapper {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.filter-row-gap {
  row-gap: 0.5rem;
}

.filter-dates-col,
.filter-title-col {
  min-width: 180px;
}

.users-pane {
  gap: 0.5rem;
}

.scroll-pane {
  overflow-y: auto;
}

.scroll-pane-sm {
  overflow-y: auto;
}

.tab-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.tab-content > .tab-pane {
  display: none !important;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.tab-content > .tab-pane.active,
.tab-content > .tab-pane.show {
  display: flex !important;
  flex-direction: column;
}

#viewProjectDetail .tab-content {
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  overflow-anchor: none;
  padding-bottom: 1rem;
}

#viewProjectDetail #tabBoard,
#viewProjectDetail #tabGantt,
#viewProjectDetail #tabAttachments {
  flex: 0 0 auto;
  overflow: visible;
}

.tab-pane:not(.active):not(.show) .kanban-board-wrapper,
.tab-pane:not(.active):not(.show) .gantt-board-wrapper {
  display: none !important;
}

.admin-user-list {
  max-height: 260px;
  overflow-y: auto;
}

.domain-loading {
  position: relative;
  z-index: 10;
}

.startup-loading {
  position: relative;
  z-index: 11;
}

.back-link-small {
  font-size: 0.7rem;
}

.screenshot-overlay {
  position: fixed;
  inset: 0;
  background: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.6);
  backdrop-filter: blur(2px);
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
}

.screenshot-stage {
  position: relative;
  max-width: 100vw;
  max-height: 100vh;
}

.screenshot-img {
  display: block;
  max-width: 100vw;
  max-height: 100vh;
}

.screenshot-selection {
  position: fixed;
  border: 2px dashed var(--bs-primary, #0d6efd);
  background: rgba(13, 110, 253, 0.15);
  pointer-events: none;
}

.screenshot-instructions {
  position: fixed;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.7);
  color: #fff;
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 0.9rem;
  z-index: 2002;
}

.screenshot-cancel {
  position: fixed;
  top: 12px;
  right: 12px;
  z-index: 2002;
}

.task-chat-btn,
.task-history-btn {
  color: var(--bs-link-color, #0d6efd);
}

.task-chat-btn:hover,
.task-chat-btn:focus,
.task-history-btn:hover,
.task-history-btn:focus {
  color: var(--bs-link-hover-color, #0a58ca);
  text-decoration: none;
}

.task-chat-editor {
  min-height: 200px;
  overflow-y: auto;
  background: var(--bs-body-bg, #fff);
}

.task-chat-editor:focus {
  outline: none;
  box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25);
}

.chat-editor-toolbar {
  margin-bottom: 0.5rem;
}


.task-chat-attachment {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--bs-border-color, #dee2e6);
  border-radius: 0.5rem;
  background: var(--bs-body-bg, #fff);
  color: var(--bs-body-color, #212529);
}

.task-chat-attachment + .task-chat-attachment {
  margin-top: 0.4rem;
}

.db-save-status-text {
  font-weight: 600;
}

.history-table-wrapper {
  max-height: 60vh;
  overflow: auto;
}

.history-table th.history-sortable {
  cursor: pointer;
  user-select: none;
}

.history-table th.history-sortable i {
  margin-left: 0.35rem;
  opacity: 0.6;
}

.history-details .history-change {
  font-size: 0.85rem;
}

.history-details .history-change + .history-change {
  margin-top: 0.25rem;
}

/* ============================================================
   Mobile phone refinements (<= 576px). Purely additive: the
   desktop layout and the existing <= 991px tablet rules above are
   left untouched. Focus is touch ergonomics, the iOS input-zoom
   issue, dense-row tap sizing and overflow safety -- the broad
   layout reflow (kanban carousel, detail/calendar reflow, body
   scroll) is already handled at <= 991px.
   ============================================================ */
@media (max-width: 576px) {
  /* iOS Safari auto-zooms when focusing any control whose font is
     < 16px; this stops that jump and enlarges the tap area. */
  .form-control,
  .form-select,
  textarea.form-control {
    font-size: 16px;
    min-height: 42px;
  }

  /* Finger-friendly nav, dropdown and actionable list rows. */
  .nav-link,
  .dropdown-item,
  .list-group-item-action {
    min-height: 42px;
    display: flex;
    align-items: center;
  }

  .dropdown-menu {
    font-size: 1rem;
  }

  /* Comfortable tap height for standard buttons; compact .btn-sm
     (used in dense action rows) and the modal close keep their size. */
  .btn:not(.btn-sm):not(.btn-close):not(.btn-link) {
    min-height: 42px;
  }

  /* Momentum scrolling for any horizontally scrollable table. */
  .table-responsive {
    -webkit-overflow-scrolling: touch;
  }

  /* Long unbreakable strings (URLs, ids) in notes/history must wrap
     rather than force horizontal page overflow. */
  .note-entry,
  .note-entry *,
  .history-details {
    overflow-wrap: anywhere;
    word-break: break-word;
  }

  /* Reclaim a little horizontal space on narrow screens. */
  .view-panel {
    padding-left: 0.15rem;
    padding-right: 0.15rem;
  }
}

/* ============================================================
   Mobile UX fixes — Phase 1 (scrolling, filters, container heights).
   Calendar/attachments "scroll within a taller container" applies on all
   sizes (per request); the touch/filter/kanban rules are scoped to phones
   and tablets (<= 991px).
   ============================================================ */

/* Calendar grid cells: show every task and scroll within the cell instead of
   truncating to "+N more". Pairs with the renderer change that stops capping. */
.calendar-day-cell {
  max-height: 264px;
}
.calendar-day-tasks {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
.calendar-year-task-list {
  max-height: 220px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* Attachments: a taller table whose rows scroll within the container. */
#projectAttachmentsPanel .table-responsive {
  max-height: 65vh;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
}

@media (max-width: 991px) {
  /* The filter body kept its desktop max-height on phones, so expanded options
     spilled past it and the cards painted over them, and its inner scroll was
     hard to touch. Let it size to content and scroll with the page. */
  .filter-card .card-body {
    max-height: none !important;
    overflow: visible !important;
    overscroll-behavior: auto;
  }

  /* Keep the filter expand/collapse toggle reachable even when the label and
     "Clear all filters" button are wide. */
  .filter-card-header {
    flex-wrap: nowrap;
    gap: 0.5rem;
  }
  .filter-card-header > div:first-child {
    min-width: 0;
  }
  .filter-card-header .filter-action-btn {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .filter-card-header .section-toggle-btn {
    flex: 0 0 auto;
  }

  /* Detail tab content was a contained nested scroller that only responded to
     the scrollbar edge on touch; make single-finger vertical scrolling work. */
  #viewProjectDetail .tab-content {
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: auto;
    touch-action: pan-y;
  }

  /* The dashboard's horizontal scroll captured vertical touch panning. */
  .project-dashboard {
    overflow-x: visible;
  }

  /* Taller kanban columns so more than a couple of cards show before the
     column scrolls. dvh handles the mobile URL bar; vh/min-height are the
     fallback for older browsers. */
  .kanban-column {
    height: calc(100dvh - 220px) !important;
    min-height: 60vh !important;
  }
}

/* ============================================================
   Phase 2 — calendar navigation: Day view, drill-down links,
   sticky view/date header, and timeline labels that follow the
   visible portion of a multi-day bar.
   ============================================================ */

/* (The .calendar-toolbar is already position:sticky; grid views now keep it
   put because the grid scrolls inside .calendar-grid-scroll, not the shell.) */

/* Day view: a simple scrollable agenda of the day's tasks. */
.calendar-day-agenda {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 0.5rem 0.15rem;
}

/* Clickable day number (-> Day view) styled as a plain bold number. */
.calendar-day-number {
  color: inherit;
  text-decoration: none;
  font-weight: 800;
  line-height: 1;
}
.calendar-day-number:hover,
.calendar-day-number:focus {
  text-decoration: underline;
  color: var(--bs-primary, #0d6efd);
}

/* Small per-week jump (-> Week view) on the first day of each week. */
.calendar-week-link {
  color: var(--pm-muted-color);
  text-decoration: none;
  font-size: 0.7rem;
  line-height: 1;
}
.calendar-week-link:hover,
.calendar-week-link:focus {
  color: var(--bs-primary, #0d6efd);
}

/* Year month header is now a button (-> Month view); strip button chrome. */
.calendar-year-month-link {
  width: 100%;
  border: 0;
  background: transparent;
  padding: 0;
  color: inherit;
  cursor: pointer;
}
.calendar-year-month-link:hover .badge,
.calendar-year-month-link:focus .badge {
  text-decoration: none;
}
.calendar-year-month-link:hover span:first-child,
.calendar-year-month-link:focus span:first-child {
  text-decoration: underline;
}

/* Timeline: pin each multi-day bar's label to the visible left edge so the
   task title/dates stay readable without scrolling back to the bar's start.
   Sticky clamps the label within the bar, so it never escapes the bar. */
.calendar-timeline-task-pill {
  position: relative;
  padding-left: 0.7rem;
  padding-right: 0.7rem;
}
/* Pin the label group (icon, title, project and date range — all now inside
   .gantt-bar-title) to the visible left edge so it follows the bar as you
   scroll, with a little breathing room on each side. */
.calendar-timeline-task-pill .gantt-bar-title {
  position: sticky;
  left: 0.7rem;
  padding-right: 0.35rem;
  align-self: flex-start;
}
/* Top row: task-type icon + date range share a line so the dates don't take a
   separate vertical line (saves space, especially on mobile). */
.calendar-timeline-task-pill .gantt-bar-titlehead {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  max-width: 100%;
}

/* Per-column kanban sort controls (status column headers): a compact date-field
   select + an asc/desc toggle. The select must not stretch to fill the header. */
.kanban-sort-controls .kanban-sort-field {
  width: auto;
  min-width: 4.4rem;
  flex: 0 0 auto;
  padding-top: 0.1rem;
  padding-bottom: 0.1rem;
}
.kanban-sort-controls .kanban-sort-dir {
  flex: 0 0 auto;
  padding-top: 0.1rem;
  padding-bottom: 0.1rem;
}

/* ============================================================
   Calendar "List" layout — a date/month-grouped agenda toggled from the
   calendar toolbar (Calendar | List). Mirrors the calendar pill content.
   ============================================================ */
.calendar-list {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.25rem 0.15rem 0.75rem;
}
.calendar-list-group {
  display: flex;
  flex-direction: column;
}
.calendar-list-group-header {
  display: block;
  width: 100%;
  text-align: left;
  border: 0;
  border-bottom: 1px solid var(--bs-border-color-translucent, rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.12));
  background: transparent;
  font-weight: 800;
  padding: 0.55rem 0.25rem 0.3rem;
  margin-top: 0.4rem;
  color: var(--bs-emphasis-color, var(--bs-body-color));
  cursor: pointer;
}
.calendar-list-group-header:hover,
.calendar-list-group-header:focus {
  color: var(--bs-primary, #0d6efd);
  text-decoration: underline;
}
.calendar-list-row {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.4rem 0.55rem;
  border-left: 4px solid var(--calendar-task-color, var(--bs-primary, #0d6efd));
  border-radius: 0.35rem;
  background: color-mix(in srgb, var(--calendar-task-color, #0d6efd) 7%, var(--bs-body-bg, #fff));
}
.calendar-list-row + .calendar-list-row {
  margin-top: 0.2rem;
}
.calendar-list-row:hover {
  background: color-mix(in srgb, var(--calendar-task-color, #0d6efd) 15%, var(--bs-body-bg, #fff));
}
.calendar-list-range {
  flex: 0 0 auto;
  min-width: 9.5rem;
  color: var(--pm-muted-color);
  font-size: 0.85rem;
}
.calendar-list-main {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
  min-width: 0;
}
.calendar-list-title {
  border: 0;
  background: transparent;
  padding: 0;
  font-weight: 700;
  color: var(--bs-link-color, #0d6efd);
  cursor: pointer;
  text-align: left;
}
.calendar-list-title:hover,
.calendar-list-title:focus {
  text-decoration: underline;
}
.calendar-list-project {
  color: var(--pm-muted-color);
  font-size: 0.85rem;
}
@media (max-width: 576px) {
  .calendar-list-row {
    flex-direction: column;
    gap: 0.15rem;
  }
  .calendar-list-range {
    min-width: 0;
    font-size: 0.78rem;
  }
}

/* ===== Home Dashboard View (cross-project main-page view) ===== */
/* Project link on global-board task cards: keep it one quiet line under the
   title, truncating long project names. */
.task-card-project-link {
  min-width: 0;
  display: flex;
  align-items: center;
}
.task-card-project-link .task-card-project-btn {
  font-size: 0.8rem;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Project link inside the global dashboard widgets' task rows. */
.dashboard-task-meta .dashboard-task-project-link {
  font-size: 0.8rem;
  max-width: 12rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Status mix (Home Dashboard View): one legible row per status — swatch, name,
   count — scrolling inside the widget when the union is long. */
.homedash-status-mix {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  max-height: 13rem;
  overflow-y: auto;
  padding-right: 0.25rem;
}
.homedash-status-mix-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
}
.homedash-status-mix-row .status-mix-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.status-mix-swatch {
  flex: 0 0 auto;
  width: 0.8rem;
  height: 0.8rem;
  border-radius: 0.2rem;
  border: 1px solid rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.15);
}

/* Completion widget: completed of total per task type, one row each (2026-09-15). */
.dashboard-completion-types {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  max-height: 10.5rem;
  overflow-y: auto;
  padding-right: 0.25rem;
}
.dashboard-completion-type-row {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  min-width: 0;
}
.dashboard-completion-type-row .completion-type-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dashboard-completion-type-row .completion-type-count {
  flex: 0 0 auto;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
/* Counts at the row's own size, so seven or eight types fit before the list scrolls. */
.dashboard-completion-type-row .dashboard-metric-link {
  font-size: inherit;
  line-height: 1.25;
  vertical-align: baseline;
}

/* Projects widget: expandable per-status project lists. */
.homedash-proj-status-list {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15rem;
  padding-left: 1.4rem;
  margin-top: 0.15rem;
}
.homedash-proj-status-list .btn {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: left;
}

/* Sortable attachment table headers (detail + Home Dashboard View tabs). */
.attachment-sort-th {
  cursor: pointer;
  white-space: nowrap;
  user-select: none;
}
.attachment-sort-th:hover {
  text-decoration: underline;
}

/* Wide layout: each column scrolls its own cards under a fixed status header,
   instead of the whole page scrolling. The Filters card scrolls away with the
   detail tab; the board is one scrollport-tall sticky block, so once the filters
   pass above it the board pins to the top and its columns take over scrolling.
   Scoped to #kanbanBoard + a min-width query so the Home Dashboard View board and
   the <=991px snap view keep their own behavior. */
@media (min-width: 992px) {
  /* Keep its natural height so it can scroll off the top instead of being
     squeezed — an expanded filter panel no longer steals board height. */
  #viewProjectDetail #sharedFiltersCard {
    flex: 0 0 auto;
  }
  /* One scrollport tall (flex-basis 100% of the detail tab) and sticky, so it
     fills the viewport once the filters scroll past above it. */
  #viewProjectDetail #tabBoard {
    flex: 0 0 100%;
    min-height: 0;
    overflow: hidden;
    position: sticky;
    top: 0;
  }
  #viewProjectDetail #tabBoard .kanban-board-wrapper {
    min-height: 0;
  }
  #kanbanBoard {
    align-items: stretch;
    overflow-y: hidden;
  }
  #kanbanBoard > [class*='col-'] {
    display: flex;
    height: auto;
    min-height: 0;
  }
  #kanbanBoard .kanban-column {
    height: 100%;
    min-height: 0;
  }
  #kanbanBoard .kanban-tasks {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
  }
}

/* ===== Home page shell + Dashboard View panes + Calendar (wide screens) =====
   The home page is a flex COLUMN: the List/Dashboard toggle is a fixed header
   that never scrolls, and whichever view is active (#homeListView or
   #homeDashView) fills the rest and scrolls INSIDE itself. Because the chrome
   lives in the flex header (not sticky over a scrolling document), nothing ever
   scrolls behind it — so there is no bleed-through and no hand-tuned sticky
   offsets. Within Dashboard View the tabs + filters are a fixed sub-header and
   the active pane (widgets / board / calendar) is the inner scroller, which also
   gives the calendar a real bounded height so the Week view fills. */
@media (min-width: 992px) {
  /* Home page: non-scrolling flex column; the active view scrolls, not this. */
  #viewProjects {
    overflow: hidden;
  }
  #viewProjects > #homeViewToggleWrap {
    flex: 0 0 auto;
  }
  #viewProjects > #homeListView {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    padding-right: 0.25rem;
  }
  /* Each section keeps its natural height so the collapsed bars stay readable and
     an expanded section shows in full; the list scrolls as a whole. Without this,
     .section-card { overflow: hidden } gives every card an automatic min-height of
     0, so flex squeezes them all to fit instead of scrolling. */
  #viewProjects > #homeListView > * {
    flex: 0 0 auto;
  }
  #viewProjects > #homeDashView {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }

  /* Dashboard View sub-header (tabs + filters) stays put; the pane scrolls. */
  #homeDashView > #homeDashTabs,
  #homeDashView > #homeDashFiltersCard {
    flex: 0 0 auto;
  }
  #homeDashView > .tab-content {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  /* Widgets pane scrolls vertically inside the bounded area. (Attachments keeps
     the base overflow:hidden and scrolls its inner table instead — see below.) */
  #homeDashView #homeDashTabDashboard {
    overflow-y: auto;
    overflow-x: hidden;
  }

  /* --- Tasks board: fill the pane, scroll each status column independently. --- */
  #homeDashView #homeDashTabTasks .kanban-board-wrapper {
    height: 100%;
    min-height: 0;
    overflow: hidden;
  }
  #homeKanbanBoard {
    align-items: stretch;
    overflow-y: hidden;
  }
  #homeKanbanBoard > [class*='col-'] {
    display: flex;
    height: auto;
    min-height: 0;
  }
  #homeKanbanBoard .kanban-column {
    height: 100%;
    min-height: 0;
  }
  #homeKanbanBoard .kanban-tasks {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
  }

  /* --- Calendar pane fills; #homeDashCalendar is the flex chain to the grid. --- */
  #homeDashView #homeDashTabCalendar {
    overflow: hidden;
  }
  #homeDashCalendar {
    height: 100%;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  /* --- Project detail Calendar tab: sticks under the detail page tabs and fills
     one scrollport (same pattern the board already uses). #ganttGrid is
     display:block in calendar mode, so make it a flex-column fill. --- */
  #viewProjectDetail #tabGantt {
    flex: 0 0 100%;
    min-height: 0;
    overflow: hidden;
    position: sticky;
    top: 0;
  }
  #viewProjectDetail #tabGantt .gantt-board-wrapper {
    height: 100%;
    min-height: 0;
  }
  #viewProjectDetail #tabGantt #ganttGrid.calendar-grid-mode {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    height: 100%;
  }

  /* --- Shared calendar internals (project #tabGantt + home #homeDashCalendar):
     shell fills, the options bar sits at the top of the bounded area (below the
     page tabs), the grid scrolls beneath it, headers pin, and Week fills. --- */
  #viewProjectDetail #tabGantt .calendar-view-shell,
  #homeDashCalendar .calendar-view-shell {
    flex: 1 1 auto;
    min-height: 0;
    height: 100%;
  }
  #viewProjectDetail #tabGantt .calendar-toolbar,
  #homeDashCalendar .calendar-toolbar {
    position: static;
    flex: 0 0 auto;
  }
  #viewProjectDetail #tabGantt .calendar-grid-scroll,
  #homeDashCalendar .calendar-grid-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
  }
  /* Grid-view column headers (SUN..SAT) pin to the top of the scrolling grid. */
  #viewProjectDetail #tabGantt .calendar-grid-scroll .calendar-weekday,
  #homeDashCalendar .calendar-grid-scroll .calendar-weekday {
    position: sticky;
    top: 0;
    z-index: 4;
    background: var(--bs-body-bg, #fff);
    box-shadow: 0 1px 0 var(--bs-border-color-translucent, rgba(0, 0, 0, 0.12));
  }
  /* Timeline-view date header row pins to the top of the scrolling grid too. */
  #viewProjectDetail #tabGantt .gantt-header,
  #homeDashCalendar .gantt-header {
    position: sticky;
    top: 0;
    z-index: 4;
    background: var(--bs-body-bg, #fff);
  }
  /* Week view: the day boxes fill the remaining vertical space (header row auto,
     day-cell row stretches). Other grid views keep their fixed cell heights. */
  #viewProjectDetail #tabGantt .calendar-day-grid-week,
  #homeDashCalendar .calendar-day-grid-week {
    height: 100%;
    grid-template-rows: auto minmax(0, 1fr);
  }
  #viewProjectDetail #tabGantt .calendar-day-grid-week .calendar-day-cell,
  #homeDashCalendar .calendar-day-grid-week .calendar-day-cell {
    min-height: 0;
    /* Lift the shared .calendar-day-cell { max-height: 264px } cap so a Week cell
       can grow into its 1fr grid row; .calendar-day-tasks still scrolls inside. */
    max-height: none;
    height: 100%;
  }

  /* Day view is an agenda list appended straight into the shell (no grid-scroll
     wrapper), so give it its own fill + scroll or it clips at the pane edge. */
  #viewProjectDetail #tabGantt .calendar-day-agenda,
  #homeDashCalendar .calendar-day-agenda {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
  }
  /* List layout: the toolbar stays, the grouped list scrolls. */
  #viewProjectDetail #tabGantt .calendar-list-shell .calendar-list,
  #homeDashCalendar .calendar-list-shell .calendar-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
  }

  /* --- Home Dashboard View Attachments: pin the name filter + sortable column
     headers; only the attachment rows scroll. --- */
  #homeDashView #homeDashTabAttachments > .d-flex {
    flex: 0 0 auto;
  }
  #homeDashView #homeDashAttachmentsPanel {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }
  #homeDashView #homeDashAttachmentsPanel .table-responsive {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
  }
  #homeDashView #homeDashAttachmentsPanel thead th {
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--bs-body-bg, #fff);
    box-shadow: 0 1px 0 var(--bs-border-color-translucent, rgba(0, 0, 0, 0.12));
  }
}

/* Required-field marker on the project Details form. applyTemplateModeUI() hides
   these in template mode — a template deliberately allows blanks, so the asterisk
   must not claim otherwise. */
.required-marker {
  margin-left: 0.15rem;
  font-weight: 700;
  line-height: 1;
}

/* ---- Consolidated home filter panel --------------------------------------
   Two collapsed groups, and inside each a chip per field. A chip carries its
   own value so the filter is readable without opening anything; the control
   only exists in the DOM while the field is open. */
.home-filter-group + .home-filter-group {
  margin-top: 0.35rem;
}

.home-filter-group-toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.3rem 0.25rem;
  background: none;
  border: 0;
  border-radius: 0.35rem;
  text-align: left;
  color: inherit;
}

.home-filter-group-toggle:hover {
  background-color: rgba(var(--bs-emphasis-color-rgb, 0, 0, 0), 0.05);
}

.home-filter-group-caret {
  width: 0.75rem;
  font-size: 0.75rem;
  opacity: 0.7;
}

.home-filter-group-body {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 0.35rem 0 0.15rem 1.25rem;
}

/* A closed field is chip-sized; an open one grows to its control's width. */
.home-filter-field {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  max-width: 100%;
}

.home-filter-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 0.35rem;
  max-width: 100%;
  padding: 0.2rem 0.6rem;
  font-size: 0.8125rem;
  line-height: 1.35;
  background: none;
  border: 1px dashed var(--bs-border-color);
  border-radius: 999px;
  color: inherit;
}

.home-filter-chip:hover {
  border-style: solid;
  background-color: rgba(var(--bs-primary-rgb), 0.06);
}

.home-filter-chip.active {
  border-style: solid;
  border-color: rgba(var(--bs-primary-rgb), 0.55);
  background-color: rgba(var(--bs-primary-rgb), 0.1);
  font-weight: 600;
}

.home-filter-chip-value {
  max-width: 12rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  opacity: 0.85;
  font-weight: 400;
}

.home-filter-chip-caret {
  font-size: 0.6875rem;
  opacity: 0.6;
}

/* The clear affordance sits on the chip rather than inside the control, so an
   active filter can be dropped without opening it. */
.home-filter-chip-clear {
  position: absolute;
  top: -0.35rem;
  right: -0.35rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.1rem;
  height: 1.1rem;
  padding: 0;
  font-size: 0.625rem;
  line-height: 1;
  border: 1px solid var(--bs-border-color);
  border-radius: 50%;
  background-color: var(--bs-body-bg);
  color: var(--bs-danger);
}

.home-filter-control {
  min-width: 0;
}

.home-filter-preset-row {
  padding-bottom: 0.35rem;
  border-bottom: 1px solid var(--bs-border-color-translucent);
}

/* ---- Filter bar toggles ---------------------------------------------------
   One shape for every on/off filter in the home filter bar: icon + label in a
   pill, muted while off, accented while on. Previously these were three
   different controls — two bare text links, a btn-outline-warning and a form
   switch — which is what made the row read as unrelated widgets.

   The outline-warning one was worse than inconsistent: a Bootstrap outline
   button paints its color whether or not it is pressed, so "Favorites only"
   looked switched on at all times. Off is now unmistakably neutral.

   The icon never changes between states. State is carried by the pill, so a
   swapping icon is a second signal saying the same thing, and it made the row
   twitch as labels changed width. */
.filter-toggle {
  --filter-toggle-accent: var(--bs-primary, #0d6efd);
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.2rem 0.7rem;
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap;
  /* Not --bs-secondary-color: several themes define it as a low-contrast
     translucent gray (Lux resolves it to rgba(73,80,87,.75), which lands under
     4.5:1). Fading the emphasis color keeps "muted" while staying legible,
     because emphasis flips with the color mode. */
  color: rgba(var(--bs-emphasis-color-rgb, 33, 37, 41), 0.82);
  background: none;
  border: 1px solid var(--bs-border-color, #dee2e6);
  border-radius: 999px;
  transition: none;
}

.filter-toggle i {
  font-size: 0.8125rem;
  pointer-events: none;
}

.filter-toggle:hover:not(.active),
.filter-toggle:focus-visible:not(.active) {
  color: var(--filter-toggle-accent);
  border-color: var(--filter-toggle-accent);
  background-color: rgba(var(--bs-primary-rgb, 13, 110, 253), 0.06);
}

.filter-toggle.active {
  color: var(--filter-toggle-accent);
  border-color: var(--filter-toggle-accent);
  background-color: rgba(var(--bs-primary-rgb, 13, 110, 253), 0.12);
  font-weight: 600;
}

.filter-toggle:focus-visible {
  outline: 2px solid rgba(var(--bs-primary-rgb, 13, 110, 253), 0.4);
  outline-offset: 1px;
}

/* Filter options: ONE set of stateful toggle buttons. At >=992px the "dropdown"
   is just an inline row (the menu is forced open + unstyled, and the toggle button
   is d-lg-none), so it looks exactly like before. Below 992px (phone/small) it
   collapses into a real "Filter options" dropdown to save horizontal space —
   mirroring the Functions dropdown. */
@media (min-width: 992px) {
  .filter-options-menu.dropdown-menu {
    display: flex !important;
    position: static !important;
    inset: auto !important;
    transform: none !important;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    box-shadow: none;
    min-width: 0;
    float: none;
  }
}
@media (max-width: 991px) {
  .filter-options-menu.dropdown-menu {
    display: none;
    flex-direction: column;
    gap: 0.35rem;
    padding: 0.4rem;
    max-height: 70vh;
    overflow-y: auto;
  }
  .filter-options-menu.dropdown-menu.show {
    display: flex;
  }
  .filter-options-menu > * {
    width: 100%;
    justify-content: flex-start;
  }
  /* The active-filters badge already lives beside the "Filters" label, so the
     collapsed toggle needs no count of its own. */
}

/* The view-header collapse arrows (project detail + home List/Dashboard) are a
   phone-only space saver: at >=992px there is room for the full header, so hide the
   toggles (renderer keeps the headers expanded there too — viewHeaderCollapsedEffective). */
@media (min-width: 992px) {
  #detailHeaderToggleBtn,
  #homeHeaderToggleBtn {
    display: none !important;
  }
}

/* The project title, status badge and action buttons ride ONE no-wrap row: on
   desktop it fills the header after the Back button; on a phone (after the full-width
   Back + Collapse bars) it is its own full-width row and the title truncates rather
   than pushing the badge/actions onto extra rows. */
.detail-title-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: 1 1 auto;
  min-width: 0;
}
.detail-title-row #detailTitle {
  min-width: 0;
}

/* Phone (<992px) header + filter-bar spacing (per the *-Responsive.png mockups).
   Positioning only — no functionality change. */
@media (max-width: 991px) {
  /* Collapse-header arrows and the project "Back" become full-width bars on their
     own row, instead of small left-aligned buttons. */
  #homeHeaderBar { flex-wrap: wrap; }
  #homeHeaderToggleBtn,
  #detailHeaderToggleBtn,
  #backToProjectsBtn { width: 100%; }
  /* Home view-mode toggle (Dashboard / List View) spans the full width, split evenly. */
  #homeViewToggleWrap { width: 100%; }
  #homeViewToggleWrap > .btn { flex: 1 1 0; }
  /* The create actions (New Project / New Task) sit on the same bar and take the
     same treatment — a full-width row of their own, split evenly, rather than two
     small buttons stranded at the right edge under the toggle. */
  #homeHeaderActions { width: 100%; }
  #homeHeaderActions > .btn { flex: 1 1 0; }
  /* Project filter bar: the search box + expand arrow take their own full row, the
     search grows to fill, and the arrow is pinned to the right. */
  .shared-filters-search-row { width: 100%; }
  .shared-filters-search-row .task-quick-search {
    flex: 1 1 auto;
    max-width: none !important;
  }
}

/* Collapsible view headers. The bar itself is deliberately minimal — it is
   present on every screen size but must cost almost no vertical space, since the
   whole point is to give that space back to the data. */
.view-header-bar {
  min-height: 1.75rem;
  margin-bottom: 0.5rem;
}

.view-header-bar-title {
  font-size: 0.95rem;
  min-width: 0;
}

/* The project title shares its row with the action buttons. It is the only
   elastic thing there, so it yields (and ellipsizes) rather than pushing the
   buttons onto a second row — which is the row this layout exists to remove. */
.detail-title {
  min-width: 4rem;
  flex: 0 1 auto;
}

#detailActionsWrap {
  flex-shrink: 0;
}

/* HubSpot link on HubSpot-imported task cards: brand orange, darker on hover.
   Contrast holds on every Bootswatch card background (white ≈ 2.9:1 for an icon,
   dark themes ≈ 5.6:1); the hover shade lifts it to ≈ 4:1 on white. */
a.hs-task-link,
a.hs-task-link:visited { color: #ff7a59; }
a.hs-task-link:hover,
a.hs-task-link:focus { color: #d94f2d; }

/* Home Filters panel: the row above each multi-select (Task Status's "Select all /
   Reset to default" links; an empty placeholder on the other fields) has one fixed
   height so every list box starts level. */
.home-filter-actions { min-height: 1.75rem; }

/* Project identifier chips (List View cards): HubSpot deal / Comsense / cERP
   contract as one compact line; links and the copy button sit inline with text. */
.project-card-ids {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.1rem 0.25rem;
}
.project-id-chip {
  white-space: nowrap;
  text-decoration: none;
}
.project-id-chip.btn-link {
  font-size: inherit;
  line-height: inherit;
  vertical-align: baseline;
  border: 0;
}

/* Action buttons never wrap their labels — the title is the elastic element, and
   updateDetailActionsLayout() measures against the buttons' one-line widths. */
#detailActionsFull .btn,
#detailActionsCompact .btn {
  white-space: nowrap;
}

.view-header-toggle {
  flex-shrink: 0;
  line-height: 1;
}

/* ---- Language selector (shared/i18n.js mountSelector) ---------------------
   One compact button showing the active language code, opening a "Choose
   language" menu. Two homes: the internal app's branded navbar and the external
   watcher page's dark header — hence the -navbar variant, which takes its color
   from whatever bar it sits on instead of hardcoding light-on-dark. The app's
   navbar flips between light and dark text per theme (syncNavbarContrast), so
   the button follows currentColor rather than picking a color of its own. */
.pm-lang-select .pm-lang-toggle {
  font-weight: 700;
  letter-spacing: 0.04em;
  min-width: 2.75rem;
}
.pm-lang-toggle-navbar {
  color: var(--bs-navbar-brand-color, #fff);
  border: 1px solid currentColor;
  background-color: transparent;
}
.pm-lang-toggle-navbar:hover,
.pm-lang-toggle-navbar:focus,
.pm-lang-toggle-navbar.show {
  color: var(--bs-navbar-brand-color, #fff);
  background-color: rgba(127, 127, 127, 0.25);
}
.pm-lang-menu {
  min-width: 13rem;
}
.pm-lang-menu .dropdown-header {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.72rem;
  font-weight: 700;
}
/* The check column is reserved on every row (.invisible, not removed) so the
   language names stay left-aligned as the selection moves between them. */
.pm-lang-menu .pm-lang-check {
  font-size: 0.8em;
}
/* The selected language is marked by weight + the check only. Bootstrap's
   .active fill is deliberately not used: on a two-row menu a solid blue row
   reads as "hovered", which is exactly the wrong signal on the row you are
   already on. Hover keeps Bootstrap's own treatment, so the two never collide. */
.pm-lang-menu .pm-lang-option[aria-current="true"] {
  color: var(--bs-emphasis-color, inherit);
}

/* Checklist item translation line (the checklist editor's "Show Spanish").
   Sits under its item and indents to the text column so it reads as belonging to
   the row above rather than as another item. */
.task-checklist-translation {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0.15rem 0 0.45rem 3.25rem;
}
.task-checklist-translation .badge {
  flex-shrink: 0;
  font-weight: 600;
}
