﻿:root {
    --mb-sidebar-width: 240px;
    --mb-sidebar-collapsed-width: 64px;

    --mb-bg: #f8fafc;
    --mb-surface: #ffffff;
    --mb-text: #1e293b;
    --mb-text-muted: #64748b;
    --mb-border: #e2e8f0;
    --mb-stripe-bg: #fbfcfd;
    --mb-placeholder: #b6bfca;

    --mb-accent: #4f46e5;
    --mb-accent-hover: #4338ca;
    --mb-accent-soft: #eef2ff;

    --mb-emerald: #04815a;
    --mb-emerald-soft: #ecfdf5;
    --mb-amber: #ac5f05;
    --mb-amber-soft: #fffbeb;
    --mb-sky: #0277b3;
    --mb-sky-soft: #f0f9ff;
    --mb-rose: #d71c45;
    --mb-rose-soft: #fff1f2;
    --mb-violet: #7c3aed;
    --mb-violet-soft: #f5f3ff;

    --mb-sidebar-bg: #fbfcfe;
    --mb-sidebar-text: #475569;
    --mb-sidebar-text-muted: #94a3b8;
    --mb-sidebar-active-bg: var(--mb-accent-soft);
    --mb-sidebar-active-text: var(--mb-accent);

    --mb-radius-sm: 6px;
    --mb-radius: 10px;
    --mb-radius-lg: 14px;

    --mb-shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.06);
    --mb-shadow: 0 1px 2px rgba(16, 24, 40, 0.06), 0 1px 3px rgba(16, 24, 40, 0.1);

    /* Display face: a slab-leaning serif for page titles only, evoking a stamped ledger header. */
    --mb-font-display: Cambria, "Hoefler Text", Georgia, "Times New Roman", serif;
    /* Data face: tabular numerals so columns of figures align like a real ledger. */
    --mb-font-mono: ui-monospace, "Cascadia Code", "Segoe UI Mono", Consolas, "Liberation Mono", monospace;
}

body {
    background-color: var(--mb-bg);
    color: var(--mb-text);
    font-size: 0.8rem;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

::placeholder {
    color: var(--mb-placeholder) !important;
    opacity: 1;
}

/* ---- Typography roles ---- */
h1, .sidebar-brand {
    font-family: var(--mb-font-display);
}

.mb-figure {
    font-family: var(--mb-font-mono);
    font-variant-numeric: tabular-nums;
}

.mb-figure-zero {
    color: var(--mb-placeholder);
}

a {
    color: var(--mb-accent);
}

a:hover {
    color: var(--mb-accent-hover);
}

/* ---- Standardize component font sizes to the app's base scale ----
   Bootstrap hardcodes its own font-size (1rem, or 0.875rem for tooltips/
   toasts) on several components via component-local CSS variables, so they
   don't inherit the body's 0.8rem base. Pin them here instead of letting
   each page pick a different one-off value. (.btn's own --bs-btn-font-size
   is set alongside its other rules in the Buttons section below.) */
.form-control,
.form-select,
.input-group-text {
    font-size: 0.8rem;
}

.dropdown-menu {
    --bs-dropdown-font-size: 0.8rem;
}

.pagination {
    --bs-pagination-font-size: 0.8rem;
}

.tooltip {
    --bs-tooltip-font-size: 0.8rem;
}

.popover {
    --bs-popover-font-size: 0.8rem;
    --bs-popover-header-font-size: 0.8rem;
}

.toast {
    --bs-toast-font-size: 0.8rem;
}

/* ---- Toasts: pale tinted variants to match the badge/tag palette ---- */
.toast.text-bg-danger {
    background-color: var(--mb-rose-soft) !important;
    color: var(--mb-rose) !important;
}

.toast.text-bg-warning {
    background-color: var(--mb-amber-soft) !important;
    color: var(--mb-amber) !important;
}

.toast.text-bg-success {
    background-color: var(--mb-emerald-soft) !important;
    color: var(--mb-emerald) !important;
}

.toast.text-bg-info {
    background-color: var(--mb-sky-soft) !important;
    color: var(--mb-sky) !important;
}

.toast.text-bg-secondary {
    background-color: var(--mb-bg) !important;
    color: var(--mb-text-muted) !important;
}

/* ---- Login / pre-auth layout ---- */
.login-wrapper {
    min-height: 100vh;
}

.login-card {
    max-width: 680px;
    width: 100%;
}

.box-shadow,
.card {
    border: none;
    border-radius: var(--mb-radius);
    box-shadow: var(--mb-shadow);
}

.login-card .bg-dark {
    background: linear-gradient(160deg, var(--mb-accent), var(--mb-accent-hover)) !important;
}

.login-brand-logo {
    height: 2.5rem;
}

.login-brand-mark {
    height: 3.5rem;
}

/* ---- A touch of color on key figures / shortcut icons ---- */
.card-body > h3 {
    color: var(--mb-accent);
}

.card-body > i.fa-2x {
    color: var(--mb-accent);
}

/* ---- Page & card titles, same color as primary buttons ---- */
.sticky-top h4 {
    color: var(--mb-accent);
}

#mainContent .content > .row:first-child h2 {
    color: var(--mb-accent);
}

.card-body h5,
.card-body h6 {
    color: var(--mb-accent);
}

/* Bootstrap's .text-muted/.text-danger utilities use !important and would
   otherwise win over the rule above for titles that also carry them. */
.card-body h5.text-muted,
.card-body h6.text-muted {
    color: var(--mb-accent) !important;
}

/* ---- Buttons ---- */
.btn {
    --bs-btn-font-size: 0.8rem;
    border-radius: var(--mb-radius-sm);
}

.btn-sm {
    --bs-btn-font-size: 0.7rem;
}

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

.btn-primary:hover,
.btn-primary:focus {
    background-color: var(--mb-accent-hover);
    border-color: var(--mb-accent-hover);
}

.btn-outline-primary {
    color: var(--mb-accent);
    border-color: var(--mb-accent);
}

.btn-outline-primary:hover,
.btn-outline-primary:focus {
    background-color: var(--mb-accent);
    border-color: var(--mb-accent);
}

/* ---- Language / theme switcher ---- */
.lang-switcher .btn,
.theme-switcher .btn {
    padding: 0.1rem 0.4rem;
}

/* ---- Tables ---- */
.table thead th {
    color: var(--mb-text-muted);
    text-transform: uppercase;
    font-size: 0.7rem;
    letter-spacing: 0.04em;
    font-weight: 600;
    border-bottom-width: 1px;
}

.table-striped {
    --bs-table-striped-bg: var(--mb-stripe-bg);
}

.actions-menu.dropdown-menu {
    --bs-dropdown-min-width: 7rem;
    --bs-dropdown-padding-y: 0.25rem;
    --bs-dropdown-item-padding-x: 0.75rem;
    --bs-dropdown-item-padding-y: 0.3rem;
}

/* ---- Badges ---- */
.badge {
    border-radius: var(--mb-radius-sm);
    font-weight: 600;
    font-size: 0.85em;
    padding: 0.45em 0.65em;
}

.badge.bg-primary {
    background-color: var(--mb-accent-soft) !important;
    color: var(--mb-accent) !important;
}

.badge.bg-success {
    background-color: var(--mb-emerald-soft) !important;
    color: var(--mb-emerald) !important;
}

.badge.bg-info {
    background-color: var(--mb-sky-soft) !important;
    color: var(--mb-sky) !important;
}

.badge.bg-warning {
    background-color: var(--mb-amber-soft) !important;
    color: var(--mb-amber) !important;
}

.badge.bg-danger {
    background-color: var(--mb-rose-soft) !important;
    color: var(--mb-rose) !important;
}

.badge.bg-secondary {
    background-color: var(--mb-bg) !important;
    color: var(--mb-text-muted) !important;
}

.badge.bg-dark {
    background-color: var(--mb-violet-soft) !important;
    color: var(--mb-violet) !important;
}

.encoding-grid .badge,
.badge-sm-grid .badge {
    font-size: 0.7em;
    padding: 0.3em 0.5em;
}

/* ---- Authenticated layout ---- */
.sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--mb-sidebar-width);
    background-color: var(--mb-sidebar-bg);
    border-right: 1px solid var(--mb-border);
    color: var(--mb-sidebar-text);
    display: flex;
    flex-direction: column;
    transition: width 0.15s ease;
}

.sidebar-header {
    padding: 1rem;
    font-size: 1.25rem;
    font-weight: 700;
    border-bottom: 1px solid var(--mb-border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.sidebar-brand {
    color: var(--mb-text);
    text-decoration: none;
    overflow: hidden;
    white-space: nowrap;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.sidebar-brand-mark {
    width: 1.5rem;
    height: 1.5rem;
    flex: 0 0 auto;
}

.sidebar-toggle {
    position: absolute;
    top: 50%;
    right: -0.75rem;
    transform: translateY(-50%);
    z-index: 5;
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    padding: 0;
    font-size: 0.7rem;
    background-color: var(--mb-sidebar-bg);
    border: 1px solid var(--mb-border);
    border-radius: 50%;
    box-shadow: var(--mb-shadow-sm);
    color: var(--mb-text-muted);
}

.sidebar-toggle:hover,
.sidebar-toggle:focus {
    background-color: var(--mb-bg);
    color: var(--mb-text);
}

.sidebar-scroll {
    flex: 1 1 auto;
    overflow-y: auto;
}

.sidebar-menu {
    list-style: none;
    margin: 0;
    padding: 0.5rem;
}

.sidebar-menu li a {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.6rem 0.75rem;
    border-radius: var(--mb-radius-sm);
    color: var(--mb-sidebar-text);
    text-decoration: none;
}

.sidebar-menu li a i {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    font-size: 0.8rem;
    color: var(--mb-text-muted);
}

.sidebar-menu li a:hover {
    background-color: var(--mb-bg);
    color: var(--mb-text);
}

.sidebar-menu li a.active {
    background-color: var(--mb-sidebar-active-bg);
    color: var(--mb-sidebar-active-text);
    font-weight: 600;
}

.sidebar-section-label {
    padding: 1rem 0.75rem 0.25rem;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--mb-sidebar-text-muted);
}

.sidebar-footer {
    border-top: 1px solid var(--mb-border);
    padding: 0.5rem;
}

.table > tbody > tr.totals-row > td,
.table > tfoot > tr.totals-row > td {
    border-top: 2px solid var(--mb-border);
    border-bottom-width: 0;
}

.form-control.is-modified {
    background-color: var(--mb-amber-soft);
    border-color: var(--mb-amber);
}

.sidebar-user-toggle {
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    border-radius: var(--mb-radius-sm);
    color: var(--mb-sidebar-text);
    padding: 0.5rem 0.75rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.sidebar-user-toggle:hover,
.sidebar-user-toggle:focus {
    background-color: var(--mb-bg);
    color: var(--mb-text);
}

/* ---- Notifications sidebar menu badge ---- */
.sidebar-menu-badge {
    margin-left: auto;
    min-width: 1.1rem;
    height: 1.1rem;
    padding: 0 0.35rem;
    border-radius: 999px;
    background-color: var(--mb-rose);
    color: #fff;
    font-size: 0.7rem;
    line-height: 1.1rem;
    text-align: center;
    flex: 0 0 auto;
}

.sidebar-menu-badge[data-count="0"] {
    display: none;
}

/* ---- Notifications page (full list) — echoes .project-tree's row-highlight language
   (rounded rows, zebra striping, accent-soft for the row that needs attention) instead
   of a plain bordered list. The project name is a small accent-soft badge rather than a
   full-width bar, so the rows underneath keep flush with the card's left edge. ---- */
.notification-toolbar {
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--mb-border);
}

.notification-group + .notification-group {
    margin-top: 1rem;
}

.notification-group-header {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.3rem 0.6rem;
    margin-bottom: 0.35rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--mb-accent);
    background-color: var(--mb-accent-soft);
}

.notification-row {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    margin-left: 1.25rem;
    border-radius: var(--mb-radius-sm);
    cursor: pointer;
    color: var(--mb-text);
    transition: background-color 0.1s ease-in-out;
}

.notification-row + .notification-row {
    margin-top: 0.15rem;
}

.notification-row:nth-child(even) {
    background-color: var(--mb-stripe-bg);
}

.notification-row:hover {
    background-color: var(--mb-bg);
}

.notification-row.unread {
    background-color: var(--mb-accent-soft);
}

.notification-row-icon {
    flex: 0 0 auto;
    margin-top: 0.15rem;
}

.notification-row-body {
    flex: 1 1 auto;
    min-width: 0;
}

.notification-row-actions {
    flex: 0 0 auto;
}

.notification-row-time {
    color: var(--mb-text-muted);
    font-size: 0.8rem;
}

#mainContent {
    margin-left: var(--mb-sidebar-width);
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    transition: margin-left 0.15s ease;
}

#mainContent .content {
    flex: 1 1 auto;
    padding: 1.5rem;
}

.footer {
    padding: 1rem 0;
    color: var(--mb-text-muted);
}

@media (max-width: 991.98px) {
    .sidebar {
        position: static;
        width: 100%;
        height: auto;
        border-right: none;
        border-bottom: 1px solid var(--mb-border);
    }

    #mainContent {
        margin-left: 0;
    }

    .sidebar-toggle {
        display: none;
    }
}

/* ---- Collapsed sidebar ---- */
.sidebar-collapsed .sidebar {
    width: var(--mb-sidebar-collapsed-width);
}

.sidebar-collapsed #mainContent {
    margin-left: var(--mb-sidebar-collapsed-width);
}

.sidebar-collapsed .sidebar-header {
    justify-content: center;
}

.sidebar-collapsed .sidebar-menu li a {
    justify-content: center;
    position: relative;
}

.sidebar-collapsed .sidebar-menu-label,
.sidebar-collapsed .sidebar-section-label {
    display: none;
}

.sidebar-collapsed .sidebar-menu-badge {
    position: absolute;
    top: 0.35rem;
    right: 0.35rem;
    min-width: 0;
    width: 0.5rem;
    height: 0.5rem;
    padding: 0;
    font-size: 0;
    line-height: 0;
}

/* ---- Loading overlay ---- */
#loading {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 1050;
    background: rgba(255, 255, 255, 0.6);
}

#loading::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 3rem;
    height: 3rem;
    margin: -1.5rem;
    border: 0.35rem solid var(--mb-border);
    border-top-color: var(--mb-accent);
    border-radius: 50%;
    animation: mb-spin 0.8s linear infinite;
}

@keyframes mb-spin {
    to { transform: rotate(360deg); }
}

/* ---- File dropzone ---- */
.file-dropzone {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.25rem;
    min-height: 130px;
    padding: 1.25rem 1rem;
    text-align: center;
    border: 2px dashed var(--mb-border);
    border-radius: var(--mb-radius);
    background-color: var(--mb-bg);
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease;
}

.file-dropzone:hover,
.file-dropzone:focus-within {
    border-color: var(--mb-accent);
}

.file-dropzone.dragover {
    border-color: var(--mb-accent);
    background-color: var(--mb-accent-soft);
}

.file-dropzone.has-file {
    border-style: solid;
    cursor: default;
}

.file-dropzone-input {
    position: absolute;
    inset: 0;
    z-index: 1;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}

.file-dropzone-icon {
    font-size: 1.75rem;
    color: var(--mb-accent);
}

.file-dropzone-title {
    font-weight: 600;
    color: var(--mb-text);
}

.file-dropzone-file {
    position: relative;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
}

.file-dropzone-file-icon {
    font-size: 1.25rem;
    color: var(--mb-emerald);
}

.file-dropzone-filename {
    flex: 1 1 auto;
    overflow: hidden;
    font-weight: 500;
    text-align: left;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---- Project tree ---- */
.project-tree {
    list-style: none;
    padding-left: 0;
}

.project-tree .project-tree {
    padding-left: 1.15rem;
    margin-left: 0.6rem;
    margin-top: 0.25rem;
    border-left: 1px dashed var(--mb-border);
}

.project-tree-row {
    display: grid;
    grid-template-columns: 1.25rem 1fr 110px 110px 110px 7rem;
    align-items: center;
    column-gap: 0.5rem;
    padding: 0.25rem 0.5rem;
    border-radius: var(--mb-radius-sm);
    transition: background-color 0.1s ease-in-out;
}

.project-tree-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
}

.card-body > .project-tree > .project-tree-node > .project-tree-row {
    background-color: var(--mb-accent-soft);
}

.project-tree .project-tree > .project-tree-node:nth-child(even) > .project-tree-row:not(.milestone-tree-row):not(.hypothesis-tree-row) {
    background-color: var(--mb-stripe-bg);
}

.project-tree-row:hover,
.card-body > .project-tree > .project-tree-node > .project-tree-row:hover,
.project-tree .project-tree > .project-tree-node:nth-child(even) > .project-tree-row:not(.milestone-tree-row):not(.hypothesis-tree-row):hover {
    background-color: var(--mb-bg);
}

.table-hover > tbody > tr:hover > * {
    --bs-table-hover-bg: var(--mb-accent-soft);
    --bs-table-hover-color: var(--mb-text);
    background-color: var(--mb-accent-soft);
}

table.table.dataTable.table-hover > tbody > tr:hover > * {
    box-shadow: none;
    background-color: var(--mb-accent-soft);
    color: var(--mb-text);
}

.import-history-toggle-less {
    display: none;
}

.import-history-toggle[aria-expanded="true"] .import-history-toggle-more {
    display: none;
}

.import-history-toggle[aria-expanded="true"] .import-history-toggle-less {
    display: inline;
}

.project-tree-toggle {
    width: 1.25rem;
    text-align: center;
    color: var(--mb-accent);
}

.project-tree-toggle:hover {
    color: var(--mb-accent-hover);
}

.project-tree-leaf-icon {
    display: inline-block;
    width: 1.25rem;
    text-align: center;
    color: var(--mb-text-muted);
}

.project-tree-name {
    font-weight: 500;
}

.project-tree-row-inactive .project-tree-name {
    color: var(--mb-text-muted);
    font-style: italic;
}

.project-tree-row-inactive .project-tree-toggle,
.project-tree-row-inactive .project-tree-leaf-icon {
    opacity: 0.6;
}

.project-tree-header {
    display: grid;
    grid-template-columns: 1.25rem 1fr 110px 110px 110px 7rem;
    align-items: center;
    column-gap: 0.5rem;
    padding: 0.25rem 0.5rem;
    font-size: 0.8rem;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--mb-text-muted);
    border-bottom: 1px solid var(--mb-border);
    margin-bottom: 0.25rem;
}

.milestone-tree-header {
    display: grid;
    grid-template-columns: 1.25rem 260px 1fr 90px 110px 110px 100px;
    align-items: center;
    column-gap: 0.5rem;
    padding: 0.25rem 0.5rem;
    font-size: 0.8rem;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--mb-text-muted);
    border-bottom: 1px solid var(--mb-border);
    margin-bottom: 0.25rem;
}

.milestone-tree-row {
    display: grid;
    grid-template-columns: 1.25rem 260px 1fr 90px 110px 110px 100px;
    align-items: center;
    column-gap: 0.5rem;
    padding: 0.25rem 0.5rem;
    border-radius: var(--mb-radius-sm);
}

.milestone-tree-row.milestone-tree-row-even {
    background-color: var(--mb-stripe-bg);
}

.milestone-tree-row:hover {
    background-color: var(--mb-bg);
}

.milestone-date-summary {
    font-weight: 600;
}

.milestone-date-detail {
    font-weight: 400;
    color: var(--mb-text-muted);
}

/* ---- Project assignment modal: name-search suggestions dropdown ---- */
#assignUserSuggestions {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 1056;
    max-height: 220px;
    overflow-y: auto;
}

/* ---- Gantt two-pane synced panel: left WBS grid + right Frappe Gantt timeline,
   kept row-aligned by sharing --gantt-row-height/--gantt-header-height (set from
   gantt.js, same constants passed into the Gantt() constructor's bar_height/padding/
   upper_header_height/lower_header_height options) and by letting a single flex-row
   wrapper own vertical scroll so both panes scroll in lockstep with no JS scroll-sync. ---- */
.gantt-split-panel {
    border: 1px solid var(--mb-border);
    border-radius: var(--mb-radius-sm);
    overflow: hidden;
    /* Same "fill the rest of the page below the sticky header" convention as
       .kanban-board, but a fixed height (not min-height) this time: the grid pane and
       chart pane below each scroll internally within this budget so their own column/date
       headers (position: sticky, top: 0) can freeze in place — sticky only ever freezes
       against its own nearest scrolling ancestor, which only happens if that ancestor
       actually has bounded, overflowing content instead of growing to fit it. */
    height: calc(100vh - 280px);
}

/* The WBS/Resource tree reuses the generic .project-tree component, whose nested-list
   rule (.project-tree .project-tree, above) adds margin-top: 0.25rem, padding-left: 1.15rem
   and margin-left: 0.6rem per nesting level. margin-top is zeroed for the same reason as
   below (Frappe Gantt's bars have no equivalent gap, using a uniform --gantt-row-height
   pitch instead, so any stray margin drifts the grid rows out of alignment with the chart).
   padding-left/margin-left are zeroed too, for a subtler reason: every .gantt-grid-row is
   its own independent CSS Grid instance sharing the same grid-template-columns as the
   header, and that only lines their columns up if every row's box is exactly as wide as
   the header's — which the indentation (shrinking a nested row's own box the deeper it
   sits) would silently break. The WBS tree still reads as indented: renderTaskNode() in
   gantt/index.php applies the equivalent padding-left directly to the name cell's content
   instead, which doesn't touch the row's own box width. */
.gantt-grid-body .project-tree {
    margin-top: 0;
    padding-left: 0;
    margin-left: 0;
}

.gantt-split-scroll {
    display: flex;
    /* stretch, not flex-start: both panes below fill this row's full height (itself
       100% of .gantt-split-panel's fixed height) so each one's own internal scrollbar
       covers the same vertical span instead of stopping wherever its own content ends. */
    align-items: stretch;
    height: 100%;
}

.gantt-grid-pane {
    flex: 0 0 var(--gantt-panel-width, 640px);
    width: var(--gantt-panel-width, 640px);
    min-width: 0;
    height: 100%;
    border-right: 1px solid var(--mb-border);
    /* Deliberately narrower than the grid's own content width (see grid-template-columns
       below): rather than compressing every column to fit, the pane scrolls horizontally
       on its own so columns further right (Ressources, actions) stay reachable at a
       readable width instead of being squeezed or ellipsis-truncated. */
    overflow-x: auto;
    /* Bounded height above turns this pane into the actual vertical scroll container for
       the WBS rows, which is what lets .gantt-grid-header's position: sticky (top: 0)
       freeze against it instead of just sitting inert atop content that never overflows.
       The chart pane's own .gantt-container scrolls independently in lockstep via the
       scroll-mirroring listener set up in gantt.js (createGanttInstance/syncSplitPanelScroll)
       — there's no single shared scrolling ancestor for both panes once each needs its own
       sticky header, so unlike before this can no longer be pure CSS. */
    overflow-y: auto;
}

/* The vertical scrollbar stays functional (overflow-y: auto above) but hidden: scrolling
   this pane already mirrors onto the chart pane's own scrollbar (see syncSplitPanelScroll
   in gantt.js), so showing a second vertical track here next to it is just visual clutter,
   not an extra affordance — the wheel/trackpad/synced scroll all still work with it hidden.
   The horizontal scrollbar (this rule's "height" property, the sibling of "width" above)
   is deliberately kept, and given an explicit height/thumb instead of the browser default,
   because it's the only way to reach the columns past "Nom" (see overflow-x above) and is
   otherwise easy to miss entirely: on macOS, Chrome/Safari render "auto" overflow with a
   translucent overlay scrollbar that only appears while actively scrolling, so without a
   size of its own here it's invisible at rest and the horizontal-scroll affordance goes
   undiscoverable. Declaring any ::-webkit-scrollbar rule on an element is also what opts
   Chrome/Safari out of that overlay style for it, in favor of an always-reserved classic
   track — which is the effect wanted here, not just a side one.
   Firefox has no per-axis equivalent to scrollbar-width, so it isn't touched here and
   keeps showing both bars — an acceptable, purely cosmetic gap on that one browser. */
.gantt-grid-pane::-webkit-scrollbar {
    width: 0;
    height: 10px;
}

.gantt-grid-pane::-webkit-scrollbar-track {
    background: var(--mb-bg);
}

.gantt-grid-pane::-webkit-scrollbar-thumb {
    background-color: var(--mb-border);
    border-radius: var(--mb-radius-sm);
}

/* Drag handle between the WBS grid pane and the Gantt chart pane, resizing the same
   --gantt-panel-width custom property .gantt-grid-pane's width/flex-basis is defined from
   (see that rule) — same "one CSS var, set once on the .gantt-split-panel ancestor" pattern
   already used by .gantt-col-resizer, applied one level up to the pane split itself. Sits
   on top of .gantt-grid-pane's own border-right (negative margin pulls it fully over that
   1px line) so the draggable hit area isn't offset from the visible seam between panes. */
.gantt-panel-resizer {
    flex: 0 0 6px;
    width: 6px;
    margin-left: -1px;
    margin-right: -5px;
    cursor: col-resize;
    z-index: 3;
    position: relative;
}

.gantt-panel-resizer:hover,
.gantt-panel-resizer.gantt-panel-resizing {
    background-color: var(--mb-accent);
    opacity: 0.5;
}

.gantt-chart-pane {
    flex: 1 1 auto;
    /* Without min-width: 0, a flex child can't shrink below its content's intrinsic
       width, so the wide Frappe SVG would push this pane (and the whole scroller)
       wider instead of letting Frappe's own container scroll horizontally. */
    min-width: 0;
    height: 100%;
    /* Frappe Gantt wraps its SVG in its own .gantt-container (width: 100%,
       overflow: auto, sticky grid-header + side-header) — that div already owns
       both horizontal and (now) vertical scrolling for the timeline. Giving this
       pane its own overflow on top of it would nest two independent scroll
       containers around the same content: a stray sub-pixel/scrollbar-width
       mismatch between them makes this outer pane scroll too, showing a second
       scrollbar and breaking the sticky Today/view-mode toolbar (which is
       positioned relative to the inner .gantt-container's scroll, not this one).
       Both axes stay hidden here so .gantt-container is the sole scroll region. */
    overflow: hidden;
}

/* Frappe Gantt doesn't render straight into .gantt-chart-pane: gantt/index.php gives it
   a plain #ganttChart/#ganttChartResource div to construct into, and the library then
   inserts its own .gantt-container as a child of THAT div, one level deeper than this
   rule reaches. That intermediate div has no height of its own (auto, i.e. "shrink to
   fit its child"), so it can't work as a definite containing block for the percentage
   height below — percentages against an indefinite auto height resolve to none, silently
   dropping the clamp. Giving it height: 100% here (against .gantt-chart-pane's own,
   itself resolved from .gantt-split-panel's fixed height) closes that gap. */
.gantt-chart-pane > div {
    height: 100%;
}

/* Frappe Gantt's own stylesheet sets height: var(--gv-grid-height) on .gantt-container,
   an inline custom property it computes from container_height: "auto" — i.e. the exact
   pixel height of every row, with no idea a bounded parent even exists. height: 100%
   (resolving against the now-definite height of the #ganttChart div above) overrides that
   value outright rather than just capping it, so the chart pane always fills the same
   vertical span as .gantt-grid-pane on the WBS side — even when there are too few rows to
   reach it — instead of shrinking to content height and leaving the pane's bottom looking
   cut off next to the WBS grid's full-height scrollbox. Once the timeline has more rows
   than fit, this container scrolls vertically on its own — bringing back Frappe's own
   sticky .grid-header (top: 0, baked into the vendored stylesheet) as a frozen date header,
   the same way .gantt-grid-header freezes on the WBS side. Two-class selector so it
   outranks the vendored single-class rule. */
.gantt-chart-pane .gantt-container {
    height: 100%;
    overflow-x: auto;
    overflow-y: auto;
}

/* Every .gantt-grid-row is its own independent CSS Grid instance sharing this same
   grid-template-columns with .gantt-grid-header — they only stay pixel-aligned because
   every row's own box is exactly as wide as the header's (see the indentation note on
   .gantt-grid-body .project-tree above). With that guaranteed, the name column can safely
   take a minimum width like any other column: unlike a plain 1fr, minmax() here no longer
   risks misaligning rows at different WBS depths.
   Each track is a var() with the original fixed rem value as fallback, so dragging a
   .gantt-col-resizer (see gantt.js initGanttColumnResize()) only has to set one custom
   property on the .gantt-split-panel ancestor — every row picks it up through inheritance
   without JS ever touching the (potentially hundreds of) individual row elements, and the
   two split panels (WBS / Resource) stay independently sized since each only overrides the
   property on its own ancestor.
   min-width mirrors the same vars so the row's own box always grows to fit whatever the
   columns currently sum to (default 2.75 + 1.25 + 2.25 + 12 + 5.5 + 5.5 + 4 + 3 + 4 + 5.5 +
   5.5 + 12 = 63.25rem + 11 * 0.5rem column-gaps + 1rem horizontal padding = 69.75rem) —
   deliberately at least as wide as .gantt-grid-pane (see that rule) so its overflow-x
   scrolls to reveal whatever's past "Nom". Without this min-width, the row's own box would
   stay at the pane's width while its grid content merely bled out past it visually:
   background-color/:hover/the drag-and-drop drop-zone box-shadow all paint only within the
   box itself, so they'd go missing exactly in the region scrolling reveals. min-width
   instead grows the real box to match, so painting covers the full scrollable width like it
   does within the pane's initial 640px.
   The wbs column (2.25rem default) is sized for the common case (2-3 levels, single-digit
   indices, e.g. "3.2") — a WBS deeper/wider than that (e.g. "12.34.5") will visually
   overflow its cell into the gap unless the user drags it wider.
   The Resource view reuses this same 12-track grid but doesn't have a WBS/priority/status
   concept of its own (see gantt/index.php) — it pads with blank <span>s at those indices
   rather than reflowing the shared column count, which is what keeps its header and rows
   pixel-aligned against this one rule too. */
.gantt-grid-header,
.gantt-grid-row {
    display: grid;
    grid-template-columns:
        var(--gantt-col-1, 2.75rem)
        var(--gantt-col-2, 1.25rem)
        var(--gantt-col-3, 2.25rem)
        minmax(var(--gantt-col-4, 12rem), 1fr)
        var(--gantt-col-5, 5.5rem)
        var(--gantt-col-6, 5.5rem)
        var(--gantt-col-7, 4rem)
        var(--gantt-col-8, 3rem)
        var(--gantt-col-9, 4rem)
        var(--gantt-col-10, 5.5rem)
        var(--gantt-col-11, 5.5rem)
        var(--gantt-col-12, 12rem);
    align-items: center;
    column-gap: 0.5rem;
    padding: 0 0.5rem;
    min-width: calc(
        var(--gantt-col-1, 2.75rem) + var(--gantt-col-2, 1.25rem) + var(--gantt-col-3, 2.25rem) +
        var(--gantt-col-4, 12rem) + var(--gantt-col-5, 5.5rem) + var(--gantt-col-6, 5.5rem) +
        var(--gantt-col-7, 4rem) + var(--gantt-col-8, 3rem) + var(--gantt-col-9, 4rem) +
        var(--gantt-col-10, 5.5rem) + var(--gantt-col-11, 5.5rem) + var(--gantt-col-12, 12rem) + 6.5rem
    );
    font-size: 0.7rem;
}

/* Columns 1-2 hold the actions-menu button and drag handle in the WBS view; the Resource
   view pads those same tracks with blank <span>s (see the reuse note above) since resource
   groups aren't reorderable/editable rows, so there's nothing to show there. Shrinking them
   here removes that dead space from the pane's left edge without touching the WBS grid,
   which keeps reading its width from the shared var()'s own 2.75rem/1.25rem fallback. */
#ganttSplitPanelResource {
    --gantt-col-1: 0.5rem;
    --gantt-col-2: 0.25rem;
}

.gantt-grid-header {
    height: var(--gantt-header-height, 60px);
    font-weight: 600;
    text-transform: uppercase;
    color: var(--mb-text-muted);
    border-bottom: 1px solid var(--mb-border);
    position: sticky;
    top: 0;
    background-color: var(--mb-surface, var(--mb-bg));
    z-index: 1;
}

.gantt-grid-row {
    height: var(--gantt-row-height, 40px);
    border-radius: var(--mb-radius-sm);
}

/* Drag handles only exist on the header cells (there's one grid to resize, not one per
   row), positioned on the cell's own trailing edge so dragging it changes that column's
   own --gantt-col-N var (see gantt.js initGanttColumnResize()) regardless of neighbors —
   unlike a typical resizable table, columns don't compensate each other's width, the row
   just grows/shrinks and the pane's overflow-x absorbs the difference. */
.gantt-grid-header > span {
    position: relative;
}

.gantt-col-resizer {
    position: absolute;
    top: 0;
    bottom: 0;
    right: -0.5rem;
    width: 0.75rem;
    cursor: col-resize;
    z-index: 2;
}

.gantt-col-resizer:hover,
.gantt-col-resizer.gantt-col-resizing {
    background-color: var(--mb-accent);
    opacity: 0.5;
}

.gantt-grid-row.gantt-tree-row-even {
    background-color: var(--mb-stripe-bg);
}

.gantt-grid-row:hover {
    background-color: var(--mb-bg);
}

/* Every row must stay exactly --gantt-row-height tall for the two panes to stay
   aligned — long task names or many resource badges must truncate, never wrap.
   Same convention already used by .encoding-grid td/th. */
.gantt-grid-col-name,
.gantt-grid-col-resources {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* Per-row collapse must be instant, not animated, so the left grid's row count
   changes in the same frame as the refresh() call that reflows the right-side
   bars (see refreshGanttVisibleRows() in gantt.js) — otherwise the two panes
   visibly desync for the ~0.35s Bootstrap collapse transition. */
#ganttSplitPanel .collapsing {
    transition: none;
}

.gantt-tree-row-phase .project-tree-name {
    font-weight: 700;
}

.gantt-tree-name-toggle {
    color: inherit;
    text-decoration: none;
    cursor: pointer;
}

.gantt-tree-name-toggle:hover {
    color: var(--mb-accent);
}

.gantt-tree-wbs {
    font-family: var(--bs-font-monospace, monospace);
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--mb-text-muted);
    white-space: nowrap;
    margin-right: 0.15rem;
}

.gantt-tree-wbs-leaf {
    font-weight: 400;
}

.gantt-drag-handle {
    cursor: grab;
    color: var(--mb-text-muted);
    text-align: center;
}

.gantt-drag-handle:hover {
    color: var(--mb-accent);
}

.gantt-grid-row.dragging {
    opacity: 0.4;
}

/* Drop-zone feedback while dragging a WBS row over another: a top/bottom border shows
   it will land as a sibling before/after the hovered row, a filled background shows it
   will be dropped inside (reparented as a child of) the hovered row. */
.gantt-grid-row.gantt-drop-before {
    box-shadow: inset 0 2px 0 0 var(--bs-primary);
}

.gantt-grid-row.gantt-drop-after {
    box-shadow: inset 0 -2px 0 0 var(--bs-primary);
}

.gantt-grid-row.gantt-drop-inside {
    background-color: var(--bs-primary-bg-subtle);
    box-shadow: inset 0 0 0 1px var(--bs-primary);
}

/* ---- Frappe Gantt: the library prepends its own Day/Week/Month + Today toolbar
   (.side-header) straight into .upper-header, sticky-positioned over the right edge
   of the date row. Its own stylesheet only backs the individual button/select pills,
   not the toolbar strip itself, so the date text shows through the gaps around them.
   Giving the strip an opaque backing (matching the header background) fully masks
   the dates it sits over instead of visually colliding with them. ---- */
.gantt-container .side-header {
    background-color: var(--g-header-background);
}

/* ---- Frappe Gantt: default task bars. The vendored frappe-gantt.css ships
   .gantt .bar-wrapper .bar { fill: var(--g-bar-color) } (3 class selectors,
   --g-bar-color defaults to #fff), which otherwise wins over any 2-class
   override here on specificity alone regardless of source order — every rule
   in this block is prefixed with #ganttChart (ID beats any number of classes)
   so our theming actually applies instead of leaving bars white-on-white. ---- */
#ganttChart .gantt-task-bar .bar {
    fill: var(--mb-accent);
}

/* ---- Frappe Gantt: phase bars (tasks with children, rollup dates) rendered
   in a muted tone so they read as containers rather than actionable work ---- */
#ganttChart .gantt-phase-bar .bar {
    fill: var(--mb-text-muted);
    opacity: 0.55;
}

#ganttChart .gantt-phase-bar .bar-progress {
    fill: var(--mb-text-muted);
}

/* ---- Frappe Gantt: milestone bars (rollupStart === rollupEnd, same convention as
   t_milestone) rendered as a diamond instead of a rectangle. The rect this clip-path
   cuts is resized to GANTT_MILESTONE_WIDTH x bar_height and re-centered in JS first
   (see fixMilestoneBars() in gantt.js) — width narrower than height so the clip
   produces an actual elongated rhombus instead of a square standing on its corner.
   Frappe's base .bar-wrapper .bar rule still draws an outline + border-radius on the
   un-clipped box underneath, which clip-path doesn't mask — outline/border-radius are
   reset here so the diamond isn't boxed in a square frame. ---- */
#ganttChart .gantt-milestone-bar .bar {
    clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
    fill: var(--mb-amber);
    outline: none;
    border-radius: 0;
}

/* tsk_percentcomplete is freely set by a PM (0-100) even on a milestone, but there's no
   sane way to render "40% of a single point-in-time event": clipping a partial-width
   progress rect to the same diamond polygon draws a lopsided wedge, not a smaller
   diamond. Milestone completion already reads from its color/status elsewhere (the grid's
   done checkmark), so the progress fill is simply omitted here rather than hidden with
   opacity:0 or fill:transparent (both would still pay for the clip-path/paint). */
#ganttChart .gantt-milestone-bar .bar-progress {
    display: none;
}

.hypothesis-tree-header {
    display: grid;
    grid-template-columns: 1.25rem 220px 1fr 130px 110px 110px 150px 110px;
    align-items: center;
    column-gap: 0.5rem;
    padding: 0.25rem 0.5rem;
    font-size: 0.8rem;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--mb-text-muted);
    border-bottom: 1px solid var(--mb-border);
    margin-bottom: 0.25rem;
}

.hypothesis-tree-row {
    display: grid;
    grid-template-columns: 1.25rem 220px 1fr 130px 110px 110px 150px 110px;
    align-items: center;
    column-gap: 0.5rem;
    padding: 0.25rem 0.5rem;
    border-radius: var(--mb-radius-sm);
}

.hypothesis-tree-row.hypothesis-tree-row-even {
    background-color: var(--mb-stripe-bg);
}

.hypothesis-tree-row:hover {
    background-color: var(--mb-bg);
}

/* ---- Project / milestone / hypothesis / gantt trees: mobile reflow ----
   The fixed grid columns (project-tree-row, milestone-tree-row, hypothesis-tree-row,
   gantt-grid-row) crush the name column once the sidebar goes static below 991.98px.
   Below that same breakpoint, switch both trees from a rigid grid to a wrapping flex
   row so long names and action buttons get their own line instead of being squeezed
   against fixed pixel-width columns. The gantt split panel instead stacks its two
   panes vertically (see .gantt-split-scroll below) since its grid/chart split doesn't
   translate to flex-wrap. */
@media (max-width: 991.98px) {
    .project-tree-header,
    .milestone-tree-header,
    .hypothesis-tree-header,
    .gantt-grid-header {
        display: none;
    }

    /* Below this breakpoint .gantt-grid-header is hidden anyway (above), so there's
       no header left to freeze — revert the desktop fixed-height/internal-scroll setup
       entirely back to a single page-scrolling column, rather than stacking two
       independently height-capped scrollboxes (each with its own scrollbar) on a small
       screen. */
    .gantt-split-panel {
        height: auto;
    }

    .gantt-split-scroll {
        flex-direction: column;
        height: auto;
    }

    .gantt-grid-pane {
        flex: 1 1 auto;
        width: 100%;
        height: auto;
        border-right: none;
        border-bottom: 1px solid var(--mb-border);
        overflow-y: visible;
    }

    .gantt-panel-resizer {
        display: none;
    }

    .gantt-chart-pane {
        width: 100%;
        height: auto;
    }

    .gantt-chart-pane > div {
        height: auto;
    }

    .gantt-chart-pane .gantt-container {
        height: auto;
        overflow-y: hidden;
    }

    .project-tree-row {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        row-gap: 0.35rem;
        column-gap: 0.6rem;
    }

    .project-tree-row > *:empty {
        display: none;
    }

    .project-tree-name {
        flex: 1 1 auto;
        min-width: 0;
        word-break: break-word;
    }

    .project-tree-col-capexopex,
    .project-tree-col-type,
    .project-tree-col-status {
        flex: 0 0 auto;
    }

    .project-tree-actions {
        flex: 0 0 auto;
        justify-content: flex-start;
        flex-wrap: wrap;
    }

    .milestone-tree-row > *:nth-child(6)::before {
        content: "→ ";
        color: var(--mb-text-muted);
    }

    .project-tree .project-tree {
        padding-left: 0.75rem;
        margin-left: 0.35rem;
    }
}

.encoding-grid {
    table-layout: fixed;
}

.encoding-grid td,
.encoding-grid th {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ---- Encoding grids: keep the resource identity visible while scrolling months ---- */
.encoding-grid td:first-child,
.encoding-grid th:first-child {
    position: sticky;
    left: 0;
    z-index: 1;
    background-color: var(--mb-surface);
    box-shadow: 1px 0 0 var(--mb-border);
}

.encoding-grid thead th:first-child {
    z-index: 2;
}

/* ---- Encoding grids: ledger-style numeric inputs, no native spinner clutter ---- */
.encoding-grid input[type="number"]::-webkit-outer-spin-button,
.encoding-grid input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.encoding-grid input[type="number"] {
    -moz-appearance: textfield;
    text-align: right;
}

.encoding-grid .row-total {
    font-family: var(--mb-font-mono);
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

.cookie-banner {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1080;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    padding: 0.75rem 1.5rem;
    background-color: var(--mb-surface);
    border-top: 1px solid var(--mb-border);
    box-shadow: var(--mb-shadow);
    color: var(--mb-text);
}

/* ---- Dark mode ----
   html[data-bs-theme="dark"] (not the bare attribute selector): frappe-gantt.css's
   own :root block defines the same --g-* custom properties unconditionally, and is
   loaded after this stylesheet (its <link> sits at the bottom of the gantt view).
   :root and a bare [data-bs-theme="dark"] tie in specificity, so without the extra
   "html" type selector here, source order alone would let frappe's light :root
   defaults win over these dark overrides regardless of the active theme. */
html[data-bs-theme="dark"] {
    --mb-bg: #0f172a;
    --mb-surface: #1e293b;
    --mb-text: #e2e8f0;
    --mb-text-muted: #94a3b8;
    --mb-border: #334155;
    --mb-stripe-bg: rgba(255, 255, 255, 0.03);
    --mb-placeholder: #4b5b75;

    --mb-accent: #929cf9;
    --mb-accent-hover: #6366f1;
    --mb-accent-soft: rgba(129, 140, 248, 0.15);

    --mb-emerald: #34d399;
    --mb-emerald-soft: rgba(52, 211, 153, 0.15);
    --mb-amber: #fbbf24;
    --mb-amber-soft: rgba(251, 191, 36, 0.15);
    --mb-sky: #38bdf8;
    --mb-sky-soft: rgba(56, 189, 248, 0.15);
    --mb-rose: #fb7a8d;
    --mb-rose-soft: rgba(251, 113, 133, 0.15);
    --mb-violet: #a78bfa;
    --mb-violet-soft: rgba(167, 139, 250, 0.15);

    --mb-sidebar-bg: #111827;
    --mb-sidebar-text: #cbd5e1;
    --mb-sidebar-text-muted: #64748b;
    --mb-sidebar-active-bg: rgba(129, 140, 248, 0.18);
    --mb-sidebar-active-text: #a5b4fc;

    /* Frappe Gantt: the vendored frappe-gantt.css ships its own dark palette, but it's
       gated behind html[data-theme="dark"] — an attribute this app never sets (theme
       toggling here uses [data-bs-theme="dark"] on <html>, see main.php). Re-pointing
       the same --g-* custom properties the library reads keeps the chart's palette
       consistent with the app's own theme instead of frappe's unrelated near-black one. */
    --g-arrow-color: var(--mb-text-muted);
    --g-bar-color: var(--mb-surface);
    --g-bar-border: var(--mb-border);
    --g-tick-color-thick: var(--mb-border);
    --g-tick-color: rgba(255, 255, 255, 0.04);
    --g-actions-background: var(--mb-surface);
    --g-border-color: var(--mb-border);
    --g-text-muted: var(--mb-text-muted);
    --g-text-light: #ffffff;
    --g-text-dark: var(--mb-text);
    --g-progress-color: var(--mb-border);
    --g-handle-color: var(--mb-text-muted);
    --g-weekend-label-color: var(--mb-border);
    --g-expected-progress: var(--mb-accent-soft);
    --g-header-background: var(--mb-surface);
    --g-row-color: var(--mb-bg);
    --g-row-border-color: var(--mb-border);
    --g-today-highlight: var(--mb-accent);
    --g-popup-actions: var(--mb-bg);
    --g-weekend-highlight-color: var(--mb-stripe-bg);
}

/* ---- Distinction d'environnement (DEV/ACC/PRD) ---- */
[data-app-mode="DEV"] {
    --mb-accent: #7c3aed;
    --mb-accent-hover: #6d28d9;
    --mb-accent-soft: #f5f3ff;
    --mb-sidebar-active-bg: var(--mb-accent-soft);
    --mb-sidebar-active-text: var(--mb-accent);
}

[data-app-mode="ACC"] {
    --mb-accent: #d97706;
    --mb-accent-hover: #b45309;
    --mb-accent-soft: #fffbeb;
    --mb-sidebar-active-bg: var(--mb-accent-soft);
    --mb-sidebar-active-text: var(--mb-accent);
}

/* Variantes sombres : réutilisent les teintes translucides déjà définies dans [data-bs-theme="dark"] */
[data-bs-theme="dark"][data-app-mode="DEV"] {
    --mb-accent: var(--mb-violet);
    --mb-accent-hover: #8b5cf6;
    --mb-accent-soft: var(--mb-violet-soft);
    --mb-sidebar-active-bg: var(--mb-accent-soft);
    --mb-sidebar-active-text: var(--mb-accent);
}

[data-bs-theme="dark"][data-app-mode="ACC"] {
    --mb-accent: var(--mb-amber);
    --mb-accent-hover: #f59e0b;
    --mb-accent-soft: var(--mb-amber-soft);
    --mb-sidebar-active-bg: var(--mb-accent-soft);
    --mb-sidebar-active-text: var(--mb-accent);
}

[data-bs-theme="dark"] #loading {
    background: rgba(15, 23, 42, 0.7);
}

[data-bs-theme="dark"] .bg-white {
    background-color: var(--mb-surface) !important;
}

[data-bs-theme="dark"] .table-light {
    --bs-table-bg: var(--mb-bg);
    --bs-table-color: var(--mb-text);
    background-color: var(--mb-bg);
    color: var(--mb-text);
}

[data-bs-theme="dark"] .table-secondary {
    --bs-table-bg: var(--mb-surface);
    --bs-table-color: var(--mb-text);
    background-color: var(--mb-surface);
    color: var(--mb-text);
}

[data-bs-theme="dark"] .form-control.is-modified {
    background-color: rgba(217, 119, 6, 0.18);
    border-color: var(--mb-amber);
}

/* ---- Dark mode: Summernote ---- */
[data-bs-theme="dark"] .note-editor.note-frame,
[data-bs-theme="dark"] .note-editor.note-airframe {
    border-color: var(--mb-border);
}

[data-bs-theme="dark"] .note-editing-area .note-editable {
    background-color: var(--mb-surface);
    color: var(--mb-text);
}

[data-bs-theme="dark"] .note-editing-area .note-editable[contenteditable="false"] {
    background-color: rgba(255, 255, 255, 0.08);
}

[data-bs-theme="dark"] .note-status-output {
    background-color: var(--mb-surface);
    color: var(--mb-text-muted);
    border-top-color: var(--mb-border);
}

/* ---- Risk & action log register modals: compact form to match the app's dense style ---- */
.risk-modal-form .form-label,
.actionlog-modal-form .form-label {
    margin-bottom: 0.25rem;
}

/*
 * The add/edit forms wrap the modal-header/body/footer in a single <form> so one submit
 * posts everything. That <form> sits between .modal-content and .modal-body in the DOM, so
 * without this it isn't a flex participant and Bootstrap's .modal-dialog-scrollable sizing
 * (which expects .modal-content's *direct* children to be the flex items) never shrinks the
 * body — the footer (Save/Cancel) ends up pushed past the modal's height and clipped.
 */
#addRiskModal .modal-content > form,
#editRiskModal .modal-content > form,
#addActionLogModal .modal-content > form,
#editActionLogModal .modal-content > form {
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* ---- Risk register: Kanban board ---- */
.kanban-board {
    display: flex;
    gap: 0.75rem;
    overflow-x: auto;
    padding-bottom: 0.5rem;
    min-height: calc(100vh - 280px);
}

.kanban-column {
    flex: 1 1 0;
    min-width: 260px;
    display: flex;
    flex-direction: column;
    background-color: var(--mb-bg);
    border: 1px solid var(--mb-border);
    border-radius: 0.375rem;
}

.kanban-column.drag-over {
    border-color: var(--bs-primary);
    background-color: var(--bs-primary-bg-subtle);
}

.kanban-column-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.5rem 0.6rem;
    border-bottom: 1px solid var(--mb-border);
}

.kanban-column-body {
    flex: 1 1 auto;
    padding: 0.5rem;
    min-height: 60px;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.kanban-card {
    background-color: var(--mb-surface);
    border: 1px solid var(--mb-border);
    border-radius: 0.375rem;
    padding: 1.1rem 1.2rem;
    min-height: 170px;
    cursor: grab;
    box-shadow: 0 2px 4px rgba(16, 24, 40, 0.12), 0 4px 8px rgba(16, 24, 40, 0.08);
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.kanban-card:hover {
    box-shadow: 0 4px 8px rgba(16, 24, 40, 0.16), 0 8px 16px rgba(16, 24, 40, 0.1);
    transform: translateY(-1px);
}

.kanban-card.dragging {
    opacity: 0.4;
}

.kanban-card-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.65rem;
}

.kanban-card-title {
    font-weight: 600;
    color: var(--mb-text);
    margin-bottom: 0.65rem;
}

.kanban-card-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-bottom: 0.65rem;
}

.kanban-card-meta {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    color: var(--mb-text-muted);
    font-size: 0.8125rem;
}

.kanban-empty {
    text-align: center;
    padding: 0.5rem 0;
}

/* ---- Risk register: RAG accent on kanban cards ---- */
.kanban-card.rag-green {
    border-left: 4px solid var(--bs-success);
}

.kanban-card.rag-amber {
    border-left: 4px solid var(--bs-warning);
}

.kanban-card.rag-red {
    border-left: 4px solid var(--bs-danger);
}

/* ---- Risk register: RAG accent on list rows ---- */
#riskListView table tbody tr.rag-green td:first-child {
    border-left: 3px solid var(--bs-success);
}

#riskListView table tbody tr.rag-amber td:first-child {
    border-left: 3px solid var(--bs-warning);
}

#riskListView table tbody tr.rag-red td:first-child {
    border-left: 3px solid var(--bs-danger);
}

/* ---- Risk & action log registers: owner avatar (initials) ---- */
.risk-owner-avatar,
.actionlog-owner-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background-color: var(--mb-accent-soft);
    color: var(--mb-accent);
    font-size: 0.65rem;
    font-weight: 700;
}

.risk-owner-avatar-empty,
.actionlog-owner-avatar-empty {
    background-color: transparent;
    border: 1px dashed var(--mb-border);
    color: var(--mb-text-muted);
}

/* ---- Risk register: KPI RAG distribution bar ---- */
.risk-rag-bar {
    display: flex;
    height: 8px;
    border-radius: 4px;
    overflow: hidden;
    background-color: var(--mb-border);
}

.risk-rag-bar span {
    display: block;
    height: 100%;
}

/* ---- Risk & action log registers: filter bar ---- */
.risk-filter-bar,
.actionlog-filter-bar {
    overflow-x: auto;
    flex-wrap: nowrap;
    padding-bottom: 0.25rem;
}

.risk-filter-bar .form-select,
.risk-filter-bar .form-control,
.actionlog-filter-bar .form-select,
.actionlog-filter-bar .form-control {
    min-width: 110px;
    width: auto;
    flex-shrink: 0;
    font-size: 0.8125rem;
    padding-top: 0.15rem;
    padding-bottom: 0.15rem;
}

.risk-sortable,
.actionlog-sortable {
    cursor: pointer;
    user-select: none;
}

/* ---- Risk, hypothesis & action log registers: history & comments tabs (edit modal) ---- */
.risk-history-item,
.risk-comment-item,
.hypothesis-history-item,
.hypothesis-comment-item,
.actionlog-history-item,
.actionlog-comment-item {
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--mb-border);
    font-size: 0.875rem;
}

#riskCommentList,
#hypothesisCommentList,
#riskHistoryList,
#hypothesisHistoryList,
#actionlogCommentList,
#actionlogHistoryList {
    max-height: 260px;
    overflow-y: auto;
}

.risk-history-item:last-child,
.risk-comment-item:last-child,
.hypothesis-history-item:last-child,
.hypothesis-comment-item:last-child,
.actionlog-history-item:last-child,
.actionlog-comment-item:last-child {
    border-bottom: none;
}
