/* =====================================================================
   COREIDON.AI — CI Projex stylesheet
   Mobile-first; layered with min-width media queries.
   Tokens -> reset -> typography -> utilities -> components -> layout
   -> views -> swarming -> animations -> responsive layers -> touch -> print
   ===================================================================== */

/* ---------------------------------------------------------------------
   1. Tokens (CSS custom properties)
   --------------------------------------------------------------------- */
:root {
    /* Brand surfaces — light */
    --bg-main: #FFFFFF;
    --bg-secondary: #F8F5F0;
    --bg-elevated: #FFFFFF;
    --subtle-bg: #F3F4F6;

    /* Text */
    --text-primary: #000000;
    --text-secondary: #2B303B;
    --text-muted: rgba(43, 48, 59, 0.6);

    /* Brand accents */
    --accent: #091C3A;          /* Navy — primary CTA */
    --accent-cyan: #0284C7;     /* Expressive accent — data, links, focus */
    --accent-glow: rgba(2, 132, 199, 0.18);

    /* Borders */
    --border-color: #E5E7EB;
    --border-subtle: #E5E7EB;
    --border-strong: #D1D5DB;
    --border: 1px solid var(--border-color);
    --glass-border: 1px solid var(--border-subtle);

    /* Inputs */
    --input-bg: #FFFFFF;

    /* Interaction tints */
    --hover-bg: rgba(9, 28, 58, 0.04);
    --active-bg: rgba(2, 132, 199, 0.08);

    /* Semantic */
    --danger: #DC2626;
    --danger-soft: rgba(220, 38, 38, 0.10);
    --success: #16A34A;
    --warning: #F59E0B;

    /* Shadows */
    --card-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
    --card-shadow-hover: 0 6px 16px rgba(9, 28, 58, 0.08);
    --modal-shadow: 0 24px 60px rgba(9, 28, 58, 0.18);

    /* Motion */
    --ease-snappy: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
    --motion-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
    --motion-base: 200ms cubic-bezier(0.4, 0, 0.2, 1);

    /* Radii */
    --radius-sm: 4px;
    --radius-md: 6px;
    --radius-lg: 8px;
    --radius-xl: 10px;
    --radius-pill: 999px;

    /* Aliases (legacy variable names referenced across the codebase) */
    --subtle-border: var(--border-subtle);
    --text-color: var(--text-primary);
    --glass-bg: var(--bg-secondary);
    --scrollbar-thumb: var(--border-strong);
    --scrollbar-thumb-hover: var(--accent-cyan);
    --accent-secondary: var(--accent-cyan);

    /* Per-card project color fallback (overridden inline by JS) */
    --project-color: var(--accent-cyan);
}

body.dark-theme {
    --bg-main: #0A1220;
    --bg-secondary: #2B303B;
    --bg-elevated: #243447;
    --subtle-bg: #121B2A;

    --text-primary: #FFFFFF;
    --text-secondary: rgba(248, 245, 240, 0.75);
    --text-muted: rgba(248, 245, 240, 0.45);

    --accent: #091C3A;
    --accent-cyan: #38BDF8;
    --accent-glow: rgba(56, 189, 248, 0.22);

    --border-color: #2D3D52;
    --border-subtle: #1F2A3C;
    --border-strong: #2D3D52;
    --border: 1px solid var(--border-color);
    --glass-border: 1px solid var(--border-subtle);

    --input-bg: #2B303B;

    --hover-bg: rgba(248, 245, 240, 0.04);
    --active-bg: rgba(56, 189, 248, 0.10);

    --danger: #FB7185;
    --danger-soft: rgba(251, 113, 133, 0.10);
    --success: #34D399;

    --card-shadow: 0 2px 8px rgba(0, 0, 0, 0.40);
    --card-shadow-hover: 0 8px 24px rgba(0, 0, 0, 0.55);
    --modal-shadow: 0 24px 60px rgba(0, 0, 0, 0.6);
}

/* ---------------------------------------------------------------------
   2. Reset & base
   --------------------------------------------------------------------- */
*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
}

html { -webkit-text-size-adjust: 100%; }

/* Global scrollbar layout — reserve a stable gutter on every scrollable
   container so scrollbars never paint on top of content. Only takes effect
   on elements that actually scroll; harmless elsewhere. Add this once and
   future views inherit the same behaviour. */
:where(*) {
    scrollbar-gutter: stable;
}

body {
    background: var(--bg-main);
    color: var(--text-primary);
    height: 100vh;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    transition: background 0.3s, color 0.3s;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    color-scheme: light;
}
body.dark-theme { color-scheme: dark; }

button { font: inherit; color: inherit; }
input, select, textarea { font: inherit; color: inherit; }
a { color: var(--accent-cyan); text-decoration: none; }
a:hover { text-decoration: underline; }

::selection { background: var(--accent); color: #fff; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: 8px; }
::-webkit-scrollbar-thumb:hover { background: var(--scrollbar-thumb-hover); }

/* ---------------------------------------------------------------------
   3. Typography
   --------------------------------------------------------------------- */
h1, h2, h3, h4,
.logo,
.glass-btn,
.view-btn {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: -0.02em;
}

h1 { font-size: clamp(1.1rem, 2.4vw + 0.6rem, 1.6rem); line-height: 1.2; }
h2 { font-size: clamp(1rem, 1.4vw + 0.6rem, 1.25rem); line-height: 1.25; }
h3 { font-size: clamp(0.85rem, 0.6vw + 0.7rem, 1rem); line-height: 1.3; }
h4 { font-size: 0.85rem; line-height: 1.3; }

::placeholder { color: var(--text-muted); opacity: 1; }

/* ---------------------------------------------------------------------
   4. Utilities
   --------------------------------------------------------------------- */
.hidden { display: none !important; }

/* "glass" — kept for backward compatibility with existing markup */
.glass {
    background: var(--bg-main);
    border: 1px solid var(--border-subtle);
}

.glass-panel {
    background: var(--bg-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    padding: 16px;
}
body.dark-theme .glass-panel { background: var(--subtle-bg); }

/* ---------------------------------------------------------------------
   5. Inputs & form controls
   --------------------------------------------------------------------- */
.glass-input,
.glass-select,
.custom-select-trigger {
    width: 100%;
    background: var(--input-bg);
    border: 1px solid var(--border-strong);
    color: var(--text-primary);
    padding: 9px 12px;
    border-radius: var(--radius-md);
    outline: none;
    height: 40px;
    font-size: 0.9rem;
    transition: border-color var(--motion-fast), box-shadow var(--motion-fast), background var(--motion-fast);
}
textarea.glass-input {
    height: auto;
    /* Floor the visible size so the auto-resize JS in board.js / app.js can
       never shrink the field below something readable. Two failure modes
       this guards against: (1) the input-event recalc sets height='auto'
       then height=scrollHeight, which briefly collapses the textarea to
       one line and produces a small→big flicker as content wraps; (2) the
       initial recalc in openTaskModal can run while the task-view is mid-
       transition, reading scrollHeight as ~0 and sticking the inline
       style at a near-zero height. Either way the user keeps a usable
       editing area. */
    min-height: 110px;
    resize: vertical;
    line-height: 1.5;
}

.glass-input:focus,
.glass-select:focus,
.custom-select-trigger:focus {
    border-color: var(--accent-cyan);
    box-shadow: 0 0 0 3px var(--accent-glow);
}

.input-invalid,
.input-invalid:focus {
    border-color: var(--danger) !important;
    /* Stronger ring than the previous 15% alpha — easier to spot when
       the user's eye is on a button further down the form. */
    box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.32) !important;
}
.input-invalid-shake { animation: invalidShake 0.35s ease-in-out; }
/* When a field is marked invalid, recolour the sibling "(Mandatory)" hint
   that sits inside its label. The label sits BEFORE the input in source
   order, so we target it from the input using :has() (Chromium / Safari /
   Firefox 121+). Apps still rendering on older Firefox just keep the
   muted-grey hint — degrades to existing behavior. */
.control-group:has(.input-invalid) .form-hint {
    color: var(--danger);
    font-weight: 600;
}

/* Live character counter under a capped free-text field (attachCharCounter in
   app.js). Hidden until the user passes 80% of the cap so short descriptions
   stay clean, then amber, then red once over the limit. Keeps its box even when
   invisible so appearing doesn't shift the form under the cursor. */
.char-counter {
    font-size: 0.7rem;
    line-height: 1.4;
    text-align: right;
    margin-top: 2px;
    color: var(--warning);
    visibility: hidden;
    font-variant-numeric: tabular-nums;
}
.char-counter.visible { visibility: visible; }
.char-counter.over {
    visibility: visible;
    color: var(--danger);
    font-weight: 600;
}
/* The field is full and just refused a keystroke or truncated a paste. Without
   this the input would simply stop responding, which reads as a broken field. */
.char-counter.blocked {
    visibility: visible;
    color: var(--danger);
    font-weight: 600;
    animation: invalidShake 0.35s ease-in-out;
}

.label-mandatory {
    color: var(--text-muted);
    font-weight: 400;
    font-size: 0.85em;
    margin-left: 4px;
    text-transform: none;
    letter-spacing: 0;
}

label {
    font-size: 0.78rem;
    color: var(--text-secondary);
    font-weight: 500;
}

/* File input — restyle native button to match brand */
input[type="file"] { color: var(--text-secondary); font-family: inherit; font-size: 0.85rem; }
input[type="file"]::file-selector-button,
input[type="file"]::-webkit-file-upload-button {
    background: transparent;
    border: 1px solid var(--border-strong);
    color: var(--text-primary);
    padding: 6px 12px;
    border-radius: var(--radius-sm);
    margin-right: 10px;
    cursor: pointer;
    font-size: 0.75rem;
    text-transform: uppercase;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    letter-spacing: 0.02em;
    transition: var(--ease-snappy);
}
input[type="file"]::file-selector-button:hover,
input[type="file"]::-webkit-file-upload-button:hover {
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
}

/* ---------------------------------------------------------------------
   6. Buttons
   --------------------------------------------------------------------- */
.glass-btn {
    background: transparent;
    border: 1px solid var(--border-strong);
    color: var(--text-primary);
    padding: 9px 16px;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: var(--ease-snappy);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    line-height: 1.1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    text-transform: uppercase;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.glass-btn:hover {
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
    background: var(--hover-bg);
}
.glass-btn:focus-visible {
    outline: none;
    border-color: var(--accent-cyan);
    box-shadow: 0 0 0 3px var(--accent-glow);
}
.glass-btn[disabled] { opacity: 0.4; cursor: not-allowed; }

.glass-btn.primary,
.glass-btn-primary {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}
.glass-btn.primary:hover,
.glass-btn-primary:hover {
    background: #102a55;
    border-color: #102a55;
    color: #fff;
    opacity: 1;
}
body.dark-theme .glass-btn.primary,
body.dark-theme .glass-btn-primary {
    background: var(--accent);
    border-color: #1a2c50;
    color: #fff;
}
body.dark-theme .glass-btn.primary:hover,
body.dark-theme .glass-btn-primary:hover {
    background: #122a52;
    border-color: var(--accent-cyan);
}

.glass-btn-sm {
    background: transparent;
    border: 1px solid var(--border-strong);
    color: var(--text-primary);
    padding: 5px 10px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    line-height: 1.1;
    transition: var(--ease-snappy);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.glass-btn-sm:hover {
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
    background: var(--hover-bg);
}
.glass-btn-sm[disabled] { opacity: 0.4; cursor: not-allowed; }

.glass-btn-sm.primary,
.glass-btn.primary.glass-btn-sm {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

body.dark-theme .glass-btn,
body.dark-theme .glass-btn-sm {
    background: rgba(255, 255, 255, 0.02);
    border-color: var(--border-strong);
    color: var(--text-primary);
}
body.dark-theme .glass-btn:hover,
body.dark-theme .glass-btn-sm:hover {
    background: var(--bg-elevated);
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
}

/* Icon button (borderless) */
.icon-btn {
    background: transparent;
    border: 1px solid var(--border-strong);
    color: var(--text-primary);
    width: 36px;
    height: 36px;
    border-radius: var(--radius-md);
    padding: 6px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: var(--ease-snappy);
}
.icon-btn:hover {
    background: var(--hover-bg);
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
}
.icon-btn:focus-visible {
    outline: none;
    border-color: var(--accent-cyan);
    box-shadow: 0 0 0 3px var(--accent-glow);
}
.icon-btn svg { width: 100%; height: 100%; stroke: currentColor; }
.icon-btn-danger:hover {
    background: rgba(220, 38, 38, 0.10);
    border-color: var(--danger);
    color: var(--danger);
}

.icon-slot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    flex-shrink: 0;
}

/* Overview action button (kept selector) */
button.overview-action-btn {
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--border-strong);
    background: transparent !important;
    color: var(--text-secondary);
    border-radius: var(--radius-md);
    cursor: pointer;
    font-size: 0.85rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: var(--ease-snappy);
    line-height: 1;
}
.overview-action-btn:hover {
    background: var(--active-bg);
    color: var(--accent-cyan);
    border-color: var(--accent-cyan);
}
.overview-action-btn-danger:hover {
    background: var(--danger-soft);
    color: var(--danger);
    border-color: var(--danger);
}

/* Mobile menu toggle (always 44x44 on touch via media query at end) */
.mobile-menu-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-md);
    cursor: pointer;
    font-size: 1.2rem;
    flex-shrink: 0;
    background: transparent;
    border: 1px solid var(--border-strong);
    color: var(--text-primary);
    transition: var(--ease-snappy);
}
.mobile-menu-toggle:hover {
    background: var(--hover-bg);
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
}

/* ---------------------------------------------------------------------
   7. Loading overlay
   --------------------------------------------------------------------- */
.loading-overlay {
    position: fixed;
    inset: 0;
    background: var(--bg-main);
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: opacity 0.4s ease, visibility 0.4s ease;
}
.loading-overlay.hidden {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}
.loading-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 18px;
}
.loading-logo {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-size: clamp(1.7rem, 4vw, 2.5rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--text-primary);
    text-transform: uppercase;
}
.loading-logo .highlight { color: var(--accent); }
body.dark-theme .loading-logo .highlight { color: var(--accent-cyan); }
.loading-spinner {
    width: 42px;
    height: 42px;
    border: 2px solid var(--border-subtle);
    border-top-color: var(--accent-cyan);
    border-radius: 50%;
    animation: spin 0.9s linear infinite;
}
.loading-text {
    font-size: 0.85rem;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

/* ---------------------------------------------------------------------
   8. App shell layout (mobile-first)
   --------------------------------------------------------------------- */
.app-container {
    display: flex;
    flex: 1;
    min-height: 0;
    position: relative;
}

/* Sidebar — off-canvas taskView (slides from right) by default */
.sidebar {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(86%, 320px);
    z-index: 1000;
    display: flex;
    flex-direction: column;
    padding: 20px 16px;
    background: var(--bg-secondary);
    border-left: 1px solid var(--border-subtle);
    transform: translateX(100%);
    transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
    overflow-y: auto;
    overscroll-behavior: contain;
}
.sidebar.mobile-open {
    transform: translateX(0);
    box-shadow: -16px 0 40px rgba(9, 28, 58, 0.18);
}
body.dark-theme .sidebar.mobile-open {
    box-shadow: -16px 0 40px rgba(0, 0, 0, 0.6);
}

.sidebar-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(9, 28, 58, 0.45);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    z-index: 999;
}
.sidebar-overlay.active { display: block; }

/* Main content fills the rest */
.main-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    position: relative;
    min-height: 0;
    transition: opacity 0.2s ease, transform 0.2s ease;
}
.main-content.project-loading {
    opacity: 0;
    transform: translateY(5px);
}
.main-content.hidden { display: none !important; }
#overview-view,
#document-view,
#help-view { overflow-y: auto; }

/* ---------------------------------------------------------------------
   9. Sidebar — brand, nav, profile
   --------------------------------------------------------------------- */
.sidebar-header {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    margin-bottom: 24px;
    width: 100%;
}
.sidebar-header > div:first-child { flex: 1; }
.sidebar-header .brand-identity { flex: 1; }

.brand-identity {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 2px;
}
/* The .logo div is dual-purpose: starts as text fallback, JS swaps in an SVG mark.
   Constrain it to a square so the SVG (which renders at 100%) cannot blow up. */
.brand-identity .logo {
    width: 34px;
    height: 34px;
    flex: 0 0 34px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 0;
}
.brand-identity .logo svg {
    width: 100%;
    height: 100%;
    display: block;
}
.logo {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: 0.02em;
    color: var(--text-primary);
    text-transform: uppercase;
    line-height: 1.1;
}
.logo .highlight { color: var(--accent-cyan); }
body.dark-theme .logo .highlight { color: var(--accent-cyan); }
.logo-text {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 1.1rem;
    letter-spacing: 0.04em;
    color: var(--text-primary);
    text-transform: uppercase;
}
.logo-subtitle {
    font-size: 0.7rem;
    color: var(--text-muted);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-top: 2px;
}
.app-name {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 0.72rem;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.nav-section { margin-bottom: 18px; }
.nav-section h3 {
    font-size: 0.66rem;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 8px;
    font-weight: 700;
    letter-spacing: 0.1em;
}
.nav-section ul { list-style: none; padding: 0; margin: 0; }
.nav-section li {
    padding: 9px 12px;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: var(--ease-snappy);
    color: var(--text-primary);
    font-size: 0.88rem;
    margin-bottom: 2px;
    display: flex;
    align-items: center;
    gap: 8px;
    border-left: 2px solid transparent;
}
.nav-section li:hover {
    background: var(--hover-bg);
    color: var(--text-primary);
}
.nav-section li.active {
    background: var(--active-bg);
    color: var(--accent-cyan);
    border-left-color: var(--accent-cyan);
    padding-left: 10px;
    font-weight: 700;
}
.nav-section li a.nav-link {
    display: block;
    flex: 1;
    color: inherit;
    text-decoration: none;
    font: inherit;
}
.nav-section li a.nav-link:hover,
.nav-section li a.nav-link:focus {
    color: inherit;
    text-decoration: none;
}

#project-list {
    max-height: 240px;
    overflow-y: auto;
    padding-right: 2px;
    list-style: none;
    margin: 0;
}
#project-list li {
    color: var(--project-color);
    display: flex;
    justify-content: space-between;
    align-items: center;
}
#project-list li:hover { background: var(--hover-bg); }

/* Sidebar collapsed state (desktop only effect — kept for completeness) */
.sidebar.collapsed .brand-identity,
.sidebar.collapsed .app-name,
.sidebar.collapsed .logo-subtitle,
.sidebar.collapsed .nav-section h3,
.sidebar.collapsed .user-info,
.sidebar.collapsed .nav-section li,
.sidebar.collapsed .custom-select-wrapper,
.sidebar.collapsed .theme-switcher { display: none !important; }
.sidebar.collapsed .user-profile {
    display: flex;
    justify-content: center;
    padding: 5px;
    background: transparent;
    border: none;
}
.sidebar.collapsed .user-actions { display: none !important; }
.sidebar.collapsed #btn-open-admin { display: none !important; }
.sidebar.collapsed .sidebar-header { justify-content: center; align-items: center; }
.sidebar.collapsed .logo { display: block; margin-bottom: 0; }

/* User profile card */
.user-profile {
    margin-top: auto;
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 12px;
    padding: 14px;
    border-radius: var(--radius-lg);
    background: var(--bg-elevated);
    border: 1px solid var(--border-strong);
    align-items: center;
}
body.dark-theme .user-profile {
    background: var(--bg-elevated);
    border-color: var(--border-strong);
}
.user-info {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    min-width: 0;
}
.user-info #current-user-name {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 0.86rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}
.user-actions {
    grid-column: 1 / -1;
    display: flex;
    gap: 8px;
    margin-top: 4px;
}
.user-actions .icon-btn { flex: 1; }
/* Match the 44px height of the <coreidon-notifications> / <coreidon-support>
   cards so the cog sits level with them instead of pinned to the top, and
   mute the gear to the same 65%-of-text grey the bell/headset glyphs use. */
.user-actions #btn-open-admin {
    height: 44px;
    color: color-mix(in srgb, currentColor 75%, transparent);
}
/* Size the gear to match the headset (21px) instead of filling the button,
   keep its regular 2px stroke, and nudge it down 2px to sit optically centred. */
.user-actions #btn-open-admin svg {
    width: 21px;
    height: 21px;
    stroke-width: 2;
    transform: translateY(2px);
}
/* Support card's border a hair darker than the widget's 14% default. Scoped
   to projex via the widget's own --cs-border custom property — the shared
   support-widget.js (and the glyph fill) is untouched. */
.user-actions coreidon-support {
    --cs-border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
}
/* AI-credit balance widget (smart_wallet's <coreidon-wallet>). Feed it the app
   palette via its host CSS vars and let it sit as a 44px button beside the bell
   and headset. The low-balance red stroke (--cw-danger) is left at its default
   so it still stands out. data-theme is stamped from app.js to track the toggle. */
.user-actions coreidon-wallet {
    --cw-fg: var(--text-primary);
    --cw-accent: var(--accent-cyan);
    display: inline-flex;
    align-items: center;
}

.avatar {
    width: 36px;
    height: 36px;
    background: var(--accent);
    border-radius: var(--radius-lg);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 0.8rem;
    flex-shrink: 0;
    letter-spacing: 0.02em;
}

/* Theme switcher */
.theme-switcher {
    display: flex;
    width: 100%;
    margin: 8px 0;
}
.theme-toggle-btn {
    width: 100%;
    justify-content: center;
    gap: 8px;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    height: 38px;
    border-radius: var(--radius-pill);
    background: transparent;
    border: 1px solid var(--border-strong);
    color: var(--text-primary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    transition: var(--ease-snappy);
    padding: 0 14px;
    letter-spacing: 0.04em;
}
.theme-toggle-btn:hover {
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
    background: var(--hover-bg);
}

/* ---------------------------------------------------------------------
   10. Top bar
   --------------------------------------------------------------------- */
.top-bar {
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    background: var(--bg-main);
    border-bottom: 1px solid var(--border-subtle);
    z-index: 5;
    flex-shrink: 0;
}
.top-bar.glass {
    background: var(--bg-main);
    border-left: none;
    border-right: none;
    border-top: none;
}

.top-bar-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    flex-shrink: 0;
    width: 100%;
}
.top-bar-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}
.timeline-filter-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.85rem;
    color: var(--text-secondary);
}
.timeline-filter-label select {
    min-width: 180px;
}
.top-bar-row .project-info {
    flex: 1;
    min-width: 0;
}
.top-bar-row .project-info h1 {
    word-break: break-word;
    overflow-wrap: anywhere;
}

.project-info {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}
.project-info h1 {
    color: var(--project-color, var(--text-primary));
    font-size: clamp(1.05rem, 2vw + 0.5rem, 1.5rem);
}

.deadline-badge {
    font-size: 0.7rem;
    color: var(--accent-cyan);
    background: var(--active-bg);
    border: 1px solid var(--accent-cyan);
    padding: 3px 8px;
    border-radius: var(--radius-pill);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

/* View switcher tabs */
.view-switcher {
    display: flex;
    gap: 0;
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    overflow-x: auto;
    padding: 3px;
    scrollbar-width: none;
}
.view-switcher::-webkit-scrollbar { display: none; }
.view-btn {
    background: transparent;
    border: none;
    color: var(--text-muted);
    padding: 7px 14px;
    cursor: pointer;
    font-size: 0.7rem;
    transition: var(--ease-snappy);
    white-space: nowrap;
    border-radius: var(--radius-sm);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    letter-spacing: 0.04em;
}
.view-btn:hover {
    color: var(--text-primary);
    background: var(--hover-bg);
}
.view-btn.active {
    background: var(--accent);
    color: #fff;
    box-shadow: 0 1px 2px rgba(9, 28, 58, 0.2);
}
body.dark-theme .view-btn.active {
    background: var(--accent-cyan);
    color: #0A1220;
}

.controls {
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: stretch;
    width: 100%;
}
.controls-buttons {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
}
.controls-buttons .glass-btn,
.controls-buttons .glass-btn-sm { flex: 1 1 auto; }

.control-group {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 0;
}
.control-group label {
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

/* ---------------------------------------------------------------------
   11. Board / Swimlanes / Columns / Tasks
   --------------------------------------------------------------------- */
.board-container {
    flex: 1 1 0;
    overflow-y: auto;
    padding: 14px;
    min-height: 0;
}

.swimlane {
    background: var(--bg-main);
    margin-bottom: 16px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    overflow: hidden;
    box-shadow: var(--card-shadow);
}
body.dark-theme .swimlane {
    background: var(--subtle-bg);
}
.swimlane.collapsed .swimlane-content { display: none; }

.swimlane-header {
    padding: 12px 16px;
    background: var(--bg-secondary);
    display: flex;
    justify-content: space-between;
    align-items: center;
    cursor: pointer;
    user-select: none;
    border-bottom: 1px solid var(--border-subtle);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 0.85rem;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    transition: background var(--motion-fast);
}
.swimlane-header:hover { background: var(--hover-bg); }
/* Reorderable header: grab cursor + a drag-handle affordance. */
.swimlane-header.swimlane-reorderable { cursor: grab; }
.swimlane-header.swimlane-reorderable:active { cursor: grabbing; }
.swimlane-drag-handle {
    margin-right: 8px;
    color: var(--text-muted);
    font-size: 1rem;
    line-height: 1;
    cursor: grab;
}
/* The swimlane currently being dragged. */
.swimlane.swimlane-dragging { opacity: 0.5; }
/* Insertion indicator while dragging a swimlane over a drop target. */
.swimlane.drop-before { box-shadow: inset 0 3px 0 0 var(--accent-cyan); }
.swimlane.drop-after { box-shadow: inset 0 -3px 0 0 var(--accent-cyan); }

.swimlane-content {
    gap: 12px;
    padding: 12px;
    overflow-x: auto;
    display: flex;
    align-items: stretch;
}

.workflow-section {
    background: var(--bg-main);
    border-radius: var(--radius-lg);
    border: 1px solid var(--border-subtle);
    margin-right: 12px;
    display: flex;
    flex-direction: column;
    min-width: 280px;
    transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
    flex-shrink: 0;
}
body.dark-theme .workflow-section {
    background: var(--bg-secondary);
}

.workflow-section.collapsed {
    min-width: 44px;
    width: 44px;
    cursor: pointer;
    background: var(--subtle-bg);
}
.workflow-section.collapsed .workflow-columns { display: none; }
.workflow-section.collapsed .workflow-header {
    justify-content: center;
    writing-mode: vertical-rl;
    text-orientation: mixed;
    padding: 12px 0;
    gap: 10px;
    background: transparent;
    border: none;
}

.workflow-header {
    padding: 10px 14px;
    background: var(--bg-secondary);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-primary);
    display: flex;
    justify-content: space-between;
    align-items: center;
    cursor: pointer;
    border-bottom: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}

.workflow-columns {
    display: grid;
    /* grid-template-columns is set inline per-swimlane as
       repeat(N, minmax(260px, 1fr)) so columns grow to fill when they fit
       and overflow horizontally (via .swimlane-content's overflow-x:auto)
       when they don't. No static min-width — that was the old fixed-3-col
       assumption and it's what made wide screens look half-empty.

       flex: 1 stretches us to fill the .swimlane-content flex parent; without
       it the grid sizes to max-content (≈ task-card width × N) and the 1fr
       tracks have nothing to distribute against, so columns never grow.
       Leaving min-width as its flex default of `auto` (= min-content = the
       sum of track minimums) means too-many-columns naturally overflow the
       flex parent, and .swimlane-content's overflow-x:auto picks up the
       horizontal scroll. */
    flex: 1;
    gap: 10px;
    padding: 10px;
}

.column {
    background: var(--subtle-bg);
    border-radius: var(--radius-md);
    padding: 10px;
    min-height: 120px;
    min-width: 0;
    border: 1px solid var(--border-subtle);
}
body.dark-theme .column {
    background: var(--subtle-bg);
    border-color: var(--border-subtle);
}

/* Cap each column's task list to ~13 cards before scrolling so a backlog
   doesn't blow the swimlane vertically. Cards have variable height (chapter,
   checklist, blocked badge…), so the cap is an approximation: 13 cards at a
   typical ~88px each plus their 8px margin-bottom. Drag-and-drop and auto-
   scroll continue to work inside the scrollable area. Quick-add lives outside
   .task-list, so it stays anchored at the bottom. */
.task-list {
    --task-card-approx-h: 88px;
    --task-card-gap: 8px;
    max-height: calc(13 * (var(--task-card-approx-h) + var(--task-card-gap)));
    overflow-y: auto;
    /* Slim, theme-aware scrollbar so the cap is felt but not visually noisy. */
    scrollbar-width: thin;
}
.task-list::-webkit-scrollbar { width: 8px; }
.task-list::-webkit-scrollbar-thumb {
    background: var(--border-subtle);
    border-radius: 4px;
}
.task-list::-webkit-scrollbar-thumb:hover { background: var(--border-strong); }

.column-header {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-size: 0.72rem;
    font-weight: 700;
    margin-bottom: 10px;
    text-align: left;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-secondary);
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-left: 10px;
    border-left: 3px solid var(--text-muted);
}

/* Column status colors */
.column[data-status*="backlog"] .column-header { border-left-color: var(--border-strong); color: var(--text-muted); }
.column[data-status*="doing"]   .column-header { border-left-color: var(--warning); color: var(--warning); }
.column[data-status*="done"]    .column-header { border-left-color: var(--success); color: var(--success); }
.column[data-status="dev_done"][data-section="qa"]  .column-header { border-left-color: var(--text-muted); color: var(--text-muted); }
.column[data-status="qa_done"][data-section="ops"]  .column-header { border-left-color: var(--text-muted); color: var(--text-muted); }

/* Tasks */
.task-card {
    background: var(--bg-main);
    padding: 12px;
    border-radius: var(--radius-lg);
    margin-bottom: 8px;
    cursor: grab;
    border: 1px solid var(--border-subtle);
    border-left: 4px solid var(--project-color, var(--accent-cyan));
    box-shadow: var(--card-shadow);
    transition: transform var(--motion-base), box-shadow var(--motion-base), border-color var(--motion-base);
    position: relative;
}
body.dark-theme .task-card { background: var(--bg-elevated); }

.task-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--card-shadow-hover);
    border-color: var(--accent-cyan);
}

.task-card.selected {
    border-color: var(--accent-cyan);
    box-shadow: 0 0 0 2px var(--accent-glow);
    background: var(--active-bg);
}

.task-card.dragging {
    opacity: 0.5;
    border: 1px dashed var(--border-strong);
    cursor: grabbing;
}

/* Without this, a mousedown that lands on a text node inside the card lets
   text-selection win over drag initiation — the user sees a text caret
   instead of a drag image. Applies to every draggable card, board + my-tasks. */
.task-card[draggable="true"] {
    user-select: none;
    -webkit-user-select: none;
}

.task-card.is-subtask {
    background: var(--subtle-bg);
    border: 1px dashed var(--border-strong);
    border-left: 4px solid var(--project-color, var(--accent-cyan));
}
.task-card.is-subtask .task-title::before {
    content: '↳ ';
    color: var(--text-muted);
}
.task-card.is-resolved { opacity: 0.65; }

.task-card.blocked {
    background: linear-gradient(135deg, var(--danger-soft) 0%, transparent 90%);
    border: 1px solid var(--danger);
    border-left: 4px solid var(--danger);
    animation: pulse-blocked 2.4s ease-in-out infinite;
}
.task-card.blocked .task-title { color: var(--danger); font-weight: 700; }

.task-tags {
    display: flex;
    gap: 5px;
    margin-bottom: 8px;
    flex-wrap: wrap;
}

.task-group {
    font-size: 0.66rem;
    color: var(--text-muted);
    margin-bottom: 4px;
    display: block;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 700;
}
.task-title {
    font-weight: 600;
    font-size: 0.92rem;
    margin-bottom: 6px;
    color: var(--text-primary);
    line-height: 1.3;
}
.task-meta {
    display: flex;
    justify-content: space-between;
    align-items: center;
    /* Wrap on narrow columns so the time / resolved / deadline chips drop to a
       new line instead of overflowing the card edge. */
    flex-wrap: wrap;
    gap: 6px;
    font-size: 0.72rem;
    color: var(--text-muted);
    margin-top: 8px;
}

/* Deadline pill — shared by board cards, list rows and gantt labels.
   Neutral by default; amber = due soon, red = overdue. Done tasks are never
   flagged (deadlineStatus() returns null), so their pill stays neutral. */
.task-deadline {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    white-space: nowrap;
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.4;
    padding: 1px 6px;
    border-radius: var(--radius-sm);
    color: var(--text-muted);
    background: var(--subtle-bg);
}
.task-deadline.due-soon {
    color: var(--warning);
    background: rgba(245, 158, 11, 0.14);
}
.task-deadline.overdue {
    color: var(--danger);
    background: var(--danger-soft);
}
/* Deadline pinned to the card's top-right corner. The card is position:
   relative, so this anchors to its padding box. */
.task-card-deadline {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 1;
}
/* Reserve room on the first tag row so the priority / blocked / recurrence
   badges wrap instead of sliding under the corner deadline chip. Scoped to
   cards that actually carry one. */
.task-card:has(.task-card-deadline) .task-tags { padding-right: 84px; }
/* Document view deadline — same overdue/due-soon colour schema as the cards.
   Covers read-mode prose text, the <strong> emitted by docInlineDate's read
   mode, and the edit-mode date input. */
.doc-deadline.due-soon,
.doc-deadline.due-soon strong,
.doc-deadline.due-soon .doc-inline-date { color: var(--warning); }
.doc-deadline.overdue,
.doc-deadline.overdue strong,
.doc-deadline.overdue .doc-inline-date { color: var(--danger); }
/* "Resolved" date chip — green to echo .resolved-badge, sized like the
   deadline pill so it sits naturally in card / list / timeline meta rows. */
.resolved-date {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    white-space: nowrap;
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.4;
    padding: 1px 6px;
    border-radius: var(--radius-sm);
    color: var(--success);
    background: rgba(22, 163, 74, 0.12);
}
.timeline-label .resolved-date { margin-left: 8px; }
/* Global vs Local badge next to a PM's name in the admin PM list. */
.pm-scope-badge {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 7px;
    border-radius: var(--radius-pill);
    font-size: 0.62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    vertical-align: middle;
}
.pm-scope-global { color: var(--accent-cyan); background: rgba(34, 211, 238, 0.14); }
.pm-scope-local  { color: var(--warning);     background: rgba(245, 158, 11, 0.14); }
/* List view: keep the deadline pill in its own flex cell, right-aligned with
   the time cell. */
.task-row-deadline {
    display: flex;
    justify-content: flex-end;
    min-width: 92px;
}
.task-children-preview {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--border-subtle);
    font-size: 0.72rem;
    color: var(--text-secondary);
}

/* Subtask nesting */
.subtask-group {
    padding-left: 16px;
    border-left: 2px solid var(--border-subtle);
    margin-left: 8px;
}

/* Per-parent subtask fold. The handle is its own slim card tucked under the
   parent — same surface, border and corner radius as the card above it — with
   the arrow centred. Folded, it also carries the hidden-child count, which is
   the one thing the collapsed state hides from you.

   Sized for the phone first: a full-bleed strip only a few pixels tall, its
   own height driven by the arrow's em size rather than a fixed pixel box, so
   it scales with the user's text size instead of fighting it. */
.subtask-fold-bar {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    width: 100%;
    /* The card above owns an 8px bottom margin; pull the lid up against it so
       the pair reads as one stack rather than two loose blocks. */
    margin: -4px 0 8px;
    padding: 0;
    min-height: 15px;
    font: inherit;
    font-size: 0.6rem;
    font-weight: 700;
    line-height: 1;
    color: var(--text-muted);
    background: var(--bg-main);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    box-shadow: var(--card-shadow);
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    /* No double-tap-zoom delay, and no grey flash over a strip this thin. */
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    transition: color var(--motion-base), background var(--motion-base), border-color var(--motion-base);
}
/* The strip is deliberately thinner than the 40px minimum mobile.css puts on
   every button (hence .no-touch-min on it), so it earns its tap area back
   invisibly: this extender fills the dead gap above and below without growing
   the visible rectangle. The insets equal the bar's own margins exactly, so it
   reaches to — never into — the card above and whatever follows below. */
.subtask-fold-bar::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: -4px;
    bottom: -8px;
}
body.dark-theme .subtask-fold-bar { background: var(--bg-elevated); }
.subtask-fold-bar:hover {
    color: var(--accent-cyan);
    background: var(--hover-bg);
    border-color: var(--accent-cyan);
}
.subtask-fold-bar:focus-visible {
    outline: 2px solid var(--accent-cyan);
    outline-offset: 1px;
}
.subtask-fold-arrow {
    font-size: 0.52rem;
    line-height: 1;
}
/* Folded reads as "there is more here": the lid picks up the accent colour and
   spells out how many subtasks are underneath it. */
.subtask-fold-bar.is-collapsed {
    color: var(--accent-cyan);
    border-color: var(--accent-cyan);
}
.subtask-fold-count { letter-spacing: 0.04em; }

/* List rows are a flat stack with tighter spacing and a smaller radius than
   board cards, so the lid matches its own neighbours there — and its tap
   extender has to match the tighter margins too. */
.list-status-group > .subtask-fold-bar {
    margin: -3px 0 6px;
    border-radius: var(--radius-md);
}
.list-status-group > .subtask-fold-bar::before {
    top: -3px;
    bottom: -6px;
}

/* A mouse doesn't need the padded tap area, so on pointer-precise screens the
   strip is exactly as tall as it looks. */
@media (hover: hover) and (pointer: fine) {
    .subtask-fold-bar::before { content: none; }
}

/* Tags & badges */
.tag {
    display: inline-block;
    font-size: 0.62rem;
    padding: 3px 8px;
    border-radius: var(--radius-sm);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 700;
    line-height: 1;
}
.tag.high {
    background: rgba(220, 38, 38, 0.12);
    color: var(--danger);
    border: 1px solid rgba(220, 38, 38, 0.3);
}
body.dark-theme .tag.high {
    background: rgba(251, 113, 133, 0.12);
    border-color: rgba(251, 113, 133, 0.3);
}
.tag.medium {
    background: transparent;
    color: var(--text-secondary);
    border: 1px solid var(--border-strong);
}
.tag.low {
    background: rgba(22, 163, 74, 0.12);
    color: var(--success);
    border: 1px solid rgba(22, 163, 74, 0.3);
}
body.dark-theme .tag.low {
    background: rgba(52, 211, 153, 0.12);
    border-color: rgba(52, 211, 153, 0.3);
}
.tag.active {
    background: rgba(22, 163, 74, 0.12);
    color: var(--success);
    border: 1px solid rgba(22, 163, 74, 0.3);
}
body.dark-theme .tag.active {
    background: rgba(52, 211, 153, 0.12);
    border-color: rgba(52, 211, 153, 0.3);
}
.tag.planning {
    background: var(--subtle-bg);
    color: var(--text-secondary);
    border: 1px solid var(--border-strong);
}
.tag.archived {
    background: var(--subtle-bg);
    color: var(--text-muted);
    border: 1px solid var(--border-subtle);
}
body.light-theme .tag.medium,
body.light-theme .tag.planning { color: var(--text-secondary); }

/* Small icon-only "recurring task" indicator — sits in card tag rows, list /
   timeline meta and document headings whenever a task is tied to a repeat
   schedule (has recurrence_id). Monochrome glyph so it themes with the accent. */
.recurrence-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.9rem;
    line-height: 1;
    font-weight: 700;
    color: var(--primary, #6366f1);
    margin-left: 4px;
    cursor: default;
}

.blocked-badge {
    background: var(--danger);
    color: #fff;
    font-size: 0.62rem;
    padding: 2px 7px;
    border-radius: var(--radius-sm);
    font-weight: 700;
    margin-right: 5px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.resolved-badge {
    background: var(--success);
    color: #fff;
    padding: 2px 7px;
    border-radius: var(--radius-sm);
    font-size: 0.62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-left: 6px;
}
body.dark-theme .resolved-badge { color: #002010; }

/* Resolved pill above the task title in the task detail view. */
.task-view-resolved-badge {
    display: inline-block;
    margin-left: 0;
    margin-bottom: 8px;
}

.block-reason-text {
    font-size: 0.74rem;
    color: var(--danger);
    margin-top: 6px;
    font-style: italic;
}

/* Highlight pulse animation (used by board.js) */
.highlight-pulse {
    animation: highlightPulse 2s ease-in-out;
}
@keyframes highlightPulse {
    0%   { box-shadow: 0 0 0 0 var(--accent-glow); border-color: var(--accent-cyan); }
    50%  { box-shadow: 0 0 0 8px transparent; }
    100% { box-shadow: 0 0 0 0 transparent; }
}

/* ---------------------------------------------------------------------
   12. Swarming UI — calmed-down brand version
   --------------------------------------------------------------------- */
.swarming-banner {
    position: relative;
    width: 100%;
    min-height: 48px;
    background: var(--accent);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 100;
    font-weight: 500;
    padding: 12px 60px 12px 56px;
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.05);
    animation: slideDown 0.3s ease-out;
    border-bottom: 2px solid var(--danger);
    overflow: hidden;
    font-size: 0.85rem;
    letter-spacing: 0.02em;
}
.swarming-banner.hidden { display: none !important; }
.swarming-banner::before {
    content: '';
    position: absolute;
    left: 24px;
    top: 50%;
    transform: translateY(-50%);
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--danger);
    box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.7);
    animation: indicatorBlink 2s ease-in-out infinite;
}
.swarming-banner span { position: relative; z-index: 1; }
.swarming-banner b {
    color: #fff;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin-right: 6px;
}

/* Floating button on the right edge */
.swarming-floating-btn {
    position: fixed;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    z-index: 1001;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 44px;
    padding: 18px 10px;
    background: var(--accent);
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-right: none;
    border-radius: 10px 0 0 10px;
    cursor: pointer;
    transition: width 0.2s var(--motion-fast), padding 0.2s var(--motion-fast), box-shadow 0.2s var(--motion-fast);
    box-shadow: -2px 0 12px rgba(9, 28, 58, 0.18);
    overflow: visible;
}
.swarming-floating-btn.hidden { display: none !important; }
.swarming-floating-btn-indicator {
    width: 8px;
    height: 8px;
    background: var(--danger);
    border-radius: 50%;
    margin-bottom: 10px;
    animation: indicatorBlink 1.8s ease-in-out infinite;
    box-shadow: 0 0 0 2px rgba(220, 38, 38, 0.25);
}
.swarming-floating-btn-text {
    writing-mode: vertical-rl;
    text-orientation: mixed;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.16em;
    color: #fff;
    text-transform: uppercase;
}
.swarming-floating-btn-expanded {
    position: absolute;
    right: 100%;
    top: 50%;
    transform: translateY(-50%) translateX(12px);
    opacity: 0;
    pointer-events: none;
    background: var(--bg-elevated);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-lg);
    padding: 16px;
    min-width: 180px;
    text-align: center;
    transition: opacity 0.18s var(--motion-fast), transform 0.18s var(--motion-fast);
    box-shadow: var(--modal-shadow);
    color: var(--text-primary);
}
body.dark-theme .swarming-floating-btn-expanded {
    background: var(--bg-elevated);
    border-color: var(--border-strong);
}
.swarming-floating-btn-expanded::after {
    content: '';
    position: absolute;
    right: -8px;
    top: 50%;
    transform: translateY(-50%);
    border: 8px solid transparent;
    border-left-color: var(--border-strong);
}
.swarming-floating-btn:hover {
    width: 50px;
    padding: 22px 12px;
    box-shadow: -4px 0 16px rgba(9, 28, 58, 0.28);
}
.swarming-floating-btn:hover .swarming-floating-btn-expanded {
    opacity: 1;
    transform: translateY(-50%) translateX(-4px);
    pointer-events: auto;
}
.swarming-blocked-count {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-size: 2rem;
    font-weight: 700;
    color: var(--danger);
    line-height: 1;
    margin-bottom: 4px;
}
.swarming-floating-btn-expanded span {
    font-size: 0.78rem;
    color: var(--text-secondary);
    display: block;
    margin-bottom: 12px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.swarming-view-btn {
    background: var(--accent);
    color: #fff;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 8px 14px;
    border-radius: var(--radius-md);
    transition: background var(--motion-fast);
    cursor: pointer;
    border: 1px solid var(--accent);
}
.swarming-view-btn:hover { background: #102a55; }

/* Blocked swimlane / workflow / sidebar project — calm danger accent */
.swimlane.has-blocked {
    border-color: var(--danger);
}
.swimlane.has-blocked .swimlane-header {
    position: relative;
    background: linear-gradient(90deg, var(--danger-soft) 0%, transparent 70%);
    color: var(--danger);
    border-bottom-color: var(--danger);
}
.swimlane.has-blocked .swimlane-header::before {
    content: '';
    width: 8px;
    height: 8px;
    background: var(--danger);
    border-radius: 50%;
    margin-right: 8px;
    flex-shrink: 0;
    animation: indicatorBlink 2s ease-in-out infinite;
}

.workflow-section.group-blocked {
    border-color: var(--danger);
}
.workflow-section.group-blocked .workflow-header {
    background: var(--danger-soft);
    color: var(--danger);
    border-bottom-color: var(--danger);
}
.workflow-section.group-blocked .workflow-header::before {
    content: '';
    display: inline-block;
    width: 8px;
    height: 8px;
    background: var(--danger);
    border-radius: 50%;
    margin-right: 8px;
    animation: indicatorBlink 2s ease-in-out infinite;
}
.workflow-section.group-blocked.collapsed {
    background: var(--danger-soft);
}

#project-list li.has-blocked,
#project-list li.has-blocked.active,
#project-list li.has-blocked:hover {
    border-left: 3px solid var(--danger);
    padding-left: 9px;
    color: var(--danger) !important;
}
#project-list li.has-blocked::before {
    content: '';
    display: inline-block;
    width: 6px;
    height: 6px;
    background: var(--danger);
    border-radius: 50%;
    margin-right: 6px;
    flex-shrink: 0;
    animation: indicatorBlink 2s ease-in-out infinite;
}
#project-list li.has-blocked span { position: relative; z-index: 1; }

/* ---------------------------------------------------------------------
   13. Modals
   --------------------------------------------------------------------- */
.modal {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0);
    /* Must sit above the sidebar (z-index: 1000), which is position:relative on
       desktop and would otherwise paint over the modal's transparent backdrop. */
    z-index: 2000;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 12px;
    animation: modalBackdropIn 0.25s ease-out forwards;
}
.modal.hidden { display: none !important; }
.modal-content {
    width: 100%;
    max-width: 720px;
    max-height: calc(100vh - 24px);
    padding: 22px 18px;
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--bg-main);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-xl);
    box-shadow: var(--modal-shadow);
    animation: modalContentIn 0.3s ease-out forwards;
    overflow-y: auto;
}
body.dark-theme .modal-content {
    background: var(--bg-elevated);
    border-color: var(--border-strong);
}
.modal-content.glass {
    background: var(--bg-main);
}
body.dark-theme .modal-content.glass {
    background: var(--bg-elevated);
}
.close-modal {
    position: absolute;
    top: 12px;
    right: 16px;
    font-size: 1.6rem;
    line-height: 1;
    cursor: pointer;
    color: var(--text-muted);
    transition: color var(--motion-fast);
    background: transparent;
    border: none;
    z-index: 2;
}
.close-modal:hover { color: var(--danger); }

#team-modal .modal-content {
    max-width: 900px;
}

/* Members list inside the Edit Team modal. It lives in a flex-column modal, and
   `overflow-y: auto` strips a flex item's automatic min-size — on a short screen
   the list would collapse to near-zero height and its rows would be hidden behind
   the sections below. A min-height keeps rows visible; max-height caps it so a
   long roster scrolls within the list instead of pushing the modal off-screen. */
.team-members-list {
    overflow-y: auto;
    min-height: 120px;
    max-height: 40vh;
}

.modal-tabs {
    display: flex;
    gap: 4px;
    margin-bottom: 18px;
    border-bottom: 1px solid var(--border-subtle);
    overflow-x: auto;
    scrollbar-width: none;
}
.modal-tabs::-webkit-scrollbar { display: none; }
.modal-tab-btn {
    background: transparent;
    border: none;
    padding: 10px 16px;
    color: var(--text-muted);
    cursor: pointer;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    border-bottom: 2px solid transparent;
    transition: all var(--motion-fast);
    white-space: nowrap;
}
.modal-tab-btn:hover {
    color: var(--text-primary);
    background: var(--hover-bg);
}
.modal-tab-btn.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}
body.dark-theme .modal-tab-btn.active {
    color: var(--accent-cyan);
    border-bottom-color: var(--accent-cyan);
}

/* ---------------------------------------------------------------------
   14. Task view — full-page route (sister to kanban-view, list-view, …)
   The base .main-content rules drive layout/sizing/visibility; the rules
   here just style the task view's chrome (header, body, sections).
   --------------------------------------------------------------------- */

.task-view-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 18px;
    border-bottom: 1px solid var(--border-subtle);
    flex-shrink: 0;
    background: var(--bg-secondary);
}
body.dark-theme .task-view-header { background: var(--subtle-bg); }
.task-view-close {
    font-size: 1.4rem;
    line-height: 1;
    background: transparent;
    border: 1px solid var(--border-strong);
    color: var(--text-secondary);
    cursor: pointer;
    width: 36px;
    height: 36px;
    border-radius: var(--radius-md);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    transition: var(--ease-snappy);
}
.task-view-close:hover {
    color: var(--danger);
    border-color: var(--danger);
    background: var(--danger-soft);
}
.task-view-header-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

/* More menu */
.more-menu-wrapper { position: relative; }
.more-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    background: var(--bg-elevated);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-lg);
    min-width: 200px;
    z-index: 50;
    box-shadow: var(--modal-shadow);
    overflow: hidden;
}
.more-menu.hidden { display: none; }
.more-menu-item {
    display: block;
    width: 100%;
    padding: 11px 16px;
    background: none;
    border: none;
    color: var(--text-primary);
    font-size: 0.85rem;
    cursor: pointer;
    text-align: left;
    transition: background var(--motion-fast);
}
.more-menu-item:hover { background: var(--hover-bg); }
.more-menu-item.danger { color: var(--danger); }
.more-menu-item.danger:hover { background: var(--danger-soft); }

/* Task view body */
.task-view-body {
    flex: 1;
    overflow-y: auto;
    padding: 18px;
    display: flex;
    flex-direction: column;
    gap: 18px;
}

.task-view-title {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-size: clamp(1.1rem, 2vw + 0.5rem, 1.4rem);
    font-weight: 700;
    outline: none;
    border-bottom: 2px solid transparent;
    padding-bottom: 6px;
    transition: border-color var(--motion-base);
    margin: 0;
    letter-spacing: -0.01em;
    text-transform: none;
}
.task-view-title:focus { border-bottom-color: var(--accent-cyan); }
.task-view-title:empty::before {
    content: attr(data-placeholder);
    color: var(--text-muted);
    font-weight: 400;
}

.task-view-controls {
    display: grid;
    grid-template-columns: 1fr;
    gap: 10px;
}
.task-view-control {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}
.task-view-control input,
.task-view-control select,
.task-view-control .custom-select-wrapper {
    width: 100%;
    box-sizing: border-box;
}
.task-view-control input.glass-input { padding: 0 12px; }
.task-view-control label {
    font-size: 0.7rem;
    text-transform: uppercase;
    color: var(--text-muted);
    font-weight: 700;
    letter-spacing: 0.06em;
}
.task-view-control .custom-select-wrapper {
    display: block;
    width: 100%;
    min-width: 0;
}

.task-view-description { display: flex; flex-direction: column; gap: 6px; }
.task-view-section-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    color: var(--text-muted);
    font-weight: 700;
    letter-spacing: 0.06em;
}
.task-view-description textarea {
    width: 100%;
    min-height: 90px;
    resize: vertical;
    font-size: 0.9rem;
    line-height: 1.5;
}

/* Task view collapsible sections */
.task-view-section {
    border-top: 1px solid var(--border-subtle);
    padding-top: 14px;
}
.task-view-section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    cursor: pointer;
    user-select: none;
    padding-bottom: 10px;
}
.task-view-section-header h3 {
    font-size: 0.78rem;
    text-transform: uppercase;
    color: var(--text-muted);
    font-weight: 700;
    letter-spacing: 0.06em;
    margin: 0;
}
.section-toggle {
    font-size: 0.85rem;
    color: var(--text-muted);
    transition: transform 0.2s;
    display: inline-block;
    line-height: 1;
}
.task-view-section.collapsed .section-toggle { transform: rotate(-90deg); }
.task-view-section.collapsed .task-view-section-content { display: none; }
.task-view-section-content { padding-top: 4px; }

.task-view-footer {
    flex-shrink: 0;
    padding: 12px 20px;
    border-top: 1px solid var(--border-subtle);
}

/* Subtasks / Checklist */
.subtask-list { list-style: none; padding: 0; margin: 0; }
.subtask-item {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 6px;
    background: var(--subtle-bg);
    padding: 10px 12px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border-subtle);
}
.subtask-item input[type="checkbox"] { width: 18px; height: 18px; cursor: pointer; accent-color: var(--accent-cyan); }
.subtask-item input[type="text"] {
    background: transparent;
    border: none;
    color: var(--text-primary);
    flex: 1;
    outline: none;
    padding: 0;
    height: auto;
    font-size: 0.88rem;
}
.subtask-item.done input[type="text"] {
    text-decoration: line-through;
    opacity: 0.6;
}
.btn-delete-subtask {
    background: transparent;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-weight: 700;
    font-size: 1rem;
    padding: 4px 6px;
    border-radius: var(--radius-sm);
    transition: var(--ease-snappy);
}
.btn-delete-subtask:hover { color: var(--danger); background: var(--danger-soft); }

.subtask-link-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.subtask-link-item {
    display: flex;
    align-items: center;
    gap: 6px;
    background: var(--subtle-bg);
    padding: 10px 12px;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background var(--motion-fast), border-color var(--motion-fast);
    font-size: 0.88rem;
    border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--accent-cyan);
}
.subtask-link-item:hover {
    background: var(--hover-bg);
    border-color: var(--accent-cyan);
}
.subtask-link-marker { flex: 0 0 auto; color: var(--text-muted); }
.subtask-link-title { flex: 1 1 auto; min-width: 0; }
.subtask-link-item .resolved-badge { flex: 0 0 auto; margin-left: auto; }

/* Resolved subtask: full green border + soft green wash + green check so the row
   reads as "done" at a glance, without being loud. */
.subtask-link-item.is-resolved {
    background: rgba(22, 163, 74, 0.10);
    border-color: var(--success);
    border-left-color: var(--success);
}
.subtask-link-item.is-resolved:hover {
    background: rgba(22, 163, 74, 0.16);
    border-color: var(--success);
}
.subtask-link-item.is-resolved .subtask-link-marker {
    color: var(--success);
    font-weight: 700;
}

/* Comments */
.comments-section {
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-height: 320px;
    overflow-y: auto;
    padding-right: 4px;
}
.chat-message {
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    padding: 10px 14px;
    border-radius: var(--radius-md);
    font-size: 0.88rem;
    color: var(--text-primary);
}
.chat-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 0.72rem;
    color: var(--text-muted);
    margin-bottom: 4px;
    gap: 10px;
}
.chat-meta { display: inline-flex; align-items: center; gap: 8px; }
.chat-ts { white-space: nowrap; }
.comment-actions { display: inline-flex; gap: 6px; }
.comment-actions .link-btn {
    background: transparent;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    padding: 0;
    font-size: 0.75rem;
}
.comment-actions .link-btn:hover {
    color: var(--accent-cyan);
    text-decoration: underline;
}
.comment-actions .link-btn.danger:hover { color: var(--danger); }
.comment-edit-input {
    width: 100%;
    box-sizing: border-box;
    resize: vertical;
}
.chat-input-area {
    display: flex;
    gap: 8px;
    flex-direction: column;
}
.chat-input-area input { flex: 1; }

.comment-composer {
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    padding: 12px;
    background: var(--bg-secondary);
    /* Positioning context for the @-mention dropdown (absolute child). */
    position: relative;
}

/* Rendered comment body: preserve the author's line breaks (serializeCommentEditor
   stores <br>/blocks/typed+pasted newlines as '\n'; renderCommentBody escapes but
   keeps them). overflow-wrap keeps long unbroken strings (URLs) from overflowing. */
.chat-body {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* @-mentions: highlighted token in a rendered comment body. */
.chat-body .mention {
    color: var(--accent-cyan);
    font-weight: 600;
}

/* @-mention typeahead dropdown, anchored under the composer textarea. */
.mention-dropdown {
    position: absolute;
    background: var(--bg-elevated);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md, 8px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
    max-height: 220px;
    overflow-y: auto;
    z-index: 10000;
}
.mention-dropdown .mention-item {
    padding: 6px 12px;
    cursor: pointer;
    font-size: 0.85rem;
    color: var(--text-primary);
}
.mention-dropdown .mention-item:hover,
.mention-dropdown .mention-item.active {
    background: var(--bg-secondary);
}
.mention-dropdown .mention-empty {
    padding: 8px 12px;
    color: var(--text-muted);
    font-size: 0.8rem;
    font-style: italic;
}
body.dark-theme .comment-composer { background: var(--subtle-bg); }
.comment-composer textarea.glass-input { background: var(--input-bg); }
.comment-staged-files {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.comment-staged-files .chip { font-size: 0.78rem; }

/* ---------------------------------------------------------------------
   15. Custom selects
   --------------------------------------------------------------------- */
.custom-select-wrapper {
    position: relative;
    user-select: none;
    display: block;
    min-width: 0;
    width: 100%;
}
.custom-select-wrapper.is-disabled {
    opacity: 0.5;
    pointer-events: none;
}
.custom-select-wrapper select { display: none; }
.custom-select-trigger {
    background: var(--input-bg);
    border: 1px solid var(--border-strong);
    color: var(--text-primary);
    padding: 0 12px;
    border-radius: var(--radius-md);
    cursor: pointer;
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 40px;
    white-space: nowrap;
    overflow: hidden;
    min-width: 0;
    font-size: 0.88rem;
    transition: var(--ease-snappy);
}
.custom-select-trigger:hover { border-color: var(--accent-cyan); }
.custom-select-trigger:after {
    content: '▾';
    font-size: 0.7rem;
    margin-left: 10px;
    color: var(--text-muted);
    flex-shrink: 0;
}
.custom-options {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    background: var(--bg-elevated);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    z-index: 500;
    max-height: 240px;
    overflow-y: auto;
    display: none;
    box-shadow: var(--modal-shadow);
}
body.dark-theme .custom-options { background: var(--bg-elevated); }
.custom-options.open { display: block; }
.custom-option {
    padding: 10px 14px;
    cursor: pointer;
    transition: background var(--motion-fast);
    border-bottom: 1px solid var(--border-subtle);
    font-size: 0.88rem;
    color: var(--text-primary);
}
.custom-option:last-child { border-bottom: none; }
.custom-option:hover { background: var(--hover-bg); }
.custom-option.selected {
    background: var(--active-bg);
    color: var(--accent-cyan);
    font-weight: 600;
}
.custom-option.hidden { display: none; }
.custom-select-search {
    position: sticky;
    top: 0;
    width: 100%;
    padding: 9px 14px;
    background: var(--bg-elevated);
    border: none;
    border-bottom: 1px solid var(--border-subtle);
    color: var(--text-primary);
    font-size: 0.85rem;
    font-family: inherit;
    box-sizing: border-box;
    z-index: 1;
    outline: none;
}
.custom-select-search:focus {
    border-bottom-color: var(--accent-cyan);
}
#add-member-row .custom-select-wrapper {
    display: block;
    width: 100%;
    min-width: 0;
}
#add-member-row .custom-select-trigger { width: 100%; }

/* ---------------------------------------------------------------------
   16. Bulk actions bar
   --------------------------------------------------------------------- */
.bulk-bar {
    position: fixed;
    bottom: 14px;
    left: 14px;
    right: 14px;
    padding: 12px 14px;
    z-index: 200;
    display: flex;
    gap: 12px;
    align-items: stretch;
    flex-direction: column;
    border-radius: var(--radius-lg);
    background: var(--bg-elevated);
    border: 1px solid var(--border-strong);
    box-shadow: var(--modal-shadow);
}
.bulk-bar.hidden { display: none !important; }
.bulk-controls {
    display: flex;
    gap: 8px;
    align-items: stretch;
    flex-wrap: wrap;
}
.bulk-controls > * { flex: 1 1 calc(50% - 4px); }
.bulk-bar .custom-options {
    top: auto;
    bottom: calc(100% + 4px);
}

#btn-bulk-delete {
    background: var(--danger-soft);
    color: var(--danger);
    border-color: var(--danger);
}
#btn-bulk-delete:hover {
    background: var(--danger);
    color: #fff;
    border-color: var(--danger);
}

/* ---------------------------------------------------------------------
   17. Notifications
   --------------------------------------------------------------------- */
.notification-container {
    position: fixed;
    top: auto;
    bottom: 80px;
    left: 14px;
    right: 14px;
    z-index: 1000;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.notification-toast {
    background: var(--bg-elevated);
    color: var(--text-primary);
    font-weight: 500;
    padding: 12px 16px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border-subtle);
    border-left: 4px solid var(--accent);
    box-shadow: var(--modal-shadow);
    animation: slideIn 0.3s ease-out forwards;
    min-width: auto;
    max-width: 100%;
    word-wrap: break-word;
    font-size: 0.88rem;
}

/* Sticky variant used for long-running background tasks (SWOT export, etc.).
   Has a spinner that turns into a ✓ / ! glyph in the terminal states; the
   success/error states colour the left border + are clickable. */
.notification-toast-progress { padding-right: 14px; }
.notification-toast-progress.is-progress { border-left-color: var(--accent-cyan); }
.notification-toast-progress.is-success  { border-left-color: var(--success); }
.notification-toast-progress.is-error    { border-left-color: var(--danger); }
.notification-toast-progress.is-clickable {
    cursor: pointer;
    transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.notification-toast-progress.is-clickable:hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 18px rgba(0,0,0,0.18);
}
.progress-toast-row {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}
.progress-toast-spinner {
    width: 16px;
    height: 16px;
    border: 2px solid var(--border-subtle);
    border-top-color: var(--accent-cyan);
    border-radius: 50%;
    animation: spin 0.9s linear infinite;
    flex: 0 0 auto;
}
.progress-toast-icon {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 0.85rem;
    flex: 0 0 auto;
    /* The kind class on the parent sets the colour. */
}
.notification-toast-progress.is-success .progress-toast-icon {
    background: var(--success);
    color: #fff;
}
.notification-toast-progress.is-error .progress-toast-icon {
    background: var(--danger);
    color: #fff;
}
.progress-toast-body {
    flex: 1;
    min-width: 0;
}
.progress-toast-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.notification-toast-progress.is-success .progress-toast-text,
.notification-toast-progress.is-error   .progress-toast-text {
    white-space: normal;  /* let the final message wrap so the user can read it */
}

/* ---------------------------------------------------------------------
   18. Document view
   --------------------------------------------------------------------- */
.document-content {
    padding: 24px 14px;
    display: flex;
    justify-content: center;
}
.document-paper {
    position: relative;
    max-width: 860px;
    width: 100%;
    background: var(--bg-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-xl);
    padding: 28px 22px;
    line-height: 1.7;
    font-size: 0.95rem;
    color: var(--text-primary);
    box-shadow: var(--card-shadow);
}
body.dark-theme .document-paper { background: var(--subtle-bg); }
.document-paper .doc-title {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: clamp(1.4rem, 3vw, 2.2rem);
    letter-spacing: -0.02em;
    color: var(--text-primary);
    margin: 0 0 20px 0;
    padding-bottom: 16px;
    padding-right: 110px;
    border-bottom: 2px solid var(--accent-cyan);
    text-transform: none;
}
.document-paper h2 {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-size: 1.25rem;
    font-weight: 700;
    margin: 28px 0 12px 0;
    color: var(--text-primary);
    letter-spacing: -0.01em;
    text-transform: none;
}
.document-paper .doc-intro p { margin: 0 0 12px 0; color: var(--text-primary); }
.document-paper .doc-intro strong {
    color: var(--accent-cyan);
    font-weight: 700;
}
.document-paper p { margin: 0 0 12px 0; }

.doc-task-list {
    list-style: none;
    counter-reset: task-counter;
    padding: 0;
    margin: 0;
}
.doc-task {
    counter-increment: task-counter;
    margin: 22px 0;
    padding-left: 44px;
    position: relative;
}
.doc-task::before {
    content: counter(task-counter) ".";
    position: absolute;
    left: 0;
    top: 0;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--accent-cyan);
    min-width: 36px;
}
/* Chapter-numbered tasks render their own label via `.doc-task-num`, so
   suppress the CSS auto-counter to avoid showing both numbers. */
.doc-task.has-chapter::before { content: none; }
.doc-task-num {
    position: absolute;
    left: 0;
    top: 0;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--accent-cyan);
    min-width: 36px;
}
/* Swimlane subsection heading inside the document view. Sits between the
   "Activities" h2 and the per-swimlane <ol> of tasks. Sized between h2 and
   h3 with a subtle accent so the grouping is visible without competing
   with the project title. */
.document-paper h3.doc-swimlane-heading {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-size: 1.05rem;
    font-weight: 700;
    margin: 18px 0 6px 0;
    color: var(--text-secondary);
    letter-spacing: 0.02em;
    text-transform: uppercase;
}
.doc-task-title {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-size: 1.05rem;
    font-weight: 700;
    margin: 0 0 6px 0;
    color: var(--text-primary);
    letter-spacing: -0.01em;
    text-transform: none;
}
.doc-task-meta {
    font-size: 0.82rem;
    color: var(--text-secondary);
    margin: 0 0 8px 0;
    font-style: italic;
}
.doc-task-desc {
    margin: 8px 0 12px 0;
    color: var(--text-primary);
}
.doc-resolved {
    color: var(--success);
    font-weight: 600;
    font-style: normal;
}

.doc-subtask-list {
    list-style: none;
    padding: 0;
    margin: 12px 0 0 0;
}
.doc-subtask {
    margin: 12px 0;
    padding-left: 44px;
    position: relative;
}
.doc-subtask-head {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    position: relative;
}
.doc-subtask-num {
    position: absolute;
    left: -44px;
    top: 0;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--accent-cyan);
    min-width: 36px;
}
.doc-subtask-title {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-size: 1rem;
    font-weight: 600;
    margin: 0;
    color: var(--text-primary);
    text-transform: none;
}

.doc-checklist-wrap {
    margin: 10px 0 12px 0;
    padding: 10px 14px;
    background: var(--subtle-bg);
    border-left: 3px solid var(--border-strong);
    border-radius: var(--radius-sm);
}
.doc-checklist-label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 700;
    color: var(--text-muted);
    margin-bottom: 6px;
}
.doc-checklist {
    list-style: none;
    padding: 0;
    margin: 0;
}
.doc-checklist li {
    padding: 4px 0;
    font-size: 0.9rem;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    gap: 6px;
}
.doc-checklist li.done {
    color: var(--text-muted);
    text-decoration: line-through;
}
.doc-check {
    color: var(--accent-cyan);
    margin-right: 4px;
    font-size: 1rem;
    display: inline-block;
    width: 18px;
    cursor: pointer;
    user-select: none;
}
.doc-check:hover { opacity: 0.7; }
.doc-check-text { flex: 1; min-width: 0; }
.doc-check-delete {
    background: transparent;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 1rem;
    padding: 0 4px;
    opacity: 0;
    transition: var(--ease-snappy);
}
.doc-checklist li:hover .doc-check-delete { opacity: 1; }
.doc-check-delete:hover { color: var(--danger); }

.doc-edit {
    outline: none;
    border-radius: var(--radius-sm);
    padding: 0 3px;
    margin: 0 -3px;
    transition: background var(--motion-fast);
    cursor: text;
}
.doc-edit:hover { background: var(--hover-bg); }
.doc-edit:focus {
    background: var(--active-bg);
    box-shadow: 0 0 0 1px var(--accent-cyan);
}
.doc-edit:empty::before {
    content: attr(data-placeholder);
    color: var(--text-muted);
    font-style: italic;
}
.doc-placeholder { color: var(--text-muted); font-style: italic; }
.doc-editable-block {
    display: block;
    min-height: 1.5em;
    padding: 6px 8px;
    margin: 0;
    border-radius: var(--radius-sm);
    white-space: pre-wrap;
}
.doc-editable-block:hover { background: var(--hover-bg); }
.doc-editable-block:focus {
    background: var(--active-bg);
    box-shadow: 0 0 0 1px var(--accent-cyan);
}

.doc-inline-select,
.doc-inline-date {
    background: transparent;
    border: none;
    border-bottom: 1px dashed var(--border-strong);
    color: var(--accent-cyan);
    font-weight: 600;
    font-family: inherit;
    font-size: inherit;
    padding: 0 2px;
    cursor: pointer;
    transition: border-color var(--motion-fast), background var(--motion-fast);
    height: auto;
}
.doc-inline-select:hover,
.doc-inline-date:hover {
    border-bottom-color: var(--accent-cyan);
    background: var(--hover-bg);
}
.doc-inline-select:focus,
.doc-inline-date:focus {
    outline: none;
    border-bottom-color: var(--accent-cyan);
    background: var(--active-bg);
}
.doc-inline-date { color-scheme: light dark; }

/* Document/settings assignment editor: Teams + Members chip pickers. */
.doc-assignment {
    display: flex;
    flex-wrap: wrap;
    gap: 18px 32px;
    margin: 4px 0 14px;
}
.doc-assignment-group {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 200px;
}
.doc-assignment-label {
    font-size: 0.8rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary);
}
/* Read-mode task/subtask titles are clickable to open the task detail modal. */
.doc-task-title-link {
    cursor: pointer;
    transition: color var(--motion-fast);
}
.doc-task-title-link:hover {
    color: var(--accent-cyan);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.doc-task-head,
.doc-subtask-head {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}
.doc-task-head .doc-task-title,
.doc-subtask-head .doc-subtask-title { flex: 1; }
.doc-task-actions {
    display: flex;
    gap: 4px;
    flex-shrink: 0;
    opacity: 0.4;
    transition: opacity var(--motion-fast);
}
.doc-task:hover .doc-task-actions,
.doc-subtask:hover .doc-task-actions { opacity: 1; }
.doc-action-btn {
    width: 28px;
    height: 28px;
    padding: 0;
    border: 1px solid var(--border-strong);
    background: transparent;
    color: var(--text-secondary);
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: 0.85rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: var(--ease-snappy);
}
.doc-action-btn:hover {
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
    background: var(--hover-bg);
}
.doc-action-btn.doc-action-danger:hover {
    border-color: var(--danger);
    color: var(--danger);
    background: var(--danger-soft);
}

.doc-add-wrap { margin: 22px 0 8px 0; }
.doc-add-sub { margin: 8px 0 0 0; padding-left: 44px; }
.doc-add-btn {
    background: transparent;
    border: 1px dashed var(--border-strong);
    color: var(--text-secondary);
    padding: 10px 18px;
    border-radius: var(--radius-md);
    cursor: pointer;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 600;
    font-size: 0.82rem;
    transition: var(--ease-snappy);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.doc-add-btn:hover {
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
    border-style: solid;
}
.doc-add-btn-sm {
    background: transparent;
    border: 1px dashed var(--border-strong);
    color: var(--text-muted);
    padding: 5px 10px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: 0.74rem;
    transition: var(--ease-snappy);
}
.doc-add-btn-sm:hover {
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
}
.doc-add-btn-xs {
    background: transparent;
    border: none;
    color: var(--text-muted);
    padding: 4px 0;
    cursor: pointer;
    font-size: 0.78rem;
    margin-top: 4px;
}
.doc-add-btn-xs:hover { color: var(--accent-cyan); }

.doc-task.is-resolved .doc-task-title,
.doc-subtask.is-resolved .doc-subtask-title { opacity: 0.7; }

.doc-block { margin: 6px 0 10px 0; }
.doc-empty {
    color: var(--text-muted);
    font-style: italic;
    margin: 12px 0;
}

.doc-edit-toggle {
    position: absolute;
    top: 18px;
    right: 18px;
    background: transparent;
    border: 1px solid var(--border-strong);
    color: var(--text-secondary);
    padding: 6px 12px;
    border-radius: var(--radius-md);
    cursor: pointer;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 600;
    font-size: 0.74rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    transition: var(--ease-snappy);
    z-index: 2;
}
.doc-edit-toggle:hover {
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
}
.doc-edit-toggle.active {
    background: var(--accent-cyan);
    border-color: var(--accent-cyan);
    color: #fff;
}
body.dark-theme .doc-edit-toggle.active { color: #0A1220; }
.doc-edit-toggle.active:hover { opacity: 0.9; }

/* ---------------------------------------------------------------------
   19. Calendar
   --------------------------------------------------------------------- */
.calendar-container {
    padding: 14px;
    height: 100%;
    overflow-y: auto;
    display: grid;
    grid-template-columns: 1fr;
    grid-auto-rows: minmax(110px, auto);
    gap: 8px;
}
.calendar-day {
    background: var(--bg-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    padding: 10px;
    min-height: 110px;
    position: relative;
    min-width: 0;
    display: flex;
    flex-direction: column;
    /* The JS caps events into .calendar-day-events (which clips overflow) and
       pins a "+N more" pill below it that opens the full-day popup. Clipping the
       cell keeps a busy day from spilling over its card or — on the fixed-height
       desktop/tablet grid — stretching its whole row. */
    overflow: hidden;
}
/* Scrollless, clipped events area. flex:1 + min-height:0 lets it shrink inside a
   fixed-height cell so the pinned "+N more" pill below always stays visible. */
.calendar-day-events {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}
/* "+N more" pill — pinned below the clipped events area; opens the full-day
   popup. flex-shrink:0 keeps it from being squeezed out in a fixed-height cell. */
.calendar-more {
    flex-shrink: 0;
    align-self: flex-start;
    font-size: 0.72rem;
    font-weight: 600;
    padding: 3px 8px;
    margin-top: 2px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    color: var(--text-secondary);
    background: var(--active-bg);
    transition: opacity var(--motion-fast), color var(--motion-fast);
}
.calendar-more:hover {
    opacity: 0.85;
    color: var(--accent-cyan);
}
body.dark-theme .calendar-day { background: var(--subtle-bg); }
.calendar-day.today {
    background: var(--active-bg);
    border-color: var(--accent-cyan);
}
.calendar-day-header {
    flex-shrink: 0;
    font-size: 0.8rem;
    font-weight: 700;
    margin-bottom: 8px;
    color: var(--text-secondary);
    text-align: right;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.calendar-day-name {
    font-size: 0.66rem;
    text-transform: uppercase;
    margin-bottom: 5px;
    color: var(--text-muted);
    text-align: center;
    letter-spacing: 0.08em;
    font-weight: 700;
}
.calendar-event {
    font-size: 0.74rem;
    padding: 4px 8px;
    border-radius: var(--radius-sm);
    margin-bottom: 4px;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: flex;
    align-items: center;
    gap: 5px;
    max-width: 100%;
    border-left: 3px solid var(--accent-cyan);
    background: var(--active-bg);
    color: var(--text-primary);
    transition: opacity var(--motion-fast);
}
.calendar-event.project-event {
    background: rgba(2, 132, 199, 0.10);
    border-left-color: var(--project-color, var(--accent-cyan));
}
.calendar-event.swimlane-event {
    background: var(--active-bg);
    border-left-color: var(--accent-cyan);
}
.calendar-event.ticket-event {
    background: rgba(220, 38, 38, 0.10);
    border-left-color: var(--danger);
    color: var(--danger);
}
.calendar-event.task-event {
    background: rgba(22, 163, 74, 0.10);
    border-left-color: var(--success);
    color: var(--success);
}
/* Ghost events: recurring tasks scheduled for a future day that don't exist yet.
   Dashed, faded and italic so they read as "not real (yet)"; the ↻ + "Scheduled"
   label in the text marks them. Not clickable — there's no task to open. */
.calendar-event.task-event-ghost {
    background: transparent;
    border-left-style: dashed;
    border-left-color: var(--success);
    color: var(--success);
    opacity: 0.6;
    font-style: italic;
    cursor: default;
}
.calendar-event.task-event-ghost:hover { opacity: 0.85; }
.calendar-event.meeting-event {
    background: rgba(124, 58, 237, 0.12);
    border-left-color: var(--accent-violet, #7c3aed);
    color: var(--accent-violet, #7c3aed);
}
.calendar-event:hover { opacity: 0.85; }
/* Organizer-owned meetings are clickable to edit; signal it. */
.calendar-event.meeting-event-editable { cursor: pointer; }
.calendar-event.meeting-event-editable:hover {
    opacity: 1;
    background: rgba(124, 58, 237, 0.22);
}

/* Edit/Schedule modal: heading + the in-form Delete (cancel meeting)
   action shown only when editing. */
.meeting-form-heading {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-size: 1rem;
    font-weight: 700;
    color: var(--text-primary);
    text-align: left;
    margin-bottom: 4px;
}
.meeting-form-danger {
    display: flex;
    justify-content: flex-end;
    border-top: 1px solid var(--border-subtle);
    padding-top: 12px;
    margin-top: 4px;
}
/* Small banner shown above the title field when the meeting modal is
   opened from a project context (openProjectMeetingModal). */
.meeting-form-project-banner {
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--accent-glow, rgba(2,132,199,0.10));
    border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--accent-cyan);
    border-radius: var(--radius-sm, 6px);
    padding: 8px 12px;
    font-size: 0.85rem;
    color: var(--text-primary);
}
.meeting-form-project-icon { font-size: 1rem; opacity: 0.9; }

/* Schedule-meeting modal body (rendered inside the shared showPrompt). */
/* Schedule-meeting form — mobile-first, lives inside the shared prompt
   modal. Everything stacks; only Start/End share a row. */
.meeting-form {
    display: flex;
    flex-direction: column;
    gap: 12px;
    text-align: left;
    min-width: 0;
}
.meeting-form-label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text-secondary);
    min-width: 0;
}
/* Root cause of the horizontal scroll: .glass-input is width:100% with
   9px/12px padding but no border-box, so each control rendered 24px
   wider than its cell, and native date/time inputs add intrinsic
   min-widths on top. Constrain them here (scoped, no global impact). */
.meeting-form .glass-input {
    width: 100%;
    max-width: 100%;
    min-width: 0;
    box-sizing: border-box;
}
/* Two columns only — Start | End. Fits even on a ~300px viewport, so
   no overflow regardless of modal width. Date is full-width above. */
.meeting-form-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    min-width: 0;
}
/* (The attendee <select multiple> that used to live here was replaced by the
   .ps chip picker — see section 25b.) */

/* Room availability panel — booked slots for the chosen room+date, shown
   inline between the time pickers and attendees. Compact, scrolls if a
   busy day overflows; never widens the modal. */
.meeting-availability {
    min-width: 0;
}
.meeting-availability:empty { display: none; }
.meeting-avail-head {
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-secondary);
    margin-bottom: 4px;
}
.meeting-avail-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 132px;
    overflow-y: auto;
}
.meeting-avail-item {
    display: flex;
    gap: 8px;
    align-items: baseline;
    font-size: 0.82rem;
    padding: 4px 8px;
    border-radius: var(--radius-sm);
    background: rgba(220, 38, 38, 0.10);
    border-left: 3px solid var(--danger);
    min-width: 0;
}
.meeting-avail-time {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--danger);
    white-space: nowrap;
    flex-shrink: 0;
}
.meeting-avail-title {
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.meeting-avail-pending { color: var(--text-muted); font-style: italic; }
.meeting-avail-free {
    font-size: 0.82rem;
    color: var(--success);
    padding: 4px 0;
}
.meeting-avail-loading,
.meeting-avail-error {
    font-size: 0.82rem;
    color: var(--text-secondary);
    padding: 4px 0;
}
.meeting-avail-error { color: var(--danger); }
.calendar-legend {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    font-size: 0.78rem;
    color: var(--text-muted);
    margin-left: 0;
}
/* Month switcher: prev / "May 2026" / next on a single row. On mobile this
   stays visible above the collapsible Options block — it's primary nav, not
   a tuck-it-away setting. */
.calendar-month-nav {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.calendar-month-nav-btn {
    flex: 0 0 auto;
}

.calendar-filter-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.78rem;
    color: var(--text-secondary);
    cursor: pointer;
    user-select: none;
}
.calendar-filter-toggle input[type="checkbox"] {
    cursor: pointer;
}

/* Event-type filter (All / Tasks / Tickets / Meetings). Compact segmented
   control sized to sit inline with the calendar's other controls. On mobile
   it falls into the collapsible "Options" menu without extra plumbing —
   parent `.controls` is what mobile.js toggles. */
.calendar-type-filter {
    display: inline-flex;
    align-items: stretch;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    overflow: hidden;
}
.cal-type-btn {
    background: transparent;
    color: var(--text-secondary);
    border: none;
    border-right: 1px solid var(--border-subtle);
    padding: 4px 10px;
    font-size: 0.78rem;
    font-weight: 600;
    cursor: pointer;
    transition: background var(--motion-fast), color var(--motion-fast);
}
.cal-type-btn:last-child { border-right: none; }
.cal-type-btn:hover {
    background: var(--active-bg);
    color: var(--text-primary);
}
.cal-type-btn.active {
    background: var(--active-bg);
    color: var(--accent-cyan);
}
body.is-mobile .calendar-type-filter {
    width: 100%;
    justify-content: stretch;
}
body.is-mobile .cal-type-btn {
    flex: 1 1 0;
    padding: 8px 6px;
    font-size: 0.82rem;
}

/* Navigation loading overlay — sits on top of the current view while the
   next view fetches its data. Lets the user stay on what they were looking
   at, with a clear "we're working on it" cue, instead of getting a flash
   of empty content. Pointer-events on so accidental clicks during the
   transition don't fire on whatever's underneath. */
.nav-loading-overlay {
    position: fixed;
    inset: 0;
    background: rgba(255, 255, 255, 0.55);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    z-index: 9500;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: all;
    animation: nav-loading-fade-in 120ms ease-out;
}
body.dark-theme .nav-loading-overlay {
    background: rgba(10, 12, 16, 0.55);
}
.nav-loading-spinner {
    width: 48px;
    height: 48px;
    border: 4px solid var(--border-subtle);
    border-top-color: var(--accent-cyan);
    border-radius: 50%;
    animation: nav-loading-spin 800ms linear infinite;
}
@keyframes nav-loading-spin { to { transform: rotate(360deg); } }
@keyframes nav-loading-fade-in { from { opacity: 0; } to { opacity: 1; } }

/* Mobile-only day-events sheet. Driven by the calendar's "+N more" pill
   when the day overflows the inline cap. Backdrop dismiss + close button. */
.cal-day-sheet-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 9000;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    animation: cal-day-sheet-fade 160ms ease-out;
}
.cal-day-sheet {
    width: 100%;
    max-height: 85vh;
    /* Opaque elevated surface — projex has no --bg-primary, so the old var fell
       back to transparent and the calendar showed through the popup. */
    background: var(--bg-elevated);
    border-top-left-radius: 16px;
    border-top-right-radius: 16px;
    box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.18);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    animation: cal-day-sheet-rise 200ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
.cal-day-sheet-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 18px;
    border-bottom: 1px solid var(--border-subtle);
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--text-primary);
}
.cal-day-sheet-close {
    background: none;
    border: none;
    color: var(--text-secondary);
    font-size: 1.1rem;
    cursor: pointer;
    padding: 4px 10px;
    line-height: 1;
}
.cal-day-sheet-list {
    overflow-y: auto;
    padding: 12px 16px calc(20px + env(safe-area-inset-bottom, 0px));
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.cal-day-sheet-list .calendar-event {
    margin: 0;
    /* In the sheet there's no horizontal pressure — let long titles wrap so
       the user can read the full label without a tooltip. */
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
}
@keyframes cal-day-sheet-rise {
    from { transform: translateY(100%); }
    to { transform: translateY(0); }
}
@keyframes cal-day-sheet-fade {
    from { background: rgba(0, 0, 0, 0); }
    to { background: rgba(0, 0, 0, 0.45); }
}
/* On desktop the day-events popup is a centred modal rather than a bottom sheet. */
@media (min-width: 1024px) {
    .cal-day-sheet-overlay { align-items: center; }
    .cal-day-sheet {
        width: auto;
        min-width: 340px;
        max-width: 440px;
        max-height: 70vh;
        border-radius: 16px;
        box-shadow: 0 12px 40px rgba(0, 0, 0, 0.28);
        animation: cal-day-pop 150ms ease-out;
    }
    .cal-day-sheet-list { padding: 12px 16px 16px; }
}
@keyframes cal-day-pop {
    from { opacity: 0; transform: scale(0.96); }
    to { opacity: 1; transform: scale(1); }
}

/* ---------------------------------------------------------------------
   20. Timeline
   --------------------------------------------------------------------- */
.timeline-container {
    padding: 14px;
    height: 100%;
    overflow: auto;
    display: flex;
    flex-direction: column;
    gap: 16px;
}
.timeline-chart-wrapper {
    /* One variable drives the sidebar label column width — used by the
       label cells, the dependency SVG offset, and the today line's inline
       calc() in views.js. Bump in one place to widen the Project/Module
       column without de-syncing the layers.

       Responsive to screen width via clamp(): never narrower than 240px (so
       names stay readable on small laptops), scales with the viewport, and
       never wider than 780px on large displays. A viewport-relative length
       (vw) — not % — is deliberate: it resolves to the same pixel value in
       both the header row (full wrapper) and the scrollable body rows, so
       the header and label column stay pixel-aligned even when a vertical
       scrollbar appears (a % would diverge by the scrollbar width). */
    --timeline-label-width: clamp(240px, 30vw, 780px);
    background: var(--bg-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    position: relative;
}
body.dark-theme .timeline-chart-wrapper { background: var(--subtle-bg); }
.timeline-header-row {
    display: flex;
    border-bottom: 1px solid var(--border-subtle);
    background: var(--subtle-bg);
}
body.dark-theme .timeline-header-row { background: var(--bg-elevated); }
.timeline-sidebar-header {
    width: var(--timeline-label-width);
    padding: 10px;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    border-right: 1px solid var(--border-subtle);
    flex-shrink: 0;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.timeline-timeline-header {
    flex: 1;
    padding: 10px;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    text-align: center;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* Day-by-day date axis (Gantt header): a month band over per-day columns. Each
   day cell is exactly pxPerDay wide (inline) so it aligns with the bars + day
   gridlines below. Overrides the single-cell header styling above. */
.timeline-timeline-header.timeline-date-axis {
    padding: 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    text-align: left;
    text-transform: none;
    letter-spacing: 0;
    overflow: hidden;
}
.timeline-month-row,
.timeline-day-row { display: flex; flex-wrap: nowrap; }
.timeline-month-row { border-bottom: 1px solid var(--border-subtle); }
.timeline-month-cell {
    flex: 0 0 auto;
    box-sizing: border-box;
    padding: 4px 8px;
    font-size: 0.7rem;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    border-right: 1px solid var(--border-subtle);
    color: var(--text-secondary);
}
.timeline-day-cell {
    flex: 0 0 auto;
    box-sizing: border-box;
    padding: 3px 0;
    font-size: 0.62rem;
    font-weight: 500;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    border-right: 1px solid var(--border-subtle);
    color: var(--text-muted);
}
.timeline-day-cell.is-weekend { background: var(--subtle-bg); color: var(--text-secondary); }
body.dark-theme .timeline-day-cell.is-weekend { background: rgba(255, 255, 255, 0.04); }
.timeline-day-cell.is-today { color: var(--danger); font-weight: 700; background: var(--danger-soft); }

/* Per-day vertical gridlines in each track, aligned to the day columns (both
   start at the day-snapped minDate, so a 1px line every pxPerDay lands on a day
   boundary). --timeline-day-px is set per render on the wrapper. */
.timeline-chart-wrapper.is-scroll .timeline-track {
    background-image: repeating-linear-gradient(
        to right,
        var(--border-subtle) 0, var(--border-subtle) 1px,
        transparent 1px, transparent var(--timeline-day-px, 34px)
    );
}

.timeline-body { overflow-y: auto; flex: 1; position: relative; }
.timeline-row {
    display: flex;
    border-bottom: 1px solid var(--border-subtle);
    /* Rows used to be a fixed 38px and labels truncated with ellipsis. Now
       labels wrap so the full title is always visible and the deadline pill
       stays anchored to the right of the column — height grows to fit.
       Dependency-arrow y-coords read the row's offsetTop after layout, so
       variable heights don't drift the arrows. */
    min-height: 38px;
    align-items: stretch;
    position: relative;
}
.timeline-row:hover { background: var(--hover-bg); }
.timeline-label {
    width: var(--timeline-label-width);
    padding: 8px 10px;
    border-right: 1px solid var(--border-subtle);
    flex-shrink: 0;
    font-size: 0.82rem;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    gap: 8px;
    box-sizing: border-box;
    /* No nowrap / ellipsis — title text in .timeline-label-text wraps to
       additional lines, and the meta strip (.timeline-label-end) is pinned
       to the right via flex so the deadline pill is always visible at the
       end of the row regardless of how long the title gets. */
}
.timeline-label-text {
    flex: 1;
    min-width: 0;
    word-break: break-word;
    overflow-wrap: anywhere;
    line-height: 1.3;
}

/* Task/subtask title in the timeline sidebar is a link into the task modal. */
.timeline-task-link {
    cursor: pointer;
    transition: color var(--motion-fast);
}
.timeline-task-link:hover {
    color: var(--accent-cyan);
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* ─── Gantt mode switch + Financials mode ───────────────────────────────── */
.timeline-mode-switch { display: inline-flex; gap: 4px; }
.timeline-only-controls { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* Date/zoom/simulation controls are timeline-only — hidden in Financials mode. */
.timeline-mode-financials .timeline-only-controls { display: none; }

/* Right-side cost columns replace the bar track. Header cells and row cells
   share the same width + box model so the columns line up. */
.timeline-fin-head {
    flex: 1;
    display: flex;
    justify-content: flex-end;
    align-items: center;
    padding-right: 6px;
}
.timeline-fin-col {
    width: 130px;
    box-sizing: border-box;
    padding: 0 12px;
    text-align: right;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 0.72rem;
    text-transform: uppercase;
}
.timeline-fin-cells {
    flex: 1;
    display: flex;
    justify-content: flex-end;
    align-items: center;
    padding-right: 6px;
}
.timeline-fin-cell {
    width: 130px;
    box-sizing: border-box;
    padding: 8px 12px;
    text-align: right;
    font-size: 0.82rem;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}
.timeline-fin-cell.is-over { color: var(--danger); }
/* Rollup rows read heavier than their leaf tasks. */
.timeline-row.project-row .timeline-fin-cell { font-weight: 700; color: var(--text-primary); }
.timeline-fin-empty { padding: 16px; color: var(--text-muted); font-size: 0.85rem; }

/* ── Financials monthly columns ──────────────────────────────────────────
   When per-month actual-cost columns are present the table can be wider than
   the viewport, so the whole wrapper scrolls (x + y); the Project/Module label
   stays pinned left and the header row pinned top. Only applied to the
   financials wrapper that actually carries month columns (.has-months) so the
   plain 3-column financials view keeps its original right-aligned layout. */
.timeline-fin-wrapper.has-months { overflow: auto; flex: 1; min-height: 0; }
.timeline-fin-wrapper.has-months .timeline-header-row,
.timeline-fin-wrapper.has-months .timeline-body,
.timeline-fin-wrapper.has-months .timeline-row { width: max-content; min-width: 100%; }
.timeline-fin-wrapper.has-months .timeline-body { overflow: visible; }
.timeline-fin-wrapper.has-months .timeline-header-row { position: sticky; top: 0; z-index: 3; }
.timeline-fin-wrapper.has-months .timeline-fin-head,
.timeline-fin-wrapper.has-months .timeline-fin-cells { flex: 0 0 auto; justify-content: flex-start; }
/* Pin the label column to the left while the months scroll under it. */
.timeline-fin-wrapper.has-months .timeline-sidebar-header,
.timeline-fin-wrapper.has-months .timeline-label {
    position: sticky;
    left: 0;
    z-index: 2;
    background: var(--bg-secondary);
}
.timeline-fin-wrapper.has-months .timeline-sidebar-header { z-index: 4; }
body.dark-theme .timeline-fin-wrapper.has-months .timeline-sidebar-header,
body.dark-theme .timeline-fin-wrapper.has-months .timeline-label { background: var(--subtle-bg); }
/* Month header + value cells — fixed width so header and rows align. */
.timeline-fin-month-col,
.timeline-fin-month-cell {
    width: 100px;
    box-sizing: border-box;
    padding: 0 12px;
    text-align: right;
    flex-shrink: 0;
    border-left: 1px solid var(--border-subtle);
    font-variant-numeric: tabular-nums;
}
.timeline-fin-month-col {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    align-self: stretch;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-muted);
}
.timeline-fin-month-cell {
    padding-top: 8px;
    padding-bottom: 8px;
    font-size: 0.82rem;
    color: var(--text-secondary);
}
.timeline-row.project-row .timeline-fin-month-cell { font-weight: 700; color: var(--text-primary); }
.timeline-label-end {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
    flex-wrap: nowrap;
}
/* Assignee initials pill — circular 22px chip, full name shown via the
   native title tooltip on hover. Color comes from a stable hash on the
   user id (set inline via `style="background:hsl(...)"`) so the same
   person reads as the same color across every Gantt row. */
.timeline-assignee {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    color: #fff;
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    line-height: 1;
    user-select: none;
    cursor: default;
    box-shadow: 0 0 0 1px rgba(255,255,255,0.5) inset;
}
/* overflow: hidden clips bars whose start_date is before the visible
   window (negative `left` percent) or whose end is past maxDate — without
   it those bars escape into the Project/Module column on the left, and
   past the wrapper border on the right. The dependency SVG lives at body
   level, not inside tracks, so its arrows are unaffected. */
/* align-self: stretch (not height: 100%) so the track fills the row's height.
   The row uses min-height, not a fixed height, so a percentage height here
   resolves to `auto` → collapses to the absolutely-positioned bar's 0 content
   height → overflow:hidden then clips every bar. Stretch sizes the track to the
   row's actual (label-driven) height regardless. */
.timeline-track { flex: 1; position: relative; align-self: stretch; overflow: hidden; }

/* Horizontal-scroll Gantt: the chart renders the whole project span at a fixed
   px-per-day and scrolls sideways (replacing the old ±week paging). Mirrors the
   financials .has-months two-axis scroll — wide content, sticky label column,
   sticky header — but the timeline track + its header take an explicit pixel
   width (--timeline-track-width, set per render in views.js) because the bars
   inside are absolutely positioned and give the track no intrinsic width. */
.timeline-chart-wrapper.is-scroll { overflow: auto; flex: 1; min-height: 0; cursor: grab; }
/* While click-dragging to pan (see enableTimelineDragScroll in views.js): show
   the closed-hand cursor and suppress text selection so dragging over labels /
   bar captions doesn't highlight them. */
.timeline-chart-wrapper.is-scroll.is-grabbing { cursor: grabbing; user-select: none; }
.timeline-chart-wrapper.is-scroll .timeline-header-row,
.timeline-chart-wrapper.is-scroll .timeline-body,
.timeline-chart-wrapper.is-scroll .timeline-row { width: max-content; min-width: 100%; }
.timeline-chart-wrapper.is-scroll .timeline-body { overflow: visible; }
/* z-index note: the today line is z-10 and the dependency SVG z-5, so the
   sticky column/header must sit ABOVE 10 or the red line bleeds over the
   Project/Module column as it scrolls under it. Corner (sidebar-header) tops
   both the sticky header row and the sticky label column. */
.timeline-chart-wrapper.is-scroll .timeline-header-row { position: sticky; top: 0; z-index: 12; }
.timeline-chart-wrapper.is-scroll .timeline-timeline-header,
.timeline-chart-wrapper.is-scroll .timeline-track {
    flex: 0 0 var(--timeline-track-width);
    width: var(--timeline-track-width);
}
/* Keep the Project/Module column pinned left, covering bars/arrows/today-line
   that scroll under it. (Compositing the moving today-line — not these sticky
   cells — is what stops the red ghost trails; see .timeline-today-line below.
   Promoting the per-row cells instead created seams the line bled through.) */
.timeline-chart-wrapper.is-scroll .timeline-sidebar-header,
.timeline-chart-wrapper.is-scroll .timeline-label {
    position: sticky;
    left: 0;
    z-index: 11;
    background: var(--bg-secondary);
}
.timeline-chart-wrapper.is-scroll .timeline-sidebar-header { z-index: 13; }
/* The label cell only covers the row's content height, so the 1px row-divider
   gap below it leaves the red today-line showing through in the column (the
   divider itself is translucent). Paint over that gap with the label's own
   opaque bg (blocks the line) plus the divider tint on top (keeps the row
   separator look). Theme-aware fill so it's fully opaque in both themes. */
.timeline-chart-wrapper.is-scroll .timeline-label {
    box-shadow: 0 1px 0 0 var(--border-subtle), 0 1px 0 0 var(--bg-secondary);
}
body.dark-theme .timeline-chart-wrapper.is-scroll .timeline-sidebar-header,
body.dark-theme .timeline-chart-wrapper.is-scroll .timeline-label { background: var(--subtle-bg); }
body.dark-theme .timeline-chart-wrapper.is-scroll .timeline-label {
    box-shadow: 0 1px 0 0 var(--border-subtle), 0 1px 0 0 var(--subtle-bg);
}
/* Dependency arrows: pin the SVG to the track's explicit width (not
   100% - label) so its %-based paths stay aligned with the bars even when the
   body is stretched to min-width:100% on a wide screen. */
.timeline-chart-wrapper.is-scroll .timeline-dependency-svg { width: var(--timeline-track-width); }

.timeline-bar {
    position: absolute;
    top: 7px;
    height: 24px;
    border-radius: var(--radius-sm);
    font-size: 0.7rem;
    display: flex;
    align-items: center;
    padding: 0 8px;
    white-space: nowrap;
    /* Floor so a same-day item (start == deadline → width 0%) still shows a
       visible nub instead of collapsing to nothing under box-sizing:border-box. */
    min-width: 6px;
    overflow: hidden;
    box-shadow: 0 1px 2px rgba(9, 28, 58, 0.08);
    transition: width 0.3s, left 0.3s;
    color: #fff;
    font-weight: 600;
}
.timeline-bar.project {
    background: var(--project-color);
    color: var(--text-primary);
    font-weight: 700;
    z-index: 2;
}
.timeline-bar.swimlane {
    background: var(--active-bg);
    border: 1px solid var(--accent-cyan);
    color: var(--text-primary);
    z-index: 1;
}
.timeline-bar.task {
    /* Accent-cyan instead of success-green so the bar doesn't read as
       "done" by default. Green now exclusively signals completion via the
       .is-resolved modifier below. */
    background: var(--accent-cyan);
    color: #fff;
    z-index: 0;
    height: 18px;
    top: 10px;
    font-size: 0.66rem;
}
.timeline-bar.endless {
    background: linear-gradient(90deg, var(--project-color) 0%, transparent 100%);
    border-right: none;
}
.timeline-bar.endless-swimlane {
    background: linear-gradient(90deg, var(--active-bg) 0%, transparent 100%);
    border-right: none;
}
.timeline-bar.endless-task {
    background: linear-gradient(90deg, var(--accent-cyan) 0%, transparent 100%);
    border-right: none;
}
/* Subtask bar — hollow / dashed-outline variant of the task bar. Cyan so it
   reads as a sibling of the parent bar; transparent fill + smaller height +
   dashed border make the parent/child distinction immediate. */
.timeline-bar.subtask {
    background: transparent;
    border: 1.5px dashed var(--accent-cyan);
    color: var(--accent-cyan);
    height: 14px;
    top: 12px;
    font-size: 0.62rem;
    font-weight: 600;
    box-shadow: none;
    z-index: 0;
}
.timeline-bar.endless-subtask { border-right: none; }

/* Done state — applied to parent tasks AND subtasks whose column is the
   "done" role. Green is reserved for this state so the bar color carries
   real completion signal. The dashed subtask style is preserved on resolved
   subtasks; only the stroke + text color flip to green. */
.timeline-bar.task.is-resolved {
    background: var(--success);
}
.timeline-bar.task.is-resolved.endless-task {
    background: linear-gradient(90deg, var(--success) 0%, transparent 100%);
}
.timeline-bar.subtask.is-resolved {
    border-color: var(--success);
    color: var(--success);
}

/* ── Reschedule simulation overlay ──────────────────────────────────────────
   "Ghost" bar drawn in the same track as the planned bar, at the simulated
   position. Transparent fill + dashed outline so it reads as a proposal, not a
   committed date; the horizontal offset (it sits at the shifted start) is what
   makes the impact visible next to the solid planned bar. Non-interactive. */
.timeline-bar.timeline-bar-sim {
    background: transparent !important;
    box-shadow: none;
    border: 1.5px dashed var(--accent-cyan);
    opacity: 0.95;
    pointer-events: none;
    z-index: 4;
    color: transparent;
}
.timeline-bar.timeline-bar-sim.sim-earlier { border-color: var(--success); background: rgba(22, 163, 74, 0.12) !important; }
.timeline-bar.timeline-bar-sim.sim-later   { border-color: var(--warning); background: rgba(245, 158, 11, 0.14) !important; }

/* Summary banner above the chart. */
.timeline-sim-banner {
    margin: 6px 0 10px;
    padding: 10px 12px;
    border: 1px solid var(--border-color, rgba(2, 132, 199, 0.25));
    border-left: 4px solid var(--accent-cyan);
    border-radius: var(--radius-sm);
    background: var(--hover-bg, rgba(2, 132, 199, 0.06));
}
.timeline-sim-banner-head {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
.timeline-sim-banner-sub {
    color: var(--text-secondary, #64748b);
    font-size: 0.8rem;
    flex: 1;
    min-width: 160px;
}
.timeline-sim-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
}
.timeline-sim-chip {
    font-size: 0.72rem;
    padding: 2px 8px;
    border-radius: 999px;
    border: 1px solid transparent;
    background: var(--active-bg, rgba(2, 132, 199, 0.1));
    color: var(--text-primary);
    white-space: nowrap;
}
.timeline-sim-chip.sim-earlier { border-color: var(--success); color: var(--success); }
.timeline-sim-chip.sim-later   { border-color: var(--warning); color: var(--warning); }

/* Toolbar toggle active state. */
#timeline-sim-btn.is-active {
    background: var(--accent-cyan);
    color: #fff;
    border-color: var(--accent-cyan);
}

/* Resolved pill rendered inside the timeline sidebar label. Smaller than
   the board's pill so it doesn't push the time badge / chapter offscreen. */
.timeline-resolved-badge {
    font-size: 0.58rem;
    padding: 1px 5px;
    margin-left: 5px;
}

.timeline-dependency-svg {
    position: absolute;
    top: 0;
    left: var(--timeline-label-width);
    width: calc(100% - var(--timeline-label-width));
    height: 100%;
    pointer-events: none;
    z-index: 5;
    overflow: visible;
}
.timeline-dependency-line {
    fill: none;
    stroke: var(--accent-cyan);
    stroke-width: 1.5;
    stroke-dasharray: 4 2;
    opacity: 0.6;
}
.timeline-today-line {
    position: absolute;
    /* Lives inside .timeline-body now (not the wrapper), so top: 0 starts at
       the first row, not below the header — and the line shares the body's
       scrollbar-aware coordinate system with the task bars and dependency
       SVG so it stays glued to today's column as the body scrolls.
       Height is set inline from JS to body.scrollHeight so the line spans
       the full scrollable content, not just the visible viewport (the
       previous `bottom: 0` only sized to the viewport, hiding the line
       below the fold for projects with many rows). */
    top: 0;
    width: 2px;
    background: var(--danger);
    z-index: 10;
    pointer-events: none;
}

/* ---------------------------------------------------------------------
   21. List view
   --------------------------------------------------------------------- */
.list-view-container {
    padding: 14px;
    height: 100%;
    overflow-y: auto;
}
.list-project-section {
    margin-bottom: 16px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    overflow: hidden;
}
body.dark-theme .list-project-section { background: var(--subtle-bg); }
.list-project-header {
    padding: 14px 18px;
    background: var(--subtle-bg);
    border-bottom: 1px solid var(--border-subtle);
    display: flex;
    justify-content: space-between;
    align-items: center;
    cursor: pointer;
    transition: background var(--motion-fast);
}
body.dark-theme .list-project-header { background: var(--bg-elevated); }
.list-project-header:hover { background: var(--hover-bg); }
.list-project-header h3 {
    margin: 0;
    font-size: 1rem;
    color: var(--project-color);
    text-transform: none;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    letter-spacing: -0.01em;
}
.list-project-content { padding: 14px; }

.list-swimlane {
    margin-bottom: 12px;
    background: var(--bg-main);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    overflow: hidden;
}
body.dark-theme .list-swimlane { background: var(--bg-secondary); }
.list-swimlane-header {
    padding: 10px 14px;
    background: var(--subtle-bg);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 0.85rem;
    color: var(--text-primary);
    display: flex;
    justify-content: space-between;
    align-items: center;
    cursor: pointer;
    transition: background var(--motion-fast);
    text-transform: uppercase;
    letter-spacing: 0.02em;
    border-left: 3px solid var(--accent-cyan);
}
body.dark-theme .list-swimlane-header { background: var(--bg-elevated); }
.list-swimlane-header:hover { background: var(--hover-bg); }
.list-swimlane-header .toggle-icon {
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    display: inline-block;
}

.list-status-group {
    padding: 10px;
    border-bottom: 1px solid var(--border-subtle);
    min-height: 60px;
}
.list-status-group:last-child { border-bottom: none; }
.list-status-group.list-status-animate {
    animation: listStatusSlide 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
}

.list-section-wrapper {
    border-left: 2px solid var(--border-subtle);
    margin-left: 8px;
    margin-top: 5px;
}
.list-section-wrapper.list-section-animate {
    animation: listSectionSlide 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
}
.list-section-header {
    padding: 6px 10px;
    background: var(--subtle-bg);
    font-size: 0.74rem;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    cursor: pointer;
    display: flex;
    justify-content: space-between;
    transition: background var(--motion-fast);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.list-section-header:hover { background: var(--hover-bg); }
.list-section-header .toggle-icon {
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    display: inline-block;
}

.list-status-header {
    font-size: 0.78rem;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 8px;
    padding-left: 10px;
    border-left: 3px solid var(--text-muted);
    font-weight: 700;
    letter-spacing: 0.06em;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.list-status-header[class*="backlog"] { border-color: var(--border-strong); }
.list-status-header[class*="doing"]   { border-color: var(--warning); color: var(--warning); }
.list-status-header[class*="done"]    { border-color: var(--success); color: var(--success); }

/* Done-column visibility toggle: lives in the column / section header next to
   the card count. Plain text button so it inherits the header's color and
   weight; opacity nudges it back behind the title visually. */
.column-header-actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.done-toggle-btn {
    background: transparent;
    border: 1px solid var(--border-subtle);
    color: inherit;
    line-height: 1;
    padding: 4px 6px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    opacity: 0.75;
    transition: opacity var(--motion-base), background var(--motion-base);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.done-toggle-btn svg {
    width: 16px;
    height: 16px;
    display: block;
}
.done-toggle-btn:hover { opacity: 1; background: var(--hover-bg); }
.list-status-header .done-toggle-btn {
    margin-left: 8px;
    vertical-align: middle;
}
.is-done-section.is-collapsed { margin-bottom: 4px; }

.task-row {
    display: flex;
    align-items: center;
    gap: 12px;
    background: var(--bg-main);
    padding: 10px 12px;
    border-radius: var(--radius-md);
    margin-bottom: 6px;
    cursor: grab;
    transition: var(--ease-snappy);
    border: 1px solid var(--border-subtle);
    border-left: 4px solid var(--project-color, var(--accent-cyan));
    box-shadow: var(--card-shadow);
    flex-wrap: wrap;
}
body.dark-theme .task-row { background: var(--bg-elevated); }
.task-row:hover {
    background: var(--hover-bg);
    border-color: var(--accent-cyan);
}
.task-row.blocked {
    background: var(--danger-soft);
    border: 1px solid var(--danger);
    border-left: 4px solid var(--danger);
    animation: pulse-blocked 2.4s ease-in-out infinite;
}
.task-row.selected {
    background: var(--active-bg);
    border-color: var(--accent-cyan);
    box-shadow: 0 0 0 2px var(--accent-glow);
}
.task-row.dragging {
    opacity: 0.5;
    border: 1px dashed var(--border-strong);
    cursor: grabbing;
}

/* ---------------------------------------------------------------------
   22. Analytics
   --------------------------------------------------------------------- */
.analytics-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 10px;
    align-items: center;
}
/* .controls goes 2-col grid at sm (640px+); analytics lays out its own rows. */
.controls.analytics-controls { display: flex; }
/* One full-width line per row: works identically whether the parent is our own
   flex column or the tablet-up `.top-bar > .controls` wrapping row. */
.analytics-controls-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 10px;
    align-items: center;
    flex: 1 1 100%;
    min-width: 0;
}
.analytics-presets,
.analytics-source-group {
    display: inline-flex;
    gap: 4px;
    flex-wrap: wrap;
    align-items: center;
    background: var(--bg-elevated);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    padding: 3px;
}
/* The sources wrapper is transparent — each source is its own boxed group, so
   the Projects box visibly CONTAINS its status chips (divider between) while
   Simple Tasks stands alone beside it. */
.analytics-sources {
    display: inline-flex;
    gap: 8px;
    flex-wrap: wrap;
    align-items: stretch;
}
.analytics-source-group .analytics-statuses {
    display: inline-flex;
    gap: 4px;
    flex-wrap: wrap;
    align-items: center;
    margin-left: 4px;
    padding-left: 8px;
    border-left: 1px solid var(--border-subtle);
}
/* Same height + type scale as the chip groups — the primary color already says
   "action"; it doesn't need to be a bigger card than the filters it refreshes. */
.analytics-refresh {
    margin-left: auto;
    padding: 8px 14px;
    font-size: 0.78rem;
    line-height: 1;
    min-height: 0;
}
/* Status chips are meaningless while the Projects source is off — keep their
   selection but read as inert (toggleAnalyticsSource also sets disabled). */
.preset-chip.is-disabled,
.preset-chip:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}
.preset-chip.is-disabled:hover,
.preset-chip:disabled:hover { background: transparent; color: var(--text-secondary); }
.preset-chip.is-active.is-disabled:hover { background: var(--accent); color: #fff; }
.preset-chip {
    appearance: none;
    border: 0;
    background: transparent;
    color: var(--text-secondary);
    font: inherit;
    font-size: 0.78rem;
    font-weight: 600;
    line-height: 1;
    padding: 6px 10px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.preset-chip:hover { background: var(--subtle-bg); color: var(--text-primary); }
.preset-chip.is-active {
    background: var(--accent);
    color: #fff;
    box-shadow: 0 1px 0 rgba(255,255,255,0.04) inset;
}
.preset-chip.is-active:hover { background: var(--accent); color: #fff; }
.analytics-range-row {
    display: inline-flex;
    gap: 6px;
    align-items: center;
}
.analytics-range-sep { color: var(--text-muted); font-size: 0.85rem; }
.glass-input-sm { max-width: 150px; padding: 4px 8px; font-size: 0.85rem; }
.chart-header-note {
    display: block;
    font-size: 0.72rem;
    font-style: italic;
    color: var(--text-muted);
    font-weight: 400;
    margin-top: 2px;
}
@media (max-width: 768px) {
    .analytics-controls-row > * { width: 100%; }
    .analytics-sources { flex-direction: column; gap: 8px; }
    /* Projects chip takes the group's first line; its status chips wrap onto
       their own line INSIDE the same box, under a divider — containment reads
       on a narrow screen too. */
    .analytics-source-group .source-chip { flex: 1 1 100%; }
    .analytics-source-group .analytics-statuses {
        flex: 1 1 100%;
        margin-left: 0;
        margin-top: 4px;
        padding-left: 0;
        padding-top: 6px;
        border-left: none;
        border-top: 1px solid var(--border-subtle);
    }
    /* ≥44px touch targets for every control on small screens. */
    .preset-chip { flex: 1 1 auto; text-align: center; padding: 13px 10px; }
    .analytics-refresh { margin-left: 0; min-height: 44px; }
    .glass-input-sm { max-width: none; flex: 1 1 auto; }
}

.analytics-container {
    padding: 14px;
    height: 100%;
    overflow-y: auto;
    display: grid;
    grid-template-columns: 1fr;
    gap: 14px;
    padding-bottom: 100px;
}
.chart-card {
    background: var(--bg-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    padding: 18px;
    display: flex;
    flex-direction: column;
    box-shadow: var(--card-shadow);
}
body.dark-theme .chart-card { background: var(--subtle-bg); }
.chart-card.full-width { grid-column: 1 / -1; }
.chart-header {
    margin-bottom: 16px;
    border-bottom: 1px solid var(--border-subtle);
    padding-bottom: 10px;
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.chart-header h3 {
    color: var(--text-primary);
    font-size: 1rem;
    text-transform: none;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    letter-spacing: -0.01em;
}
.chart-body {
    flex: 1;
    min-height: 220px;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
}

.cfd-chart { width: 100%; height: 100%; overflow: visible; }
.cfd-area { fill-opacity: 0.18; stroke-width: 2; }
.cfd-line { fill: none; stroke-width: 2.5; stroke-linecap: round; }
.cfd-axis { stroke: var(--border-subtle); stroke-width: 1; }
.cfd-label { font-size: 11px; font-weight: 500; fill: var(--text-secondary); }
.cfd-axis-label { fill: var(--text-muted); font-size: 9px; }
.cfd-axis-title { fill: var(--text-primary); font-size: 11px; font-weight: 600; }
.cfd-tick { stroke: var(--border-subtle); stroke-width: 1; }
.cfd-grid { stroke: var(--text-muted); stroke-width: 1; stroke-dasharray: 4, 4; opacity: 0.3; }
.cfd-tooltip {
    position: absolute;
    background: var(--bg-elevated);
    color: var(--text-primary);
    padding: 6px 10px;
    border-radius: var(--radius-sm);
    font-size: 0.78rem;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.2s;
    border: 1px solid var(--border-strong);
    box-shadow: var(--modal-shadow);
}

/* Performance matrix */
.perf-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
    width: 100%;
}
.perf-card {
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    padding: 14px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    border-left: 4px solid var(--border-strong);
}
.perf-card.high-perf  { border-left-color: var(--success); }
.perf-card.needs-help { border-left-color: var(--danger); }
.perf-card.steady     { border-left-color: var(--warning); }
.perf-metric {
    display: flex;
    justify-content: space-between;
    font-size: 0.86rem;
}
.perf-metric span:last-child { font-weight: 700; }
.perf-bar-bg {
    height: 6px;
    background: var(--border-subtle);
    border-radius: 3px;
    overflow: hidden;
    margin-top: 4px;
}
.perf-bar-fill {
    height: 100%;
    background: var(--accent-cyan);
    border-radius: 3px;
    transition: width 0.4s ease;
}
.perf-sort {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 0.82rem;
    color: var(--text-muted);
}
.perf-sort select { padding: 4px 8px; font-size: 0.82rem; }
.perf-overdue { color: var(--danger); }

.rec-box {
    background: var(--active-bg);
    border: 1px solid var(--accent-cyan);
    padding: 14px;
    border-radius: var(--radius-md);
    margin-bottom: 14px;
}
.rec-title {
    font-weight: 700;
    color: var(--accent-cyan);
    margin-bottom: 6px;
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 0.78rem;
}
.rec-text {
    font-size: 0.88rem;
    color: var(--text-secondary);
    line-height: 1.55;
}

.bottleneck-bar {
    display: flex;
    height: 28px;
    border-radius: var(--radius-sm);
    overflow: hidden;
    margin-top: 10px;
    border: 1px solid var(--border-subtle);
}
.bn-segment {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.72rem;
    color: #fff;
    font-weight: 700;
    transition: width 0.5s;
}

.forecast-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 10px;
}
.forecast-table th {
    text-align: left;
    padding: 10px;
    border-bottom: 1px solid var(--border-subtle);
    color: var(--text-muted);
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.forecast-table td {
    padding: 12px 10px;
    border-bottom: 1px solid var(--border-subtle);
}
.forecast-row:last-child td { border-bottom: none; }
.prob-badge {
    padding: 4px 10px;
    border-radius: var(--radius-sm);
    font-size: 0.78rem;
    font-weight: 700;
    display: inline-block;
    min-width: 80px;
    text-align: center;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.prob-50 {
    background: rgba(245, 158, 11, 0.15);
    color: var(--warning);
    border: 1px solid var(--warning);
}
.prob-85 {
    background: var(--active-bg);
    color: var(--accent-cyan);
    border: 1px solid var(--accent-cyan);
}
.prob-95 {
    background: rgba(22, 163, 74, 0.12);
    color: var(--success);
    border: 1px solid var(--success);
}
.forecast-summary {
    display: flex;
    gap: 14px;
    margin-bottom: 18px;
    background: var(--subtle-bg);
    padding: 14px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border-subtle);
    flex-wrap: wrap;
}
.forecast-stat {
    flex: 1;
    min-width: 120px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
}
.forecast-stat span:first-child {
    font-size: 0.72rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 700;
}
.forecast-stat span:last-child {
    font-size: 1.2rem;
    font-weight: 700;
    color: var(--text-primary);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}

/* ---------------------------------------------------------------------
   23. Team & Admin views
   --------------------------------------------------------------------- */
.team-view-container {
    padding: 18px;
    height: 100%;
    overflow-y: auto;
}
.team-details-header {
    margin-bottom: 22px;
    border-bottom: 1px solid var(--border-subtle);
    padding-bottom: 18px;
}
.team-details-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 18px;
}
.detail-card {
    background: var(--bg-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    padding: 18px;
    box-shadow: var(--card-shadow);
}
body.dark-theme .detail-card { background: var(--subtle-bg); }
.detail-card h3 {
    margin-bottom: 12px;
    color: var(--accent-cyan);
    border-bottom: 1px solid var(--border-subtle);
    padding-bottom: 10px;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 0.92rem;
}
.member-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.88rem;
}
.member-table th {
    text-align: left;
    padding: 10px;
    color: var(--text-muted);
    border-bottom: 1px solid var(--border-subtle);
    font-size: 0.74rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.member-table td {
    padding: 10px;
    border-bottom: 1px solid var(--border-subtle);
}
.admin-badge {
    display: inline-block;
    margin-left: 6px;
    padding: 2px 6px;
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    background: rgba(2, 132, 199, 0.12);
    color: var(--accent-cyan);
    border: 1px solid rgba(2, 132, 199, 0.3);
    border-radius: var(--radius-sm);
    line-height: 1;
    vertical-align: middle;
}
body.dark-theme .admin-badge {
    background: rgba(56, 189, 248, 0.14);
    border-color: rgba(56, 189, 248, 0.3);
}
.member-legend {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 4px 0 12px;
    font-size: 0.74rem;
    color: var(--text-muted);
}
.member-legend .admin-badge { margin-left: 0; }
.project-list-simple {
    list-style: none;
    padding: 0;
}
.project-list-simple li {
    padding: 10px;
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    margin-bottom: 6px;
    border-radius: var(--radius-md);
    display: flex;
    justify-content: space-between;
    align-items: center;
    transition: var(--ease-snappy);
}
.project-list-simple li:hover {
    background: var(--hover-bg);
    border-color: var(--accent-cyan);
    cursor: pointer;
}

/* Admin team list */
.team-list-admin {
    margin-top: 16px;
    overflow-y: auto;
}
.team-item {
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    padding: 12px;
    border-radius: var(--radius-md);
    margin-bottom: 8px;
}
.team-item-header {
    font-weight: 700;
    display: flex;
    justify-content: space-between;
    margin-bottom: 6px;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    letter-spacing: 0.02em;
    color: var(--text-primary);
}
.team-members {
    font-size: 0.92rem;
    color: var(--text-secondary);
    padding-left: 8px;
    list-style: none;
}
.team-members li {
    list-style: none;
    padding: 2px 0;
}

/* Admin sections */
.admin-section { transition: all 0.3s ease-in-out; }
.admin-section-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    cursor: pointer;
    padding: 16px 18px;
}
.admin-section-header h3 {
    margin: 0;
    text-transform: uppercase;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-size: 0.92rem;
    letter-spacing: 0.02em;
    color: var(--text-primary);
}
.admin-section-header .toggle-icon {
    font-size: 1.1rem;
    transition: transform 0.3s ease-out;
    color: var(--text-muted);
}
.admin-section.collapsed .toggle-icon { transform: rotate(-90deg); }
.admin-section-content {
    padding: 0 18px 18px 18px;
    opacity: 1;
    transition: opacity 0.3s ease-out, padding 0.3s ease-out;
}
.admin-section.collapsed .admin-section-content {
    display: none;
    opacity: 0;
    padding-top: 0;
    padding-bottom: 0;
}
.admin-section:not(.collapsed) .admin-section-content {
    animation: adminSlideDown 0.32s ease-out;
}

/* My Tasks injects .admin-grid inside this wrapper, so the wrapper must
   carry the flex chain (like .main-content) or .admin-grid's flex:1 +
   overflow-y:auto can't size/scroll and content gets clipped. */
#my-tasks-container {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* My Tasks boards (simple + project sections) render .workflow-columns straight
   into .admin-section-content, which — unlike the main board's .swimlane-content
   — has no horizontal scroll. The inline grid is repeat(N, minmax(260px,1fr)), so
   on a narrow screen the 260px-min tracks can't shrink and the columns spilled out
   of the panel. Scroll horizontally instead, matching the main board. */
#my-tasks-container .workflow-columns { overflow-x: auto; }

.admin-grid {
    flex: 1;
    overflow-y: auto;
    padding: 18px;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.admin-header {
    padding: 14px 16px;
    margin-bottom: 18px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    background: var(--bg-main);
    border-bottom: 1px solid var(--border-subtle);
}
.admin-header h1 {
    font-size: clamp(1.1rem, 2vw + 0.5rem, 1.5rem);
    margin: 0;
    flex: 1;
    min-width: 0;
}
.admin-header-actions {
    display: flex;
    gap: 8px;
    align-items: center;
}

/* Admin status zone (drag area) */
.admin-status-zone {
    background: var(--subtle-bg);
    border: 2px dashed var(--border-strong);
    border-radius: var(--radius-md);
    padding: 14px;
    margin-bottom: 16px;
    min-height: 100px;
    transition: var(--ease-snappy);
}
.admin-status-zone.drag-over {
    background: var(--active-bg);
    border-color: var(--accent-cyan);
}
.admin-status-header {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--text-primary);
    margin-bottom: 12px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.admin-project-card {
    background: var(--bg-main);
    padding: 12px;
    border-radius: var(--radius-md);
    margin-bottom: 8px;
    cursor: grab;
    border: 1px solid var(--border-subtle);
    transition: var(--ease-snappy);
}
body.dark-theme .admin-project-card { background: var(--bg-elevated); }
.admin-project-card:hover {
    border-color: var(--accent-cyan);
    transform: translateY(-1px);
    box-shadow: var(--card-shadow);
}
.admin-project-card.dragging {
    opacity: 0.5;
    border: 1px dashed var(--border-strong);
    cursor: grabbing;
}
/* :hover applies transform:translateY(-1px), which creates a stacking
   context that traps an open dropdown's z-index inside the card. Later
   sibling cards (positioned .custom-select-wrapper content) then paint over
   the open options, making them unclickable. Raise the whole card while one
   of its dropdowns is open so the options sit above the cards below. */
.admin-project-card:has(.custom-options.open) {
    position: relative;
    z-index: 1000;
}

/* Time analysis cards */
.time-card {
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    margin-bottom: 10px;
    overflow: hidden;
    transition: var(--ease-snappy);
}
.time-card:hover { border-color: var(--accent-cyan); }
.time-card-header {
    padding: 12px 16px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    cursor: pointer;
    user-select: none;
}
.time-card-header h3 {
    margin: 0;
    font-size: 0.95rem;
    color: var(--project-color);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    letter-spacing: -0.01em;
    text-transform: none;
}
.time-card-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
    margin-top: 14px;
}
.time-card-grid > div { min-width: 0; overflow: hidden; }
.task-time-row {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 10px;
    padding: 4px 0;
    border-bottom: 1px solid var(--border-subtle);
    font-size: 0.86rem;
}
.task-time-title {
    flex: 1;
    min-width: 0;
    word-wrap: break-word;
    overflow-wrap: break-word;
}
.task-time-hours {
    white-space: nowrap;
    flex-shrink: 0;
    font-weight: 700;
    color: var(--accent-cyan);
}
.time-card-content {
    padding: 0 16px 16px 16px;
    border-top: 1px solid var(--border-subtle);
    max-height: 50000px;
    opacity: 1;
    overflow: visible;
    transition: max-height 0.5s ease-out, opacity 0.3s ease-out, padding 0.3s ease-out;
}
.time-card.collapsed .time-card-content {
    max-height: 0;
    opacity: 0;
    padding-top: 0;
    padding-bottom: 0;
    border-top: none;
}
.time-card .toggle-icon {
    transition: transform 0.3s;
    display: inline-block;
    margin-left: 10px;
    font-size: 0.78rem;
    color: var(--text-muted);
}
.time-card.collapsed .toggle-icon { transform: rotate(-90deg); }

/* Dev time cards */
.dev-time-card {
    background: var(--bg-main);
    border-radius: var(--radius-sm);
    margin-bottom: 6px;
    overflow: hidden;
    border: 1px solid var(--border-subtle);
}
body.dark-theme .dev-time-card { background: var(--bg-elevated); }
.dev-time-card-header {
    padding: 8px 12px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    cursor: pointer;
    font-size: 0.88rem;
    font-weight: 600;
    transition: background var(--motion-fast);
}
.dev-time-card-header:hover { background: var(--hover-bg); }
.dev-time-card-content {
    padding: 10px 12px;
    background: var(--subtle-bg);
    border-top: 1px solid var(--border-subtle);
    font-size: 0.84rem;
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-height: 50000px;
    opacity: 1;
    overflow: visible;
    transition: max-height 0.5s ease-out, opacity 0.25s ease-out, padding 0.25s ease-out;
}
.dev-time-card.collapsed .dev-time-card-content {
    max-height: 0;
    opacity: 0;
    padding-top: 0;
    padding-bottom: 0;
    border-top: none;
}
.dev-time-card .toggle-icon {
    font-size: 0.74rem;
    transition: transform 0.2s;
    color: var(--text-muted);
}
.dev-time-card.collapsed .toggle-icon { transform: rotate(-90deg); }

/* ---------------------------------------------------------------------
   24. SWOT module
   --------------------------------------------------------------------- */
.swot-container {
    padding: 18px 22px 100px;
    height: 100%;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 16px;
}
.swot-section {
    padding: 18px;
    border-radius: var(--radius-lg);
    background: var(--bg-secondary);
    border: 1px solid var(--border-subtle);
}
body.dark-theme .swot-section { background: var(--subtle-bg); }
.swot-context-controls {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
}
.swot-workspace {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
    min-height: 500px;
}
.swot-brainstorm {
    padding: 18px;
    border-radius: var(--radius-lg);
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    display: flex;
    flex-direction: column;
}
.swot-input-group {
    display: flex;
    gap: 8px;
    margin-bottom: 14px;
    flex-wrap: wrap;
}
.swot-matrix {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
}
.swot-quadrant {
    padding: 14px;
    border-radius: var(--radius-lg);
    display: flex;
    flex-direction: column;
    min-height: 200px;
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
}
.quadrant-header {
    display: flex;
    justify-content: space-between;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    margin-bottom: 10px;
    text-transform: uppercase;
    font-size: 0.8rem;
    color: var(--text-secondary);
    letter-spacing: 0.04em;
}
.swot-drop-zone {
    flex: 1;
    background: var(--bg-main);
    border-radius: var(--radius-md);
    padding: 10px;
    border: 1px dashed var(--border-strong);
}
body.dark-theme .swot-drop-zone { background: var(--bg-elevated); }
.swot-item {
    background: var(--bg-main);
    padding: 8px 12px;
    border-radius: var(--radius-md);
    margin-bottom: 6px;
    cursor: grab;
    border: 1px solid var(--border-subtle);
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 0.88rem;
    transition: border-color var(--motion-fast);
}
body.dark-theme .swot-item { background: var(--bg-secondary); }
.swot-item:hover { border-color: var(--accent-cyan); }
.swot-item-meta {
    display: flex;
    gap: 8px;
    align-items: center;
}
.priority-indicator {
    cursor: pointer;
    font-weight: 700;
    font-size: 1rem;
    user-select: none;
    transition: transform var(--motion-fast);
}
.priority-indicator.p-1 { color: var(--success); }
.priority-indicator.p-2 { color: var(--warning); }
.priority-indicator.p-3 { color: var(--danger); }
.priority-indicator:hover { opacity: 0.85; transform: scale(1.1); }
.delete-swot {
    cursor: pointer;
    color: var(--text-muted);
    font-size: 1rem;
}
.delete-swot:hover { color: var(--danger); }
.swot-actions {
    display: flex;
    justify-content: center;
    margin-top: 18px;
}
.swot-ai-section {
    margin-top: 22px;
    padding-top: 18px;
    border-top: 1px solid var(--border-subtle);
    animation: slideDown 0.3s ease-out;
}
.swot-generated-grid {
    display: flex;
    flex-direction: column;
    gap: 22px;
    margin-top: 14px;
}
.swot-gen-card {
    background: var(--bg-main);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    padding: 14px;
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 10px;
    transition: var(--ease-snappy);
}
body.dark-theme .swot-gen-card { background: var(--bg-elevated); }
.swot-gen-card.selected {
    box-shadow: 0 0 0 2px var(--accent-cyan);
    background: var(--active-bg);
    border-color: var(--accent-cyan);
}
.swot-gen-card:not(.selected) { opacity: 0.6; }
.gen-context-badge {
    font-size: 0.66rem;
    padding: 2px 7px;
    border-radius: var(--radius-sm);
    background: var(--subtle-bg);
    color: var(--text-muted);
    margin-bottom: 6px;
    display: inline-block;
    text-transform: uppercase;
    font-weight: 700;
    letter-spacing: 0.06em;
}
.swot-results-group {
    padding: 18px;
    border-radius: var(--radius-lg);
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
}
.swot-results-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--border-subtle);
    flex-wrap: wrap;
}
.swot-results-header h4 {
    margin: 0;
    font-size: 1rem;
    color: var(--text-primary);
    text-transform: none;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.swot-results-cards {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
}
.gen-subtasks {
    background: var(--subtle-bg);
    padding: 10px;
    border-radius: var(--radius-sm);
    font-size: 0.84rem;
    border: 1px solid var(--border-subtle);
}
.gen-subtasks ul { list-style: none; padding: 0; margin: 0; }
.gen-subtasks li {
    display: flex;
    gap: 8px;
    align-items: flex-start;
    margin-bottom: 4px;
    color: var(--text-secondary);
}
.gen-subtasks li input { margin-top: 3px; accent-color: var(--accent-cyan); }
.gen-subtasks label {
    display: block;
    font-size: 0.7rem;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 5px;
    font-weight: 700;
    letter-spacing: 0.06em;
}

/* --- SWOT AI action-plan loading overlay -------------------------------
   Shown while the generate-action-plan AI call is in flight (5–30s).
   Full-screen blur backdrop + a centred card with an animated SVG
   "neural" node graph: a glowing brain hexagon at the centre, eight
   orbiting nodes connected via marching-ants dashed lines, and a
   rotating outer dashed ring. Captioned with a rotating status line. */
.swot-ai-loading-overlay {
    position: fixed;
    inset: 0;
    background: rgba(9, 18, 30, 0.72);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    z-index: 9000;
    display: flex;
    align-items: center;
    justify-content: center;
    animation: swotAiFadeIn 0.25s ease-out;
}
.swot-ai-loading-overlay.closing { animation: swotAiFadeOut 0.22s ease-in forwards; }
@keyframes swotAiFadeIn  { from { opacity: 0; } to { opacity: 1; } }
@keyframes swotAiFadeOut { from { opacity: 1; } to { opacity: 0; } }

.swot-ai-loader-card {
    background: var(--bg-secondary);
    border-radius: var(--radius-lg);
    border: 1px solid var(--border-subtle);
    padding: 26px 36px 30px;
    max-width: 380px;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
}
body.dark-theme .swot-ai-loader-card { background: var(--bg-elevated); }

.swot-ai-loader-svg {
    width: 200px;
    height: 200px;
    display: block;
}

/* Halo behind the brain — slow pulsing breath. */
.swot-ai-loader-svg .ai-halo {
    transform-box: fill-box;
    transform-origin: center;
    animation: aiHaloPulse 2.6s ease-in-out infinite;
}
@keyframes aiHaloPulse {
    0%, 100% { transform: scale(0.92); opacity: 0.55; }
    50%      { transform: scale(1.08); opacity: 1; }
}

/* Outer dashed ring — slow CCW spin. */
.swot-ai-loader-svg .ai-ring {
    stroke: var(--accent-cyan);
    stroke-width: 1.5;
    opacity: 0.55;
    transform-box: fill-box;
    transform-origin: center;
    animation: aiRingSpin 16s linear infinite;
}
@keyframes aiRingSpin {
    from { transform: rotate(0deg);    }
    to   { transform: rotate(-360deg); }
}

/* Connection lines — marching ants towards the brain. */
.swot-ai-loader-svg .ai-conn {
    stroke: var(--accent-cyan);
    stroke-width: 1.3;
    stroke-dasharray: 4 6;
    opacity: 0.7;
    animation: aiConnFlow 1.8s linear infinite;
}
/* Stagger each line so the "data flowing in" feel is asymmetric. */
.swot-ai-loader-svg .ai-conn-2 { animation-delay: -0.2s; }
.swot-ai-loader-svg .ai-conn-3 { animation-delay: -0.4s; }
.swot-ai-loader-svg .ai-conn-4 { animation-delay: -0.6s; }
.swot-ai-loader-svg .ai-conn-5 { animation-delay: -0.8s; }
.swot-ai-loader-svg .ai-conn-6 { animation-delay: -1.0s; }
.swot-ai-loader-svg .ai-conn-7 { animation-delay: -1.2s; }
.swot-ai-loader-svg .ai-conn-8 { animation-delay: -1.4s; }
@keyframes aiConnFlow {
    from { stroke-dashoffset: 0;   }
    to   { stroke-dashoffset: -20; }
}

/* Orbiting nodes — staggered pulse so the activity reads as
   "many ideas at once" rather than a single throb. */
.swot-ai-loader-svg .ai-node {
    fill: var(--accent-cyan);
    transform-box: fill-box;
    transform-origin: center;
    animation: aiNodePulse 2.4s ease-in-out infinite;
}
.swot-ai-loader-svg .ai-node-1 { animation-delay: 0s;     }
.swot-ai-loader-svg .ai-node-2 { animation-delay: 0.15s;  }
.swot-ai-loader-svg .ai-node-3 { animation-delay: 0.30s;  }
.swot-ai-loader-svg .ai-node-4 { animation-delay: 0.45s;  }
.swot-ai-loader-svg .ai-node-5 { animation-delay: 0.60s;  }
.swot-ai-loader-svg .ai-node-6 { animation-delay: 0.75s;  }
.swot-ai-loader-svg .ai-node-7 { animation-delay: 0.90s;  }
.swot-ai-loader-svg .ai-node-8 { animation-delay: 1.05s;  }
@keyframes aiNodePulse {
    0%, 100% { opacity: 0.35; transform: scale(0.7);  }
    50%      { opacity: 1;    transform: scale(1.15); }
}

/* Central brain hexagon. */
.swot-ai-loader-svg .ai-brain-shell {
    fill: var(--bg-main);
    stroke: var(--accent-cyan);
    stroke-width: 2;
    transform-box: fill-box;
    transform-origin: center;
    animation: aiBrainPulse 2s ease-in-out infinite;
}
body.dark-theme .swot-ai-loader-svg .ai-brain-shell { fill: var(--bg-elevated); }
@keyframes aiBrainPulse {
    0%, 100% { transform: scale(1);    opacity: 1;    }
    50%      { transform: scale(1.04); opacity: 0.95; }
}
.swot-ai-loader-svg .ai-circuit path {
    fill: none;
    stroke: var(--accent-cyan);
    stroke-width: 1.4;
    stroke-linecap: round;
    opacity: 0.85;
}
.swot-ai-loader-svg .ai-circuit-dot { fill: var(--accent-cyan); opacity: 0.85; }
.swot-ai-loader-svg .ai-circuit-core {
    fill: var(--accent-cyan);
    transform-box: fill-box;
    transform-origin: center;
    animation: aiCoreBlink 1.4s ease-in-out infinite;
}
@keyframes aiCoreBlink {
    0%, 100% { opacity: 0.6; transform: scale(0.9); }
    50%      { opacity: 1;   transform: scale(1.2); }
}

/* Caption + status line + thin indeterminate progress strip. */
.swot-ai-loader-caption {
    text-align: center;
    color: var(--text-primary);
    width: 100%;
}
.swot-ai-loader-title {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 1.05rem;
    margin-bottom: 4px;
}
.swot-ai-loader-step {
    font-size: 0.85rem;
    color: var(--text-muted);
    min-height: 1.25em;
    transition: opacity 0.18s ease;
}
.swot-ai-loader-step.fading { opacity: 0; }
.swot-ai-loader-progress {
    margin: 14px auto 0;
    width: 220px;
    height: 4px;
    background: var(--subtle-bg);
    border-radius: 2px;
    overflow: hidden;
    position: relative;
}
.swot-ai-loader-progress-bar {
    position: absolute;
    top: 0;
    height: 100%;
    width: 35%;
    background: linear-gradient(90deg, transparent 0%, var(--accent-cyan) 50%, transparent 100%);
    animation: aiProgressSweep 1.8s ease-in-out infinite;
}
@keyframes aiProgressSweep {
    0%   { left: -35%;  }
    100% { left: 100%;  }
}

/* Respect reduced-motion preferences: keep the layout, drop the spinners. */
@media (prefers-reduced-motion: reduce) {
    .swot-ai-loader-svg .ai-halo,
    .swot-ai-loader-svg .ai-ring,
    .swot-ai-loader-svg .ai-conn,
    .swot-ai-loader-svg .ai-node,
    .swot-ai-loader-svg .ai-brain-shell,
    .swot-ai-loader-svg .ai-circuit-core,
    .swot-ai-loader-progress-bar {
        animation: none !important;
    }
}

/* --- SWOT final-step kanban-style layout ---------------------------------
   Phases become swimlanes on export, so we mirror that here: one panel
   per phase, parent task cards stacked inside, subtasks rendered as
   indented child cards under their parent (visually nested via left
   border + indent + ↳ connector). */
.swot-phase-section {
    padding: 16px 16px 14px;
    border-radius: var(--radius-lg);
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
}
.swot-phase-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    padding-bottom: 10px;
    margin-bottom: 14px;
    border-bottom: 1px solid var(--border-subtle);
}
.swot-phase-title {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
}
.swot-phase-name {
    margin: 0;
    font-size: 1.02rem;
    color: var(--text-primary);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.swot-phase-count {
    font-size: 0.78rem;
    color: var(--text-muted);
    background: var(--bg-secondary);
    padding: 2px 8px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border-subtle);
    font-weight: 600;
}
.swot-phase-range {
    font-size: 0.78rem;
    color: var(--text-secondary);
    font-family: 'JetBrains Mono', ui-monospace, Menlo, monospace;
}
.swot-phase-tasks {
    display: grid;
    grid-template-columns: 1fr;
    gap: 14px;
}

/* Parent task card — the primary unit in a phase. */
.swot-task-card {
    background: var(--bg-main);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    padding: 14px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    transition: var(--ease-snappy);
}
body.dark-theme .swot-task-card { background: var(--bg-elevated); }
.swot-task-card.selected {
    box-shadow: 0 0 0 2px var(--accent-cyan);
    background: var(--active-bg);
    border-color: var(--accent-cyan);
}
.swot-task-card:not(.selected) { opacity: 0.62; }
.swot-task-card-head {
    display: flex;
    align-items: center;
    gap: 10px;
}
.swot-task-title-input {
    flex: 1;
    font-weight: 700;
    font-size: 1rem;
}
.swot-task-desc-input {
    width: 100%;
    box-sizing: border-box;
    font-size: 0.86rem;
    color: var(--text-secondary);
}

/* Subtask cards — indented, smaller, accent-rule on the left so it's
   visually clear they belong to the task above. */
.swot-subtasks-section {
    background: var(--subtle-bg);
    padding: 10px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border-subtle);
}
.swot-subtasks-section-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 8px;
    font-weight: 700;
    letter-spacing: 0.06em;
}
.swot-subtask-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 8px;
}
.swot-subtask-card {
    display: flex;
    gap: 8px;
    align-items: flex-start;
    padding: 8px 10px;
    margin-left: 14px;
    background: var(--bg-main);
    border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--accent-cyan);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
body.dark-theme .swot-subtask-card { background: var(--bg-elevated); }
.swot-subtask-connector {
    color: var(--accent-cyan);
    font-size: 1rem;
    line-height: 1.6;
    flex-shrink: 0;
    user-select: none;
}
.swot-subtask-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.swot-subtask-row {
    display: flex;
    gap: 8px;
    align-items: center;
}
.swot-subtask-title-input { flex: 1; font-size: 0.88rem; }

/* Task-modal Activity feed: column/swimlane names inside "Moved from X to Y" /
   "Swimlane changed" lines — full-strength text color (black in light theme)
   against the softer line text, no weight change. Names are snapshots from
   the log itself. */
#modal-activity .activity-entity {
    color: var(--text-primary);
}

/* Chapter badge — the hierarchical outline label (e.g. "1.1.2") rendered
   before titles. Monospace so dotted numbers align across cards; small,
   muted background so it doesn't compete with the title text. */
.task-chapter,
.swot-task-chapter,
.swot-subtask-chapter {
    display: inline-block;
    font-family: 'JetBrains Mono', ui-monospace, Menlo, monospace;
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--accent-cyan);
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    padding: 1px 6px;
    margin-right: 6px;
    line-height: 1.5;
    user-select: text;
}
.swot-task-chapter { font-size: 0.78rem; }
.swot-subtask-chapter { font-size: 0.72rem; }
.swot-subtask-meta {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
}

.ai-suggestions-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 14px;
}
.ai-card {
    padding: 14px;
    border-radius: var(--radius-lg);
    border: 1px solid var(--accent-cyan);
    background: var(--active-bg);
}
.ai-card-header {
    display: flex;
    justify-content: space-between;
    margin-bottom: 8px;
}

/* SMART objectives */
.smart-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 14px;
}
.smart-card {
    background: var(--bg-main);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    padding: 14px;
    display: flex;
    flex-direction: column;
}
body.dark-theme .smart-card { background: var(--bg-elevated); }
.smart-breakdown {
    margin-bottom: 8px;
    font-size: 0.84rem;
    color: var(--text-muted);
}
.smart-field { margin-bottom: 4px; }
.smart-field strong {
    color: var(--accent-cyan);
    display: inline-block;
    width: 20px;
    font-weight: 700;
}
.smart-statement {
    margin-top: auto;
    padding-top: 10px;
    border-top: 1px solid var(--border-subtle);
    font-weight: 600;
    color: var(--text-primary);
    font-size: 0.9rem;
    line-height: 1.45;
}

/* SWOT wizard */
.swot-wizard-progress {
    display: flex;
    justify-content: space-between;
    margin-bottom: 28px;
    position: relative;
    padding: 0 24px;
}
.swot-wizard-progress::before {
    content: '';
    position: absolute;
    top: 16px;
    left: 24px;
    right: 24px;
    height: 2px;
    background: var(--border-subtle);
    z-index: 0;
}
.swot-step-indicator {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--bg-main);
    border: 2px solid var(--border-strong);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    position: relative;
    z-index: 1;
    transition: var(--ease-snappy);
    color: var(--text-secondary);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
body.dark-theme .swot-step-indicator { background: var(--bg-elevated); }
.swot-step-indicator.active {
    border-color: var(--accent-cyan);
    background: var(--accent-cyan);
    color: #fff;
    box-shadow: 0 0 0 4px var(--accent-glow);
}
body.dark-theme .swot-step-indicator.active { color: #0A1220; }
.swot-step-indicator.completed {
    border-color: var(--success);
    background: var(--success);
    color: #fff;
}
.swot-step-label {
    position: absolute;
    top: 38px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 0.7rem;
    white-space: nowrap;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 700;
}
.swot-step-indicator.active .swot-step-label { color: var(--accent-cyan); }

.ai-chat-interface {
    background: var(--subtle-bg);
    border-radius: var(--radius-md);
    padding: 14px;
    margin-top: 18px;
    border: 1px solid var(--border-subtle);
}
.ai-message {
    display: flex;
    gap: 10px;
    margin-bottom: 10px;
}
.ai-avatar {
    width: 32px;
    height: 32px;
    background: var(--accent);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.8rem;
    flex-shrink: 0;
    color: #fff;
    font-weight: 700;
}
.ai-bubble {
    background: var(--bg-main);
    padding: 10px 14px;
    border-radius: 0 var(--radius-md) var(--radius-md) var(--radius-md);
    font-size: 0.88rem;
    border: 1px solid var(--border-subtle);
    max-width: 80%;
    color: var(--text-primary);
}
body.dark-theme .ai-bubble { background: var(--bg-elevated); }

.grid-col-2 {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
}

/* ---------------------------------------------------------------------
   25. Permission UI: chips, picker, badges
   --------------------------------------------------------------------- */
.chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    min-height: 28px;
    padding: 4px 0;
}
/* Nothing picked yet means no chips at all, and min-height + padding would
   otherwise reserve 36px of blank space between a section's hint text and its
   picker. Every .chip-row in the app is a "what you've selected" list that is
   legitimately empty at rest, so collapse it until it has something to show.
   (JS builds these with innerHTML = '', so :empty really does match.) */
.chip-row:empty { display: none; }
.chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: 14px;
    background: var(--subtle-bg);
    border: 1px solid var(--border-strong);
    font-size: 0.82rem;
    color: var(--text-primary);
}
body.dark-theme .chip { background: var(--bg-elevated); }
.chip .chip-x {
    background: transparent;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    padding: 0;
    transition: color var(--motion-fast);
}
.chip .chip-x:hover { color: var(--danger); }

.picker-results {
    list-style: none;
    margin: 6px 0 0 0;
    padding: 0;
    max-height: 200px;
    overflow-y: auto;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    background: var(--bg-elevated);
    box-shadow: var(--card-shadow);
}
.picker-result {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    cursor: pointer;
    border-bottom: 1px solid var(--border-subtle);
    transition: background var(--motion-fast);
    font-size: 0.86rem;
}
.picker-result:last-child { border-bottom: none; }
.picker-result:hover { background: var(--hover-bg); }
.picker-result.empty {
    cursor: default;
    opacity: 0.6;
    justify-content: center;
}

/* ---------------------------------------------------------------------
   25b. createPillSelect — searchable chip multi-select
   (controllers/pill-select.js). Mirrors the dashboard's .ps* block from
   widget-insert.css, restyled on projex tokens so it themes with
   body.dark-theme instead of [data-theme].
   --------------------------------------------------------------------- */
.ps { display: flex; flex-direction: column; min-width: 0; }
/* Chip tray sits above the input, like the dashboard allow-list. No
   "load more" modal here — it scrolls, since the host modal scrolls too. */
.ps__pills {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 8px;
    max-height: 132px;
    overflow-y: auto;
}
.ps__pills:empty { display: none; }
.ps__pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    padding: 4px 6px 4px 10px;
    border-radius: 14px;
    background: var(--accent-glow, rgba(2, 132, 199, 0.10));
    border: 1px solid var(--border-strong);
    font-size: 0.8rem;
    font-weight: 500;
    color: var(--text-primary);
}
body.dark-theme .ps__pill { background: var(--bg-elevated); }
.ps__pill-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ps__pill-x {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.08);
    color: var(--text-muted);
    font-size: 0.9rem;
    line-height: 1;
    cursor: pointer;
    transition: background var(--motion-fast), color var(--motion-fast);
}
.ps__pill-x:hover { background: var(--danger); color: #fff; }
body.dark-theme .ps__pill-x { background: rgba(255, 255, 255, 0.14); }

.ps__controls {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
    min-width: 0;
}
.ps__search {
    flex: 1 1 160px;
    min-width: 0;
    box-sizing: border-box;
    padding: 9px 12px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    background: var(--bg-main);
    color: var(--text-primary);
    font-size: 0.86rem;
    font-family: inherit;
}
body.dark-theme .ps__search { background: var(--bg-elevated); }
.ps__search:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-glow, rgba(2, 132, 199, 0.15));
}
.ps__btn {
    flex: 0 0 auto;
    padding: 8px 12px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--text-secondary);
    font-size: 0.78rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: background var(--motion-fast), color var(--motion-fast), border-color var(--motion-fast);
}
.ps__btn:hover {
    background: var(--subtle-bg);
    border-color: var(--accent);
    color: var(--text-primary);
}

/* Dropdown — absolutely positioned so it overlays the fields below rather
   than pushing the modal taller as you type. */
.ps__panel {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 20;
    margin-top: 4px;
    max-height: 220px;
    overflow-y: auto;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    background: var(--bg-main);
    box-shadow: var(--card-shadow);
}
body.dark-theme .ps__panel { background: var(--bg-elevated); }
.ps--open .ps__panel { display: block; }
/* Long directories scroll HERE, not in the modal behind them — without this
   the wheel chains to .modal-content the moment the list bottoms out and the
   whole meeting form lurches. Gated on a class that renderPanel() sets only
   while the list actually overflows: `contain` blocks chaining even when the
   container has nothing to scroll, so applying it unconditionally would make
   a short result list a dead zone for the wheel. */
.ps__panel--scrollable { overscroll-behavior: contain; }
.ps__option {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 12px;
    font-size: 0.86rem;
    font-weight: 400;
    color: var(--text-primary);
    cursor: pointer;
    border-bottom: 1px solid var(--border-subtle);
    transition: background var(--motion-fast);
}
.ps__option:last-child { border-bottom: none; }
.ps__option--active,
.ps__option:hover { background: var(--hover-bg); }
.ps__option-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ps__option-sub {
    flex: 0 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.74rem;
    color: var(--text-muted);
}
.ps__empty {
    padding: 10px 12px;
    font-size: 0.8rem;
    color: var(--text-muted);
    text-align: center;
}
/* Sticky so the "list is capped" note stays visible while scrolling the
   matches — a cap you can only discover at the bottom isn't a warning. */
.ps__note {
    position: sticky;
    bottom: 0;
    padding: 6px 12px;
    border-top: 1px solid var(--border-subtle);
    background: var(--bg-main);
    font-size: 0.72rem;
    color: var(--text-muted);
    text-align: center;
}
body.dark-theme .ps__note { background: var(--bg-elevated); }

/* NB: the chip tray deliberately does NOT get overscroll-behavior:contain
   (the panel above does). `contain` blocks scroll chaining even when the
   container has nothing to scroll — with the tray under its max-height, a
   wheel over the chips did nothing at all instead of scrolling the meeting
   modal, turning the tray into a dead zone. The tray is passive display;
   the wheel belongs to the modal unless the tray itself can move. */

.origin-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: var(--radius-pill);
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-left: 8px;
    font-weight: 700;
}
.origin-badge.synced {
    background: var(--active-bg);
    color: var(--accent-cyan);
    border: 1px solid var(--accent-cyan);
}
.origin-badge.manual {
    background: var(--subtle-bg);
    color: var(--text-secondary);
    border: 1px solid var(--border-strong);
}

.pp-swimlane-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 8px;
    font-size: 0.85rem;
}
.pp-swimlane-table th,
.pp-swimlane-table td {
    text-align: center;
    padding: 7px 8px;
    border-bottom: 1px solid var(--border-subtle);
}
.pp-swimlane-table th {
    color: var(--text-muted);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 0.74rem;
}
.user-inactive { opacity: 0.55; }

/* ---------------------------------------------------------------------
   26. Attachments view (Details / List / Grid)
   --------------------------------------------------------------------- */
.att-view-switcher {
    display: inline-flex;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--subtle-bg);
}
.att-view-btn {
    background: transparent;
    border: none;
    padding: 7px 12px;
    font-size: 0.78rem;
    color: var(--text-secondary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    border-right: 1px solid var(--border-subtle);
    transition: var(--ease-snappy);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.att-view-btn:last-child { border-right: none; }
.att-view-btn:hover { background: var(--hover-bg); color: var(--text-primary); }
.att-view-btn.is-active {
    background: var(--accent);
    color: #fff;
}
body.dark-theme .att-view-btn.is-active {
    background: var(--accent-cyan);
    color: #0A1220;
}

.att-group {
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    overflow: hidden;
    margin-bottom: 12px;
    background: var(--bg-main);
}
body.dark-theme .att-group { background: var(--bg-secondary); }
.att-group-header {
    padding: 10px 14px;
    background: var(--subtle-bg);
    display: flex;
    flex-direction: column;
    gap: 2px;
    border-bottom: 1px solid var(--border-subtle);
}
.att-group-title {
    font-weight: 700;
    font-size: 0.9rem;
    color: var(--text-primary);
}
.att-group-subtitle {
    font-size: 0.74rem;
    color: var(--text-muted);
}

.attachments-list {
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--bg-main);
}
body.dark-theme .attachments-list { background: var(--bg-secondary); }
.att-row {
    display: grid;
    grid-template-columns: 24px minmax(0, 1.2fr) minmax(0, 1.6fr) auto;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    cursor: pointer;
    border-bottom: 1px solid var(--border-subtle);
    font-size: 0.86rem;
    transition: background var(--motion-fast);
}
.att-row:last-child { border-bottom: none; }
.att-row:hover { background: var(--hover-bg); }
.att-row-emoji { font-size: 1rem; line-height: 1; }
.att-row-name {
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.att-row-meta {
    color: var(--text-muted);
    font-size: 0.74rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.att-row-actions { display: inline-flex; gap: 2px; }

.attachments-details {
    width: 100%;
    border-collapse: collapse;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    overflow: hidden;
    font-size: 0.86rem;
    background: var(--bg-main);
}
body.dark-theme .attachments-details { background: var(--bg-secondary); }
.attachments-details thead tr {
    background: var(--subtle-bg);
    text-align: left;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}
.attachments-details th { padding: 8px 12px; font-weight: 700; }
.attachments-details td {
    padding: 8px 12px;
    border-top: 1px solid var(--border-subtle);
}
.attachments-details tbody tr:hover { background: var(--hover-bg); }
.att-cell-emoji { width: 28px; font-size: 1rem; }
.att-cell-meta { color: var(--text-muted); white-space: nowrap; }
.att-cell-actions { text-align: right; white-space: nowrap; }

.attachments-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 10px;
}
.att-card {
    position: relative;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    padding: 14px 10px 10px;
    background: var(--bg-secondary);
    cursor: pointer;
    text-align: center;
    transition: var(--ease-snappy);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
}
body.dark-theme .att-card { background: var(--subtle-bg); }
.att-card:hover {
    border-color: var(--accent-cyan);
    transform: translateY(-2px);
    box-shadow: var(--card-shadow);
}
.att-card-emoji {
    font-size: 2rem;
    line-height: 1;
    margin-bottom: 4px;
}
.att-card-name {
    font-size: 0.82rem;
    color: var(--text-primary);
    word-break: break-word;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    text-overflow: ellipsis;
    width: 100%;
    line-height: 1.25;
}
.att-card-meta {
    font-size: 0.7rem;
    color: var(--text-muted);
}
.att-card-actions {
    position: absolute;
    top: 4px;
    right: 4px;
    display: inline-flex;
    gap: 2px;
    opacity: 0;
    transition: opacity var(--motion-fast);
}
.att-card:hover .att-card-actions,
.att-card:focus-within .att-card-actions { opacity: 1; }

/* ---------------------------------------------------------------------
   27. Animations / Keyframes
   --------------------------------------------------------------------- */
@keyframes spin {
    to { transform: rotate(360deg); }
}
@keyframes invalidShake {
    0%, 100% { transform: translateX(0); }
    20% { transform: translateX(-4px); }
    40% { transform: translateX(4px); }
    60% { transform: translateX(-3px); }
    80% { transform: translateX(2px); }
}
@keyframes slideDown {
    from { transform: translateY(-100%); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
}
@keyframes slideIn {
    from { transform: translateY(20px); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
}
@keyframes modalBackdropIn {
    from { background: rgba(0, 0, 0, 0); backdrop-filter: blur(0); }
    to   { background: rgba(0, 0, 0, 0.4); backdrop-filter: blur(4px); }
}
@keyframes modalContentIn {
    from { opacity: 0; transform: scale(0.97) translateY(-8px); }
    to   { opacity: 1; transform: scale(1) translateY(0); }
}
@keyframes adminSlideDown {
    from { opacity: 0; transform: translateY(-8px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes listSectionSlide {
    0%   { opacity: 0; transform: translateY(-12px); }
    100% { opacity: 1; transform: translateY(0); }
}
@keyframes listStatusSlide {
    0%   { opacity: 0; transform: translateY(-8px); }
    100% { opacity: 1; transform: translateY(0); }
}
@keyframes pulse-blocked {
    0%   { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.3); }
    70%  { box-shadow: 0 0 0 8px rgba(220, 38, 38, 0); }
    100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0); }
}
@keyframes indicatorBlink {
    0%, 100% { opacity: 1; transform: scale(1) translateY(-50%); }
    50%      { opacity: 0.55; transform: scale(0.9) translateY(-50%); }
}
/* Calmed-down legacy keyframes (still defined so any reference resolves) */
@keyframes bannerShimmer {
    0%   { transform: translateX(-100%); opacity: 0; }
    50%  { opacity: 0.4; }
    100% { transform: translateX(100%); opacity: 0; }
}
@keyframes gradientFlow {
    0%   { background-position: 0% 50%; }
    100% { background-position: 200% 50%; }
}
@keyframes bannerGlow {
    0%, 100% { box-shadow: 0 1px 0 rgba(0, 0, 0, 0.05); }
    50%      { box-shadow: 0 2px 8px rgba(220, 38, 38, 0.18); }
}
@keyframes floatingBtnPulse {
    0%, 100% { opacity: 0.85; }
    50%      { opacity: 1; }
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ---------------------------------------------------------------------
   28. Responsive layers (mobile-first, only min-width queries)
   --------------------------------------------------------------------- */

/* sm: 640px+ — small tablets / large phones landscape */
@media (min-width: 640px) {
    .top-bar { padding: 14px 18px; }
    .board-container { padding: 16px 18px; }

    .controls {
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        gap: 10px;
    }
    .controls-buttons {
        grid-column: 1 / -1;
        flex-wrap: wrap;
    }
    .controls-buttons .glass-btn,
    .controls-buttons .glass-btn-sm { flex: 0 1 auto; }

    .calendar-container { grid-template-columns: repeat(2, 1fr); }

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

    .modal { padding: 24px; }
    .modal-content { padding: 28px 24px; }

    .task-view-controls { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .task-view-body { padding: 22px; }

    .bulk-bar {
        flex-direction: row;
        left: 50%;
        right: auto;
        bottom: 18px;
        transform: translateX(-50%);
        max-width: calc(100vw - 28px);
        width: auto;
        align-items: center;
    }
    .bulk-controls { flex-wrap: wrap; }
    .bulk-controls > * { flex: 0 1 auto; }

    .notification-container {
        top: auto;
        bottom: 18px;
        left: auto;
        right: 18px;
        max-width: 360px;
    }
    .notification-toast { min-width: 260px; }

    .grid-col-2 { grid-template-columns: 1fr 1fr; }
    .smart-grid { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
    .ai-suggestions-grid { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
}

/* md: 768px+ — tablets */
@media (min-width: 768px) {
    .top-bar {
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        gap: 14px;
    }
    .top-bar > .top-bar-row { flex: 1 1 auto; min-width: 0; width: auto; }
    /* Force the view switcher to its own row at every viewport size so the
       title's character count never decides whether tabs sit inline or wrap.
       `flex-basis: 100%` claims a full wrap line in the wrapping flex row,
       matching how `.controls` already behaves. */
    .top-bar > .view-switcher {
        flex: 0 0 100%;
        align-self: flex-start;
        width: max-content;
        max-width: 100%;
    }
    .top-bar > .controls {
        flex-basis: 100%;
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        align-items: flex-end;
        gap: 10px;
    }
    .top-bar > .controls > .control-group {
        flex: 1 1 180px;
        min-width: 160px;
        max-width: 240px;
    }
    .top-bar > .controls > .controls-buttons {
        margin-left: auto;
        flex-wrap: wrap;
        flex-direction: row;
        align-items: flex-end;
    }

    .calendar-container {
        grid-template-columns: repeat(4, 1fr);
        /* Fixed-height cells from tablet up (inherited by the 7-col desktop grid):
           the month stays a tidy grid and busy days collapse to "+N more" instead
           of growing the row. Mobile (<768px) keeps auto-height stacked cards. */
        grid-auto-rows: 150px;
        gap: 10px;
        padding: 18px;
    }

    .team-details-grid { grid-template-columns: 1fr 1fr; }
    .time-card-grid { grid-template-columns: 1fr 1fr; }

    .swot-workspace { grid-template-columns: 1fr 2fr; }
    .swot-matrix {
        grid-template-columns: 1fr 1fr;
        grid-template-rows: 1fr 1fr;
        gap: 14px;
    }
    .swot-results-cards { grid-template-columns: 1fr 1fr; }

    .modal-content { max-width: 720px; padding: 32px; }

    .swarming-banner { padding-left: 60px; }

    .admin-grid { padding: 28px; gap: 20px; }
    .admin-header { padding: 18px 24px; }

    .perf-grid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
    .analytics-container {
        padding: 24px;
        grid-template-columns: 1fr 1fr;
        gap: 18px;
    }
    .chart-card.full-width { grid-column: 1 / -1; }
}

/* lg: 1024px+ — laptops, persistent sidebar */
@media (min-width: 1024px) {
    .sidebar {
        position: relative;
        right: auto;
        top: auto;
        bottom: auto;
        transform: none;
        width: 264px;
        flex-shrink: 0;
        border-left: none;
        border-right: 1px solid var(--border-subtle);
        box-shadow: none !important;
    }
    .sidebar.mobile-open {
        transform: none;
        box-shadow: none;
    }
    /* Sidebar is persistent on desktop — collapsing is mobile-only */
    .sidebar.collapsed:not(.mobile-open) {
        width: 264px;
    }

    .sidebar-overlay { display: none !important; }
    .mobile-menu-toggle { display: none; }
    /* Collapse/close toggle is only meaningful for the mobile off-canvas sidebar */
    #btn-toggle-sidebar { display: none; }

    .top-bar { padding: 16px 24px; }
    .board-container { padding: 20px 24px; }

    .calendar-container { grid-template-columns: repeat(7, 1fr); }


    .workflow-section { min-width: 300px; }

    .bulk-bar { bottom: 24px; }

    .task-view-controls { grid-template-columns: repeat(3, minmax(0, 1fr)); }

    .swarming-floating-btn { width: 48px; padding: 22px 12px; }
    .swarming-floating-btn:hover { width: 56px; padding: 28px 14px; }
}

/* xl: 1280px+ — wide desktops */
@media (min-width: 1280px) {
    .sidebar { width: 280px; padding: 24px 18px; }
    .top-bar { padding: 18px 30px; }
    .board-container { padding: 22px 30px; }
    .modal-content { max-width: 900px; }
    .perf-grid { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }

    .admin-grid { padding: 36px; }
}

/* =====================================================================
   28b. POLISH — professional pass. Linear / Notion / Vercel grade.
   Subtle depth, calm motion, refined typography, no fireworks.
   ===================================================================== */

/* ---- Density tokens used by the polish layer ---- */
:root {
    --polish-card-shadow: 0 1px 2px rgba(9, 28, 58, 0.04), 0 1px 3px rgba(9, 28, 58, 0.06);
    --polish-card-shadow-hover: 0 2px 4px rgba(9, 28, 58, 0.06), 0 8px 16px rgba(9, 28, 58, 0.06);
    --polish-elevated-shadow: 0 1px 2px rgba(9, 28, 58, 0.05), 0 12px 28px rgba(9, 28, 58, 0.10);
}
body.dark-theme {
    --polish-card-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
    --polish-card-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.5);
    --polish-elevated-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
}

/* =====================================================================
   SIDEBAR
   ===================================================================== */
.sidebar {
    padding: 22px 14px 18px;
    gap: 4px;
}
.sidebar-header {
    margin-bottom: 22px;
    gap: 2px;
}
.brand-identity {
    gap: 10px;
}

.app-name {
    font-size: 0.66rem;
    color: var(--text-muted);
    letter-spacing: 0.16em;
    margin-left: 44px;
    margin-top: -2px;
}

/* Section headers — small caps, refined separator */
.nav-section { margin-bottom: 14px; }
.nav-section h3 {
    font-size: 0.62rem;
    color: var(--text-muted);
    letter-spacing: 0.14em;
    margin-bottom: 6px;
    padding: 0 10px;
}
.nav-section ul li {
    padding: 7px 10px;
    font-size: 0.85rem;
    border-radius: 6px;
    border-left: 2px solid transparent;
    color: var(--text-secondary);
    transition: background 0.15s ease, color 0.15s ease;
    margin-bottom: 1px;
}
.nav-section ul li:hover {
    background: var(--hover-bg);
    color: var(--text-primary);
}
.nav-section ul li.active {
    background: var(--active-bg);
    color: var(--accent-cyan);
    border-left-color: var(--accent-cyan);
    padding-left: 10px;
    font-weight: 600;
}

/* Project list — color dot, subtle status pill */
#project-list { padding-right: 4px; }
#project-list li {
    position: relative;
    padding-left: 22px;
    color: var(--text-secondary);
}
#project-list li::before {
    content: '';
    position: absolute;
    left: 9px;
    top: 50%;
    transform: translateY(-50%);
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--project-color, var(--text-muted));
    transition: box-shadow 0.15s ease;
}
#project-list li:hover::before {
    box-shadow: 0 0 0 3px rgba(2, 132, 199, 0.10);
}
#project-list li.active::before {
    box-shadow: 0 0 0 3px var(--active-bg);
}

/* User profile — refined card, more breathing room */
.user-profile {
    padding: 12px;
    gap: 10px;
    margin-top: 16px;
    background: var(--bg-main);
    border-radius: 10px;
    box-shadow: var(--polish-card-shadow);
}
body.dark-theme .user-profile {
    background: var(--bg-secondary);
    box-shadow: none;
}
.user-info #current-user-name {
    font-size: 0.78rem;
    text-transform: none;
    letter-spacing: 0;
    font-weight: 600;
}
.user-actions {
    margin-top: 2px;
    gap: 6px;
}

/* Avatar — solid navy, slightly softer corners */
.avatar {
    background: var(--accent);
    border-radius: 8px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07);
    width: 32px;
    height: 32px;
    font-size: 0.72rem;
}
body.dark-theme .avatar {
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

/* Theme switcher — full-width, bottom of the sidebar */
.theme-switcher {
    margin-top: 8px;
    margin-bottom: 0;
}
.theme-toggle-btn {
    height: 36px;
    border-radius: 8px;
    font-size: 0.7rem;
    letter-spacing: 0.08em;
    border: 1px solid var(--border-subtle);
    background: var(--bg-main);
    color: var(--text-secondary);
}
body.dark-theme .theme-toggle-btn {
    background: var(--bg-secondary);
    border-color: var(--border-strong);
}
.theme-toggle-btn:hover {
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
    background: var(--hover-bg);
}

/* =====================================================================
   TOP BAR — breathable hero
   ===================================================================== */
.top-bar {
    padding: 18px 24px 14px;
    gap: 16px;
    border-bottom: 1px solid var(--border-subtle);
    background: var(--bg-main);
}
.top-bar::after { content: none; }
.top-bar-row {
    gap: 14px;
}

.project-info {
    gap: 12px;
    flex-wrap: wrap;
}
.project-info h1 {
    font-size: clamp(1.15rem, 1.6vw + 0.6rem, 1.5rem);
    color: var(--project-color, var(--text-primary));
    font-weight: 700;
    letter-spacing: -0.015em;
    line-height: 1.15;
    margin: 0;
}

/* Status pill (PLANNING / ACTIVE) */
.tag.planning,
.tag.active,
.tag.archived {
    padding: 4px 10px;
    border-radius: var(--radius-pill);
    font-size: 0.62rem;
    letter-spacing: 0.1em;
    border: 1px solid;
}
.tag.planning {
    background: rgba(245, 158, 11, 0.10);
    color: var(--warning);
    border-color: rgba(245, 158, 11, 0.30);
}
.tag.active {
    background: rgba(22, 163, 74, 0.10);
    color: var(--success);
    border-color: rgba(22, 163, 74, 0.30);
}
.tag.archived {
    background: var(--subtle-bg);
    color: var(--text-muted);
    border-color: var(--border-subtle);
}

/* Deadline badge — refined cyan pill */
.deadline-badge {
    background: var(--active-bg);
    color: var(--accent-cyan);
    border: 1px solid rgba(2, 132, 199, 0.25);
    border-radius: var(--radius-pill);
    padding: 4px 10px;
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.06em;
}
body.dark-theme .deadline-badge {
    border-color: rgba(56, 189, 248, 0.30);
}

/* View switcher — segmented control */
.view-switcher {
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
    padding: 3px;
    gap: 0;
}
.view-btn {
    padding: 7px 14px;
    font-size: 0.7rem;
    border-radius: 6px;
    border: none;
    color: var(--text-muted);
    font-weight: 600;
    letter-spacing: 0.04em;
    transition: color 0.15s ease, background 0.15s ease;
}
.view-btn:hover { color: var(--text-primary); background: var(--hover-bg); }
.view-btn.active {
    background: var(--bg-main);
    color: var(--accent);
    box-shadow: 0 1px 2px rgba(9, 28, 58, 0.10), 0 0 0 1px var(--border-subtle);
}
body.dark-theme .view-btn.active {
    background: var(--bg-elevated);
    color: var(--accent-cyan);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 0 0 1px var(--border-strong);
}

/* Filter row labels — calmer, more refined */
.control-group label {
    font-size: 0.66rem;
    color: var(--text-muted);
    font-weight: 600;
    letter-spacing: 0.08em;
    margin-bottom: 4px;
}

/* =====================================================================
   BOARD — kanban polish
   ===================================================================== */
.board-container {
    padding: 18px 24px 32px;
}

/* Swimlane — quieter, more deliberate */
.swimlane {
    background: var(--bg-main);
    border: 1px solid var(--border-subtle);
    border-radius: 10px;
    margin-bottom: 16px;
    box-shadow: var(--polish-card-shadow);
    overflow: hidden;
}
body.dark-theme .swimlane {
    background: var(--bg-secondary);
    box-shadow: none;
}
.swimlane-header {
    padding: 12px 16px;
    background: var(--subtle-bg);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border-bottom: 1px solid var(--border-subtle);
    transition: background 0.15s ease;
}
.swimlane-header:hover { background: var(--hover-bg); }
body.dark-theme .swimlane-header {
    background: var(--bg-elevated);
    border-bottom-color: var(--border-subtle);
}

/* Workflow section — integrate into swimlane (no double border) */
.workflow-section {
    background: transparent;
    border: none;
    margin: 0;
    box-shadow: none;
    flex-shrink: 0;
}
body.dark-theme .workflow-section { background: transparent; }
.workflow-section + .workflow-section {
    border-left: 1px solid var(--border-subtle);
    margin-left: 12px;
    padding-left: 12px;
}
.workflow-header {
    background: transparent;
    border: none;
    padding: 4px 6px 10px;
    font-size: 0.68rem;
    color: var(--text-muted);
    letter-spacing: 0.10em;
}

.swimlane-content {
    padding: 14px 16px 18px;
    gap: 12px;
}

/* Workflow columns — better gaps */
.workflow-columns {
    gap: 12px;
    padding: 0;
    background: transparent;
}

/* Column — refined surface, status-dot header, count chip */
.column {
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    border-radius: 10px;
    padding: 12px 12px 14px;
    min-height: 140px;
    transition: border-color 0.15s ease, background 0.15s ease;
}
body.dark-theme .column {
    background: var(--bg-main);
    border-color: var(--border-subtle);
}
.column:hover { border-color: var(--border-strong); }

.column-header {
    border-left: none;
    padding: 0 0 12px;
    margin-bottom: 12px;
    border-bottom: 1px solid var(--border-subtle);
    font-size: 0.68rem;
    letter-spacing: 0.10em;
    color: var(--text-secondary);
    align-items: center;
}
.column-header > span {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.column-header > span::before {
    content: '';
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--text-muted);
    flex-shrink: 0;
}
.column[data-status*="backlog"] .column-header > span::before { background: var(--text-muted); }
.column[data-status*="doing"]   .column-header > span::before { background: var(--warning); box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.15); }
.column[data-status*="done"]    .column-header > span::before { background: var(--success); box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.15); }
.column[data-status*="backlog"] .column-header { color: var(--text-muted); }
.column[data-status*="doing"]   .column-header { color: var(--warning); }
.column[data-status*="done"]    .column-header { color: var(--success); }

.column-header .glass-btn-sm {
    border: 1px solid transparent;
    padding: 0;
    width: 22px;
    height: 22px;
    font-size: 0.95rem;
    line-height: 1;
    background: transparent;
    color: var(--text-muted);
    opacity: 0;
    transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.column:hover .column-header .glass-btn-sm { opacity: 1; }
.column-header .glass-btn-sm:hover {
    background: var(--bg-main);
    border-color: var(--border-strong);
    color: var(--accent-cyan);
}

/* Quick-add input — inviting, not noisy */
.quick-add-task {
    margin-top: 10px;
}
.quick-add-task input.glass-input {
    width: 100%;
    background: transparent;
    border: 1px dashed var(--border-strong);
    color: var(--text-secondary);
    font-size: 0.78rem;
    padding: 9px 12px;
    height: auto;
    transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.quick-add-task input.glass-input:hover {
    border-style: solid;
    border-color: var(--border-strong);
    color: var(--text-primary);
}
.quick-add-task input.glass-input:focus {
    border-style: solid;
    border-color: var(--accent-cyan);
    background: var(--bg-main);
    box-shadow: 0 0 0 3px var(--accent-glow);
    color: var(--text-primary);
}
body.dark-theme .quick-add-task input.glass-input:focus {
    background: var(--bg-elevated);
}

/* =====================================================================
   TASK CARD — clean card design
   ===================================================================== */
.task-card {
    padding: 12px 14px;
    border-radius: 8px;
    box-shadow: var(--polish-card-shadow);
    transition:
        transform 0.15s ease,
        box-shadow 0.18s ease,
        border-color 0.15s ease;
}
.task-card:hover {
    transform: translateY(-1px);
    box-shadow: var(--polish-card-shadow-hover);
    border-color: var(--border-strong);
}
body.dark-theme .task-card:hover {
    border-color: var(--border-strong);
}
.task-card.selected {
    border-color: var(--accent-cyan);
    box-shadow: 0 0 0 1px var(--accent-cyan), var(--polish-card-shadow);
    background: var(--bg-main);
}
body.dark-theme .task-card.selected {
    background: var(--bg-elevated);
}

.task-group {
    font-size: 0.6rem;
    color: var(--text-muted);
    letter-spacing: 0.10em;
    font-weight: 700;
    margin-bottom: 6px;
}
.task-tags { gap: 6px; margin-bottom: 6px; }
.task-title {
    font-size: 0.92rem;
    font-weight: 600;
    line-height: 1.35;
    margin-bottom: 0;
    color: var(--text-primary);
    letter-spacing: -0.005em;
}
.task-meta {
    margin-top: 10px;
    padding-top: 8px;
    border-top: 1px solid var(--border-subtle);
    align-items: center;
    gap: 10px;
    font-size: 0.7rem;
}
.task-meta > span {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.task-meta .avatar {
    width: 22px !important;
    height: 22px !important;
    font-size: 0.6rem !important;
    border-radius: 6px;
    margin-left: auto;
}

/* Priority tags — calmer, refined */
.tag.high {
    background: rgba(220, 38, 38, 0.10);
    color: var(--danger);
    border: 1px solid rgba(220, 38, 38, 0.25);
    border-radius: var(--radius-pill);
    padding: 2px 8px;
    font-size: 0.6rem;
    letter-spacing: 0.08em;
}
.tag.medium {
    background: rgba(245, 158, 11, 0.10);
    color: var(--warning);
    border: 1px solid rgba(245, 158, 11, 0.28);
    border-radius: var(--radius-pill);
    padding: 2px 8px;
    font-size: 0.6rem;
    letter-spacing: 0.08em;
}
.tag.low {
    background: rgba(22, 163, 74, 0.10);
    color: var(--success);
    border: 1px solid rgba(22, 163, 74, 0.28);
    border-radius: var(--radius-pill);
    padding: 2px 8px;
    font-size: 0.6rem;
    letter-spacing: 0.08em;
}

.blocked-badge {
    background: var(--danger);
    color: #fff;
    padding: 2px 8px;
    border-radius: var(--radius-pill);
    font-size: 0.6rem;
    letter-spacing: 0.08em;
    font-weight: 700;
}

/* --- Native dashboard-widget grid (analytics / financials) --------------- */
.px-widget-section { margin-bottom: 24px; }
.px-widget-section-title {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--text-secondary, #aaa);
    margin: 0 0 10px;
}
.px-widget-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 16px;
    align-items: start;
}
/* A coreidon-widget caps itself at 640px; let the cell drive width instead. */
.px-widget-cell coreidon-widget { max-width: none; margin: 0; width: 100%; }
.px-widget-cell { min-width: 0; }
.px-widget-large { grid-column: span 2; }
@media (max-width: 720px) {
    .px-widget-large { grid-column: span 1; }
}

/* Flow-efficiency breakdown — one full-width card holding two alternative
   tables (by task / by assignee). Deliberately OUTSIDE .px-widget-grid: these
   tables are wide and tall, and as grid cells they squeezed into a 280px track
   and shoved everything below them off the screen. */
.px-flow-drill {
    margin-top: 16px;
}
.px-flow-drill-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 8px;
}
.px-flow-drill-label {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text-secondary);
}
.px-flow-drill-tabs {
    display: inline-flex;
    gap: 2px;
    padding: 2px;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-pill);
    background: var(--bg-main);
}
body.dark-theme .px-flow-drill-tabs { background: var(--bg-secondary); }
.px-flow-drill-tab {
    border: none;
    background: none;
    border-radius: var(--radius-pill);
    padding: 5px 14px;
    font-family: inherit;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text-secondary);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}
.px-flow-drill-tab:hover { color: var(--text-primary); }
.px-flow-drill-tab.active {
    background: var(--accent-cyan);
    color: #fff;
}
/* The pane hosts a .px-widget-cell; it must span the full card, not a grid track. */
.px-flow-drill-pane .px-widget-cell { width: 100%; }
.resolved-badge {
    background: rgba(22, 163, 74, 0.12);
    color: var(--success);
    border: 1px solid rgba(22, 163, 74, 0.3);
    border-radius: var(--radius-pill);
    padding: 2px 8px;
    font-size: 0.6rem;
    letter-spacing: 0.08em;
}

/* =====================================================================
   TASK VIEW — refined detail panel
   ===================================================================== */
.task-view {
    background: var(--bg-main);
}
body.dark-theme .task-view {
    background: var(--bg-secondary);
}
.task-view-header {
    padding: 14px 20px;
    border-bottom: 1px solid var(--border-subtle);
    background: var(--bg-main);
}
body.dark-theme .task-view-header {
    background: var(--bg-secondary);
}
.task-view-title {
    font-size: 1.25rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    text-transform: none;
    line-height: 1.25;
}
.task-view-section {
    padding-top: 16px;
    border-top: 1px solid var(--border-subtle);
}
.task-view-section-header h3 {
    font-size: 0.7rem;
    letter-spacing: 0.10em;
    color: var(--text-muted);
    font-weight: 700;
}
.task-view-section-header { padding-bottom: 10px; }
.task-view-section-content { gap: 10px; display: flex; flex-direction: column; }
.task-view-control label {
    font-size: 0.66rem;
    letter-spacing: 0.08em;
}

/* =====================================================================
   MODALS — premium feel
   ===================================================================== */
.modal { backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
.modal-content {
    border-radius: 12px;
    box-shadow: var(--polish-elevated-shadow);
    border: 1px solid var(--border-subtle);
}
body.dark-theme .modal-content {
    border-color: var(--border-strong);
}
.modal-content h2 {
    font-size: 1.15rem;
    font-weight: 700;
    text-transform: none;
    letter-spacing: -0.01em;
    color: var(--text-primary);
}
.close-modal {
    width: 32px;
    height: 32px;
    border-radius: 8px;
    background: transparent;
    color: var(--text-muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s ease, color 0.15s ease;
}
.close-modal:hover {
    background: var(--hover-bg);
    color: var(--text-primary);
}

/* =====================================================================
   SUBTLE GLOBAL POLISH
   ===================================================================== */

/* View transitions — quick fade */
.main-content { animation: viewFade 0.18s ease-out; }
@keyframes viewFade {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* Buttons — primary depth + press feedback */
.glass-btn.primary,
.glass-btn-primary {
    box-shadow: 0 1px 2px rgba(9, 28, 58, 0.10);
}
.glass-btn.primary:hover,
.glass-btn-primary:hover {
    box-shadow: 0 2px 6px rgba(9, 28, 58, 0.18);
}
.glass-btn:active,
.glass-btn-sm:active { transform: translateY(1px); }

/* Form inputs — focus ring */
.glass-input:focus,
.glass-select:focus,
.custom-select-trigger:focus,
.custom-select-trigger.is-open {
    border-color: var(--accent-cyan);
    box-shadow: 0 0 0 3px var(--accent-glow);
    outline: none;
}

/* Loading overlay — clean spinner with cyan top arc */
.loading-spinner {
    border: 2px solid var(--border-subtle);
    border-top-color: var(--accent-cyan);
}

/* Notifications & bulk bar — proper elevation */
.notification-toast { box-shadow: var(--polish-elevated-shadow); }
.bulk-bar { box-shadow: var(--polish-elevated-shadow); }

/* =====================================================================
   28c. Restrained brand-correct refinements.
   Brand: 1px subtle borders, 4–8px radii, sharp/slightly-rounded buttons,
   plenty of whitespace, snappy professional motion. NO decorative chrome.
   ===================================================================== */

/* Project title — slightly larger but stays in brand scale */
.project-info h1 {
    font-size: clamp(1.2rem, 1.2vw + 0.7rem, 1.65rem);
    font-weight: 700;
    letter-spacing: -0.015em;
    line-height: 1.2;
}

/* More breathing room in the board */
@media (min-width: 1024px) {
    .board-container { padding: 22px 28px 60px; }
    .swimlane { margin-bottom: 18px; }
    .swimlane-content { padding: 16px; }
}

/* Sidebar nav: refined size, calm hover/active */
.nav-section ul li {
    padding: 8px 10px;
    border-radius: 6px;
    border-left: 2px solid transparent;
    color: var(--text-secondary);
    font-size: 0.86rem;
}
.nav-section ul li:hover {
    background: var(--hover-bg);
    color: var(--text-primary);
}
.nav-section ul li.active {
    background: var(--active-bg);
    color: var(--accent-cyan);
    border-left-color: var(--accent-cyan);
    padding-left: 10px;
    font-weight: 600;
}

/* Project list — quiet ID dot, no left bar */
#project-list li {
    position: relative;
    padding-left: 22px;
}
#project-list li::before {
    content: '';
    position: absolute;
    left: 8px;
    top: 50%;
    transform: translateY(-50%);
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--project-color, var(--text-muted));
}

/* Empty column — text-only hint, brand-correct.
   Text comes from the --i18n-no-tasks CSS var (set in JS from t('js.no_tasks_column')) */
.column .task-list:empty::after {
    content: var(--i18n-no-tasks, 'No tasks');
    display: block;
    text-align: center;
    color: var(--text-muted);
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 18px 0 10px;
    opacity: 0.55;
}

/* =====================================================================
   Project header — proper hero (replaces inline-style cruft)
   ===================================================================== */
.project-info {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    flex: 1;
    min-width: 0;
}
.project-title-row {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    width: 100%;
}
.project-title-row h1 {
    margin: 0;
    min-width: 0;
    word-break: break-word;
    overflow-wrap: anywhere;
}
.status-badge { display: inline-flex; align-items: center; }
.status-badge:empty { display: none; }

/* Budget badge — shows project est vs act totals in the meta row.
   Hidden when the project has no budget rows. */
.budget-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.72rem;
    color: var(--text-secondary);
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    padding: 3px 10px;
}
.budget-badge:empty { display: none; }
.budget-badge-label {
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 700;
    color: var(--text-muted);
    font-size: 0.65rem;
}
.budget-badge-est { color: var(--accent-cyan); font-weight: 600; font-variant-numeric: tabular-nums; }
.budget-badge-act { color: var(--text-primary);  font-weight: 600; font-variant-numeric: tabular-nums; }
.budget-badge-upd { color: var(--warning); font-weight: 600; font-variant-numeric: tabular-nums; }
.budget-badge-sep { color: var(--text-muted); }
.budget-badge-target {
    color: var(--text-primary);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
/* Colour cue when an estimated/updated/actual value breaches the budget target */
.budget-badge-est.is-over { color: var(--warning); }
.budget-badge-upd.is-over { color: var(--danger);  }
.budget-badge-act.is-over { color: var(--danger);  }

/* =====================================================================
   FINANCIALS VIEW
   ===================================================================== */
.fin-container {
    padding: 22px 24px 80px;
    height: 100%;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 22px;
}
.fin-empty {
    padding: 60px 20px;
    text-align: center;
    color: var(--text-muted);
    font-size: 0.9rem;
}

/* Stat card grid — auto-fits as many cards as can comfortably fit at the
   container width. 5 cards (Budget · Est · Updated · Act · Remaining) fit
   on one row at md+; gracefully collapses to fewer cols on narrower screens. */
.fin-stat-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 10px;
}
@media (min-width: 520px) {
    .fin-stat-grid { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
}
.fin-stat-card {
    background: var(--bg-main);
    border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--accent-cyan);
    border-radius: var(--radius-md);
    padding: 10px 12px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    box-shadow: 0 1px 2px rgba(9, 28, 58, 0.03);
    min-width: 0;
}
body.dark-theme .fin-stat-card { background: var(--bg-secondary); }
.fin-stat-card.is-over {
    border-left-color: var(--danger);
}
.fin-stat-card-budget {
    border-left-color: var(--accent);
}
.fin-stat-label {
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 0.62rem;
    color: var(--text-muted);
    font-weight: 700;
}
.fin-stat-value {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 1.05rem;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
    display: flex;
    align-items: baseline;
    gap: 4px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.fin-stat-card.is-over .fin-stat-value { color: var(--danger); }
.fin-stat-muted { color: var(--text-muted); font-weight: 500; }
.fin-stat-card-empty .fin-stat-value { font-size: 0.85rem; color: var(--text-muted); }

/* Editable Budget input — inherits .glass-input, overridden to look stat-cardy */
.fin-budget-input {
    background: transparent !important;
    border: none !important;
    padding: 0 !important;
    font-family: inherit !important;
    font-weight: 700 !important;
    font-size: 1.05rem !important;
    color: inherit !important;
    height: auto !important;
    width: 100% !important;
    min-width: 0 !important;
    font-variant-numeric: tabular-nums !important;
}
.fin-budget-input:focus {
    outline: 2px solid var(--accent-cyan);
    outline-offset: 2px;
    border-radius: 4px;
}
.fin-budget-currency {
    font-weight: 500;
    color: var(--text-muted);
    font-size: 0.85rem;
}

/* Budget consumption bar */
.fin-bar-wrap {
    background: var(--bg-main);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
body.dark-theme .fin-bar-wrap { background: var(--bg-secondary); }
.fin-bar-row {
    display: grid;
    grid-template-columns: 140px 1fr;
    align-items: center;
    gap: 14px;
}
.fin-bar-label {
    font-size: 0.78rem;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}
.fin-bar {
    height: 10px;
    background: var(--subtle-bg);
    border-radius: 999px;
    overflow: hidden;
    position: relative;
}
.fin-bar-fill {
    height: 100%;
    border-radius: 999px;
    transition: width 0.3s ease;
}
.fin-bar-fill-est { background: var(--accent-cyan); }
.fin-bar-fill-upd { background: var(--warning); }
.fin-bar-fill-act { background: var(--accent); }
.fin-bar-fill.is-over { background: var(--danger); }

/* Section / table styling — mirrors .budget-table but slightly denser */
.fin-section {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.fin-section-title {
    text-transform: uppercase;
    letter-spacing: 0.1em;
    font-size: 0.75rem;
    color: var(--text-muted);
    font-weight: 700;
    margin: 4px 0 0;
}
.fin-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 0.84rem;
    background: var(--bg-main);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    overflow: hidden;
}
body.dark-theme .fin-table { background: var(--bg-secondary); }
.fin-table thead th {
    background: var(--subtle-bg);
    text-align: left;
    padding: 8px 12px;
    font-weight: 600;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary);
    border-bottom: 1px solid var(--border-subtle);
    white-space: nowrap;
}
body.dark-theme .fin-table thead th { background: var(--bg-elevated); }
.fin-table tbody td {
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-subtle);
    vertical-align: middle;
}
.fin-table tbody tr:last-child td { border-bottom: none; }
.fin-table-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}
.fin-table-num.is-over  { color: var(--danger);  font-weight: 600; }
.fin-table-num.is-under { color: var(--success); font-weight: 600; }
.fin-table-row-link { cursor: pointer; transition: background 0.12s ease; }
.fin-table-row-link:hover { background: var(--hover-bg); }
.fin-table-empty {
    text-align: center;
    color: var(--text-muted);
    padding: 18px !important;
    font-style: italic;
}
/* Subtasks own budget lines too, so they get their own rows in the breakdowns.
   The parent title is prefixed muted so a subtask reads as nested rather than
   as another top-level task with a similar name. */
.fin-subtask-parent { color: var(--text-muted); font-weight: 500; }

/* Status colour dots reuse the same palette as the kanban column headers */
.fin-status-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-right: 8px;
    vertical-align: middle;
    background: var(--text-muted);
}
.fin-status-dot.fin-status-backlog { background: var(--text-muted); }
.fin-status-dot.fin-status-doing   { background: var(--warning); }
.fin-status-dot.fin-status-done    { background: var(--success); }

.fin-hint {
    font-size: 0.78rem;
    color: var(--text-muted);
    margin: 4px 0 0;
}

.ov-project-budget {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-variant-numeric: tabular-nums;
}
.ov-project-budget-est { color: var(--accent-cyan); font-weight: 600; }
.ov-project-budget-act { color: var(--text-primary);  font-weight: 600; }

/* Budget table inside the task view — Excel-like editable grid. */
.budget-table-wrap {
    overflow-x: auto;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    background: var(--bg-main);
}
body.dark-theme .budget-table-wrap { background: var(--bg-secondary); }
.budget-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 0.82rem;
    font-variant-numeric: tabular-nums;
}
.budget-table thead th {
    background: var(--subtle-bg);
    color: var(--text-secondary);
    font-weight: 600;
    text-align: left;
    padding: 6px 10px;
    border-bottom: 1px solid var(--border-subtle);
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    white-space: nowrap;
}
body.dark-theme .budget-table thead th { background: var(--bg-elevated); }
.budget-table thead tr:first-child th { border-bottom: 1px solid var(--border-subtle); }
.budget-table tbody td {
    padding: 4px 6px;
    border-bottom: 1px solid var(--border-subtle);
    vertical-align: middle;
}
.budget-table tbody tr:last-child td { border-bottom: none; }
.budget-cell {
    height: 30px !important;
    padding: 4px 8px !important;
    font-size: 0.85rem !important;
    border-radius: var(--radius-sm) !important;
}
.budget-cell-name { min-width: 140px; }
.budget-cell-unit { min-width: 70px; width: 70px; }
.budget-cell-num  { width: 100px; text-align: right !important; }
.budget-cell-total {
    text-align: right;
    font-weight: 600;
    color: var(--text-primary);
    padding: 4px 12px !important;
    min-width: 90px;
}
.budget-col-actions { width: 36px; text-align: center; }
.budget-totals-row td {
    background: var(--subtle-bg);
    font-weight: 700;
    border-top: 2px solid var(--border-strong);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: 0.72rem;
    color: var(--text-primary);
    padding: 8px 12px !important;
}
body.dark-theme .budget-totals-row td { background: var(--bg-elevated); }
.budget-totals-row .budget-cell-total {
    font-size: 0.95rem;
    color: var(--accent-cyan);
}
.budget-totals-row .budget-cell-total#modal-budget-grand-act { color: var(--text-primary); }
.budget-add-row-btn {
    margin-top: 10px;
    width: fit-content;
}

/* Rows the current user can read but not modify (non-admin/PM viewing
   existing budget lines). Inputs are disabled at the DOM level; the row
   gets a subtler background and a faint left tick to signal "locked". */
.budget-row.is-locked .budget-cell {
    background: var(--subtle-bg) !important;
    color: var(--text-secondary) !important;
    cursor: not-allowed;
}
body.dark-theme .budget-row.is-locked .budget-cell {
    background: var(--bg-elevated) !important;
}
.project-meta-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    min-height: 22px;
}
.project-meta-row:empty { display: none; }

/* Info button — small circular icon, brand-aligned (no inline cruft) */
.info-btn {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 1px solid var(--border-strong);
    background: transparent;
    color: var(--text-muted);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-style: italic;
    font-size: 0.75rem;
    line-height: 1;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.info-btn:hover {
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
    background: var(--active-bg);
}

/* Owner badge — calm metadata */
.owner-badge {
    font-size: 0.72rem;
    color: var(--text-muted);
    letter-spacing: 0;
    line-height: 1.2;
}
.owner-badge:empty { display: none; }

/* =====================================================================
   Swimlane header — clean structure (replaces inline-style cruft)
   ===================================================================== */
.swimlane-header-text {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex: 1;
    min-width: 0;
}
.swimlane-name {
    font-weight: 700;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.swimlane-count {
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--text-muted);
    background: var(--subtle-bg);
    padding: 2px 8px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border-subtle);
    flex-shrink: 0;
    text-transform: none;
    letter-spacing: 0;
    font-family: 'Inter', sans-serif;
}
body.dark-theme .swimlane-count {
    background: var(--bg-elevated);
    border-color: var(--border-strong);
}
.swimlane-due {
    font-size: 0.72rem;
    color: var(--text-muted);
    text-transform: none;
    letter-spacing: 0;
    font-weight: 500;
    font-family: 'Inter', sans-serif;
}
/* The lane's responsible person — rendered in the board swimlane header and in
   the list view's swimlane row. Deliberately quieter than the lane name and
   distinct from a task's assignee avatar: this is accountability for the whole
   lane, not ownership of any one task. Absent entirely when nobody is set. */
.swimlane-owner {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
    max-width: 200px;
    font-size: 0.72rem;
    font-weight: 500;
    font-family: 'Inter', sans-serif;
    text-transform: none;
    letter-spacing: 0;
    color: var(--text-secondary);
}
.swimlane-owner-icon { opacity: 0.55; }
.swimlane-owner-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.swimlane-header-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}
.swimlane-edit-btn {
    width: 26px;
    height: 26px;
    border: 1px solid var(--border-subtle);
    background: transparent;
    color: var(--text-muted);
    border-radius: var(--radius-sm);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.78rem;
    transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.swimlane-edit-btn:hover {
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
    background: var(--active-bg);
}
.swimlane-toggle {
    color: var(--text-muted);
    font-size: 0.7rem;
    user-select: none;
}

/* =====================================================================
   Column header — count chip, clean + button (replaces inline opacity:0.5)
   ===================================================================== */
.column-header-title {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.column-header-count {
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--text-muted);
    background: var(--subtle-bg);
    padding: 1px 7px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border-subtle);
    line-height: 1.4;
    font-family: 'Inter', sans-serif;
    text-transform: none;
    letter-spacing: 0;
    min-width: 22px;
    text-align: center;
}
body.dark-theme .column-header-count {
    background: var(--bg-elevated);
    border-color: var(--border-strong);
}
.column-add-btn {
    width: 22px;
    height: 22px;
    border: 1px solid var(--border-subtle);
    background: transparent;
    color: var(--text-muted);
    border-radius: var(--radius-sm);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.95rem;
    line-height: 1;
    opacity: 0;
    transition: opacity 0.15s ease, border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.column:hover .column-add-btn { opacity: 1; }
.column-add-btn:hover {
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
    background: var(--active-bg);
}

/* Reduced motion — honour the user preference */
@media (prefers-reduced-motion: reduce) {
    .task-card,
    .main-content { animation: none !important; transition: none !important; }
}

/* =====================================================================
   28b. Cross-view polish — classes that replace inline-style cruft
        produced by the JS controllers. Grouped by surface for clarity.
   ===================================================================== */

/* === Shared atoms === */
.empty-state-text {
    padding: 40px;
    text-align: center;
    color: var(--text-secondary);
    font-size: 0.9rem;
}
.form-hint {
    color: var(--text-muted);
    font-weight: 400;
}

/* Repeat section — already-scheduled occurrences table + delete control. */
.repeat-schedule-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 6px;
}
.repeat-occurrences-scroll {
    max-height: 190px;
    overflow-y: auto;
    border: 1px solid var(--border-color);
    border-radius: 6px;
}
.repeat-occurrences-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.8rem;
}
.repeat-occurrences-table thead th {
    position: sticky;
    top: 0;
    background: var(--bg-secondary, var(--card-bg));
    text-align: left;
    font-weight: 600;
    color: var(--text-muted);
    padding: 6px 8px;
    border-bottom: 1px solid var(--border-color);
}
.repeat-occurrences-table td {
    padding: 6px 8px;
    border-bottom: 1px solid var(--border-color);
    vertical-align: top;
}
.repeat-occurrences-table tbody tr:last-child td { border-bottom: none; }
.repeat-occ-due { white-space: nowrap; }
.repeat-occ-empty { text-align: center; color: var(--text-muted); padding: 10px; }
.repeat-occ-current { color: var(--text-muted); font-style: italic; }
.repeat-occ-status {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 0.72rem;
    border: 1px solid var(--border-color);
    color: var(--text-muted);
}
.repeat-occ-status.is-done {
    border-color: var(--success);
    color: var(--success);
}
.micro-label {
    display: block;
    font-size: 0.65rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 2px;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.btn-danger-text { color: var(--danger); }
.btn-danger {
    color: var(--danger);
    border-color: var(--danger);
}
.btn-danger:hover { background: var(--danger-soft); }
.btn-push-right { margin-left: auto; }

.tag-uppercase { text-transform: uppercase; }
.tag-status-inline {
    font-size: 0.6rem;
    vertical-align: middle;
    margin-left: 8px;
    text-transform: uppercase;
}
.tag-status-sidebar {
    font-size: 0.6rem;
    transform: scale(0.85);
    transform-origin: right center;
}

.avatar-sm {
    width: 20px;
    height: 20px;
    font-size: 10px;
}

.quick-add-input { width: 100%; }
.quick-add-task-spaced { margin-top: 10px; }

.column-add-btn { opacity: 0.55; }
.column-add-btn:hover { opacity: 1; }

/* === Team view polish === */
.team-details-subtitle {
    color: var(--text-muted);
    margin-top: 6px;
    font-size: 0.9rem;
}
.member-email { color: var(--text-secondary); }
.project-list-name { font-weight: 600; }
.project-list-empty {
    justify-content: center;
    color: var(--text-muted);
    font-style: italic;
}

/* === Calendar view polish === */
.calendar-month-label {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    min-width: 160px;
    text-align: center;
    display: inline-block;
    text-transform: uppercase;
    letter-spacing: -0.01em;
}
.calendar-day-pad {
    background: transparent;
    border-color: transparent;
    pointer-events: none;
}
.legend-dot {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.75rem;
    margin-right: 12px;
}
.legend-dot-task    { color: var(--success); }
.legend-dot-ticket  { color: var(--danger); }
.legend-dot-meeting { color: var(--accent-violet, #7c3aed); }
.legend-dot-created { color: var(--warning); }
.legend-dot-started { color: var(--accent-cyan); }
.legend-dot-done    { color: var(--success); }

/* === Timeline view polish === */
.timeline-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
    margin-bottom: 16px;
}
.timeline-controls-spacer { flex: 1; }
.timeline-chart-area {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
.timeline-label-project {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    color: var(--project-color, var(--accent-cyan));
    cursor: pointer;
}
.timeline-toggle-icon {
    margin-right: 8px;
    display: inline-block;
    transition: transform var(--motion-fast);
}
.timeline-toggle-icon.is-collapsed { transform: rotate(-90deg); }
.timeline-label-swimlane { padding-left: 30px; }
.timeline-label-task {
    padding-left: 55px;
    font-size: 0.8rem;
    color: var(--text-secondary);
}
/* Subtask label — deeper indent + muted/italic so the parent/child
   relationship reads at a glance, matching the dashed bar style. */
.timeline-label-subtask {
    padding-left: 75px;
    font-size: 0.75rem;
    color: var(--text-muted);
    font-style: italic;
}
/* ⏱ tracked/estimated badge appended to the Gantt sidebar label. Subdued
   so the task title still reads first, but visible enough to scan. */
.timeline-label-time {
    margin-left: 10px;
    padding: 1px 6px;
    font-size: 0.7rem;
    color: var(--text-muted);
    background: var(--subtle-bg);
    border-radius: var(--radius-sm);
    white-space: nowrap;
}
/* Deadline pill inside the Gantt sidebar label needs explicit spacing since
   the label lays out its parts inline (no flex gap). */
.timeline-label .task-deadline { margin-left: 8px; }
/* Inline chapter badge inside timeline labels and bars. Monospace keeps
   dotted numbers aligned across rows; small accent color picks it out
   without competing with the task title. */
.timeline-chapter {
    font-family: 'JetBrains Mono', ui-monospace, Menlo, monospace;
    font-weight: 700;
    color: var(--accent-cyan);
    margin-right: 2px;
}
.timeline-count {
    color: var(--text-muted);
    font-size: 0.75rem;
}

/* === List view polish === */
.list-swimlane-count { color: var(--text-muted); }
.list-swimlane-due {
    color: var(--text-muted);
    margin-left: 10px;
}
.list-swimlane-actions {
    display: flex;
    align-items: center;
    gap: 8px;
}
.list-swimlane-edit-btn { /* default look fine */ }
.list-swimlane-toggle { color: var(--text-secondary); }

.task-row-title { flex: 1; font-weight: 600; }
.task-row-assignee {
    width: 120px;
    font-size: 0.8rem;
    color: var(--text-secondary);
}
.task-row-priority { width: 80px; }
.task-row-checklist {
    width: 60px;
    font-size: 0.8rem;
    color: var(--text-secondary);
}
.task-row-time {
    width: 130px;
    font-size: 0.8rem;
    color: var(--text-secondary);
    white-space: nowrap;
}
.task-row-subtask-prefix { color: var(--text-muted); }

/* --- Stopwatch / live time tracking --- */
.task-time-cell { display: inline-flex; align-items: center; gap: 6px; }
.task-timer-btn {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 1px 6px; line-height: 1.4;
    font-size: 0.72rem; font-weight: 600;
    border: 1px solid var(--border-subtle);
    border-radius: 6px; background: transparent; color: var(--text-secondary);
    cursor: pointer; white-space: nowrap;
}
.task-timer-btn:hover { border-color: var(--accent); color: var(--accent); }
.task-timer-btn.running {
    border-color: var(--danger); color: var(--danger);
    background: color-mix(in srgb, var(--danger) 12%, transparent);
}
#modal-timer-btn.running { border-color: var(--danger); color: var(--danger); }

/* Budget rollup chip on board cards — estimated / actual for tasks and
   subtasks that carry budget lines. Tabular figures so the numbers line up
   down a column of cards; the actual turns red once it passes the estimate.
   An em dash stands in for an actual that hasn't been logged yet. */
.task-budget-cell {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    color: var(--text-secondary);
}
.task-budget-icon { opacity: 0.55; }
.task-budget-sep { opacity: 0.45; }
.task-budget-act { font-weight: 600; color: var(--text-primary); }
.task-budget-cell.is-over .task-budget-act { color: var(--danger); }

/* Editable time-entry history rows in the task modal */
.time-entry-row {
    display: grid;
    grid-template-columns: 1fr 64px auto auto auto;
    align-items: center; gap: 6px;
    padding: 2px 0;
}
.time-entry-user { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.time-entry-hours { padding: 2px 6px; font-size: 0.8rem; text-align: right; }
.time-entry-hours-unit { color: var(--text-muted); }
.time-entry-date { color: var(--text-muted); white-space: nowrap; }
.time-entry-del {
    border: none; background: transparent; cursor: pointer;
    color: var(--text-muted); font-size: 1rem; line-height: 1; padding: 0 4px;
}
.time-entry-del:hover { color: var(--danger); }
.time-entry-hours.field-invalid { border-color: var(--danger); outline: 1px solid var(--danger); }

.list-status-header {
    display: flex;
    align-items: center;
}

/* === Document view polish === */
/* (most rules already exist as .doc-*; this adds the empty state) */

/* === Analytics view polish === */
.analytics-loading {
    grid-column: span 2;
    text-align: center;
    padding: 40px;
    color: var(--text-secondary);
}
.cfd-legend {
    font-size: 0.8rem;
    color: var(--text-muted);
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}
.chart-body-block { display: block; }
.rec-text-flow { margin-top: 16px; }
.rec-box-muted {
    border-color: var(--border-subtle);
    background: var(--subtle-bg);
    padding: 12px;
    margin-bottom: 16px;
}

.bn-segment-wait { background: var(--warning); color: #fff; }
.bn-segment-work { background: var(--success); color: #fff; }

/* Bottleneck Analysis — card styled to match the dashboard widget sections
   (px-widget-*). Theme-aware via projex CSS vars. */
.px-bn-card {
    background: var(--bg-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    padding: 16px;
    box-shadow: var(--card-shadow);
}
body.dark-theme .px-bn-card { background: var(--subtle-bg); }
.px-bn-verdict {
    font-size: 0.9rem;
    line-height: 1.5;
    padding: 12px 14px;
    border-radius: var(--radius-md);
    border-left: 3px solid var(--border-strong);
    background: var(--subtle-bg);
    color: var(--text-primary);
    margin-bottom: 14px;
}
body.dark-theme .px-bn-verdict { background: var(--bg-elevated); }
.px-bn-verdict.bn-warn { border-left-color: var(--warning); }
.px-bn-verdict.bn-ok   { border-left-color: var(--success); }
.px-bn-signals {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 12px;
}
.px-bn-tile {
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    padding: 12px 14px;
}
body.dark-theme .px-bn-tile { background: var(--bg-elevated); }
.px-bn-tile-title {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 0.72rem;
    color: var(--text-secondary);
    margin-bottom: 8px;
    display: flex;
    align-items: center;
    gap: 6px;
}
.px-bn-tile-body { font-size: 0.86rem; color: var(--text-primary); line-height: 1.5; }
.px-bn-tile-note { margin-top: 6px; font-size: 0.8rem; color: var(--text-secondary); }
.px-bn-muted { color: var(--text-muted); }

/* Secondary line under a rec-box headline (schedule note, coverage caveat). */
.rec-subtext {
    margin-top: 6px;
    font-size: 0.85rem;
    color: var(--text-secondary);
}
/* Verdict line — color-codes the prioritized finding. */
.rec-text-flow.bn-warn {
    color: var(--warning);
    border-left: 3px solid var(--warning);
    padding-left: 12px;
}
.rec-text-flow.bn-ok {
    color: var(--success);
    border-left: 3px solid var(--success);
    padding-left: 12px;
}

.perf-group-heading {
    margin: 20px 0 10px;
    color: var(--accent);
    border-bottom: 1px solid var(--border-subtle);
    padding-bottom: 6px;
    text-transform: uppercase;
    font-size: 0.85rem;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.perf-card-name { font-weight: 700; }

.time-analysis-stack {
    display: flex;
    flex-direction: column;
    gap: 30px;
}
.time-analysis-group-heading {
    text-transform: capitalize;
    color: var(--accent);
    border-bottom: 1px solid var(--border-subtle);
    padding-bottom: 6px;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.time-card-header-meta {
    display: flex;
    align-items: center;
    gap: 10px;
}
.time-card-total { font-weight: 700; }
.time-card-subhead {
    margin-bottom: 10px;
    color: var(--text-secondary);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.dev-time-stack {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.time-row {
    display: flex;
    justify-content: space-between;
}
.time-row-bordered {
    padding: 2px 0;
    border-bottom: 1px solid var(--border-subtle);
}
.time-row-label { color: var(--accent); }
.dev-time-card-meta {
    display: flex;
    align-items: center;
    gap: 10px;
}
.dev-time-section-label {
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--accent);
    margin-bottom: 6px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.dev-time-empty {
    color: var(--text-muted);
    font-size: 0.8rem;
    font-style: italic;
}
.task-time-swimlane {
    color: var(--accent);
    margin-left: 6px;
}

/* === Forecast modal polish === */
.forecast-loading {
    text-align: center;
    padding: 24px;
    color: var(--text-secondary);
}
.forecast-section-heading {
    margin-bottom: 10px;
    border-bottom: 1px solid var(--border-subtle);
    padding-bottom: 6px;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.forecast-section-heading-spaced { margin-top: 30px; }
.forecast-cell-p50 { color: var(--warning); }
.forecast-cell-p85 { color: var(--accent-cyan); }
.forecast-cell-p95 { color: var(--success); }

/* === Overview view polish === */
.ov-content { padding: 20px; }
.ov-pbar {
    display: flex;
    align-items: center;
    gap: 8px;
}
.ov-pbar-track {
    flex: 1;
    height: 6px;
    background: var(--active-bg);
    border-radius: 3px;
    overflow: hidden;
    /* `overflow: hidden` makes this a scroll container, so the global
       `scrollbar-gutter: stable` reserves a ~10px gutter on the right and
       shrinks the content box — the fill's width:100% then stops short of the
       track end (a 100% bar looks unfinished). We only clip the fill's rounded
       corners here, never scroll, so opt out of the reserved gutter. */
    scrollbar-gutter: auto;
}
.ov-pbar-fill {
    height: 100%;
    border-radius: 3px;
    transition: width 0.3s var(--motion-base);
}
.ov-pbar-label {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--text-primary);
    min-width: 28px;
}

.ov-resolved-badge { margin-left: 6px; }
.ov-subtask-prefix { color: var(--text-muted); }
.ov-caret {
    cursor: pointer;
    user-select: none;
    font-size: 0.7rem;
    color: var(--text-secondary);
}
.ov-caret-light { color: #fff; }
.ov-caret-spacer {
    width: 0.7rem;
    display: inline-block;
}

/* Task table sits inside the project body, staggered to the right of the
   project header so the hierarchy reads at a glance. */
.ov-project-body {
    padding-left: 28px;
    border-top: 1px solid var(--border-subtle);
}

.ov-task-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--border-subtle);
}
.ov-task-row-subtask { padding-left: 44px; }
.ov-task-title {
    flex: 3;
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 6px;
}
.ov-task-title-sub { font-weight: 400; }
/* The title text links to the task's detail view (same target as the ✎ action).
   The caret and action buttons stopPropagation, so only the title opens it. */
.ov-task-title-link { cursor: pointer; }
.ov-task-title-link:hover { color: var(--accent-cyan); text-decoration: underline; }
.ov-task-assignee {
    flex: 1;
    font-size: 0.8rem;
    color: var(--text-secondary);
}
.ov-task-planned,
.ov-task-realized {
    flex: 1.2;
    font-size: 0.75rem;
    color: var(--text-secondary);
}
.ov-task-progress { flex: 1; }
.ov-task-actions {
    flex: 0.5;
    display: flex;
    gap: 6px;
    justify-content: flex-end;
    align-items: center;
}

.ov-desc-toggle {
    padding: 4px 12px 6px;
    font-size: 0.75rem;
    color: var(--text-secondary);
    border-bottom: 1px solid var(--border-subtle);
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 4px;
}
.ov-desc-toggle:hover { background: var(--hover-bg); }
.ov-desc-toggle-sub { padding-left: 44px; }
.ov-desc-body {
    padding: 6px 12px 8px;
    font-size: 0.8rem;
    color: var(--text-secondary);
    background: var(--subtle-bg);
    border-bottom: 1px solid var(--border-subtle);
}
.ov-desc-body-sub { padding-left: 36px; }

/* Project cards — primary visual unit on the overview, so they read a touch
   bolder than a generic card without becoming a section header. */
.ov-project-card {
    background: var(--bg-main);
    border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--accent-cyan);
    border-radius: var(--radius-lg);
    margin: 14px 0;
    overflow: hidden;
    box-shadow: 0 1px 2px rgba(9, 28, 58, 0.04), 0 4px 14px rgba(9, 28, 58, 0.05);
    transition: box-shadow 0.18s ease, transform 0.15s ease;
}
.ov-project-card:hover {
    box-shadow: 0 2px 4px rgba(9, 28, 58, 0.06), 0 10px 26px rgba(9, 28, 58, 0.07);
    transform: translateY(-1px);
}
body.dark-theme .ov-project-card {
    background: var(--bg-secondary);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
body.dark-theme .ov-project-card:hover {
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
}
.ov-project-head {
    padding: 12px 16px;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 18px;
    background: var(--bg-main);
}
body.dark-theme .ov-project-head { background: var(--bg-secondary); }
.ov-project-head-main { flex: 1; min-width: 0; }
.ov-project-title-row {
    display: flex;
    align-items: baseline;
    gap: 10px;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 1.18rem;
    line-height: 1.25;
    letter-spacing: -0.01em;
    min-width: 0;
}
.ov-project-link {
    color: var(--text-primary);
    text-decoration: none;
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: anywhere;
    word-break: break-word;
    transition: color 0.15s ease;
}
.ov-project-link:hover {
    color: var(--accent-cyan);
    text-decoration: none;
}
.ov-project-status-row {
    margin-top: 4px;
}
.ov-desc-trigger {
    display: flex;
    gap: 6px;
    margin-top: 4px;
    align-items: baseline;
    cursor: pointer;
    color: var(--text-secondary);
    font-size: 0.8rem;
    user-select: none;
    padding: 2px 0;
    transition: color 0.15s ease;
}
.ov-desc-trigger::before {
    content: '▸';
    font-size: 0.65rem;
    color: var(--text-muted);
    transition: transform 0.15s ease;
}
.ov-desc-trigger:hover { color: var(--accent-cyan); }
.ov-desc-trigger:hover::before { color: var(--accent-cyan); }
.ov-desc-trigger-label {
    font-weight: 600;
    color: var(--text-primary);
}
.ov-project-desc {
    font-size: 0.82rem;
    color: var(--text-secondary);
    margin-top: 4px;
    margin-bottom: 2px;
    padding: 6px 10px;
    background: var(--subtle-bg);
    border-left: 2px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    line-height: 1.45;
}
body.dark-theme .ov-project-desc {
    background: var(--bg-elevated);
}

/* Objective trigger — same structure as description, with the statement
   shown inline next to the label so the user can read it without expanding. */
.ov-objective-trigger {
    align-items: baseline;
    flex-wrap: wrap;
}
.ov-objective-statement {
    color: var(--text-secondary);
    font-weight: 500;
    margin-left: 2px;
    flex: 1 1 auto;
    min-width: 0;
}
.ov-objective-body { font-size: 0.8rem; }
.ov-objective-body .ov-smart-row,
.ov-objective-body > div { margin-bottom: 4px; }
.ov-objective-body strong {
    display: inline-block;
    width: 14px;
    color: var(--accent-cyan);
    font-weight: 700;
}

.ov-project-meta-row {
    display: flex;
    gap: 14px;
    margin-top: 6px;
    align-items: center;
    flex-wrap: wrap;
    font-size: 0.76rem;
    color: var(--text-secondary);
}
.ov-project-meta { color: var(--text-secondary); }
.ov-project-meta-label {
    color: var(--text-muted);
    margin-right: 4px;
    font-weight: 500;
}
.ov-project-head-aside {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 8px;
    min-width: 180px;
    flex-shrink: 0;
}
.ov-project-pbar { width: 160px; }

/* Filter / sort bar at the top of the overview */
.ov-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    align-items: flex-end;
    padding-top: 12px;
}
.ov-control {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 160px;
}
.ov-control-search { flex: 1 1 220px; }
.ov-control-range  { flex: 1 1 240px; }
.ov-control-reset  { flex: 0 0 auto; min-width: 0; }
.ov-control label {
    font-size: 0.66rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    font-weight: 600;
}
.ov-sort-row,
.ov-range-row {
    display: flex;
    gap: 6px;
    align-items: center;
}
.ov-sort-row .glass-select { flex: 1; }
.ov-sort-dir-btn {
    width: 36px;
    flex-shrink: 0;
    font-size: 1rem;
    line-height: 1;
}
.ov-range-row .glass-input {
    flex: 1;
    min-width: 0;
    font-size: 0.85rem;
}
.ov-range-sep {
    color: var(--text-muted);
    font-size: 0.75rem;
}

/* Multi-select + group chip — the project-level twin of the board's task
   groups: tick cards, set one group for the lot, filter by it above. */
.ov-select-box {
    width: 15px;
    height: 15px;
    margin: 0;
    flex: 0 0 auto;
    accent-color: var(--accent-cyan);
    cursor: pointer;
    align-self: center;
}
.ov-project-card-selected {
    border-color: var(--accent-cyan);
    box-shadow: 0 0 0 1px var(--accent-cyan) inset, 0 4px 14px rgba(9, 28, 58, 0.06);
}
.ov-project-group {
    display: inline-block;
    margin-left: 8px;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 600;
    line-height: 1.5;
    vertical-align: middle;
    color: var(--ov-group-color, var(--text-secondary));
    border: 1px solid var(--ov-group-color, var(--border-subtle));
    /* Tint from the same colour so the chip reads as a label, not a button. */
    background: color-mix(in srgb, var(--ov-group-color, transparent) 12%, transparent);
}

/* Bulk action bar — only present while something is selected. */
.ov-bulk-bar {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin: 0 20px;
    padding: 10px 14px;
    border: 1px solid var(--accent-cyan);
    border-radius: var(--radius-lg);
    background: color-mix(in srgb, var(--accent-cyan) 8%, var(--bg-main));
}
body.dark-theme .ov-bulk-bar {
    background: color-mix(in srgb, var(--accent-cyan) 14%, var(--bg-secondary));
}
.ov-bulk-bar.hidden { display: none; }
.ov-bulk-count {
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-secondary);
}
.ov-bulk-bar .glass-select { min-width: 200px; }

/* Result counter above the list */
.ov-project-count {
    font-size: 0.75rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 600;
    margin: 4px 4px 10px;
}

/* Action buttons in the task rows — aligned with the swimlane/column
   icon-button pattern used elsewhere in Projex. */
.ov-action-btn {
    width: 26px;
    height: 26px;
    border: 1px solid var(--border-subtle);
    background: transparent;
    color: var(--text-muted);
    border-radius: var(--radius-sm);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.85rem;
    line-height: 1;
    transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
    padding: 0;
}
.ov-action-btn:hover {
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
    background: var(--active-bg);
}
.ov-action-btn-danger:hover {
    border-color: var(--danger);
    color: var(--danger);
    background: rgba(220, 38, 38, 0.08);
}

.ov-task-table-head {
    font-size: 0.7rem;
    padding: 6px 12px;
    background: var(--active-bg);
    font-weight: 700;
    color: var(--text-secondary);
    display: flex;
    gap: 10px;
    border-bottom: 1px solid var(--border-subtle);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}

.ov-objective { margin-bottom: 24px; }
.ov-objective-head {
    background: var(--accent);
    color: #fff;
    padding: 14px 20px;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    display: flex;
    align-items: center;
    gap: 10px;
}
.ov-objective-title {
    flex: 1;
    font-weight: 700;
    font-size: 1rem;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.ov-smart-trigger {
    background: var(--bg-secondary);
    padding: 8px 20px;
    border-bottom: 1px solid var(--border-subtle);
    cursor: pointer;
    font-size: 0.8rem;
    color: var(--text-secondary);
}
.ov-smart-trigger:hover { background: var(--hover-bg); }
.ov-smart-body {
    background: var(--bg-secondary);
    padding: 10px 20px;
    border-bottom: 1px solid var(--border-subtle);
    font-size: 0.8rem;
    color: var(--text-secondary);
}
.ov-smart-row { margin-bottom: 4px; }

.ov-team-head {
    background: var(--subtle-bg);
    padding: 10px 20px;
    border-left: 3px solid var(--accent);
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    gap: 10px;
}
.ov-team-head-flat { margin-top: 8px; }

.ov-projects-section { margin-top: 32px; }
.ov-projects-section-heading {
    font-size: 1.1rem;
    font-weight: 700;
    margin-bottom: 12px;
    color: var(--text-primary);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.ov-project-wrap { padding: 0 12px; }

.ov-empty {
    text-align: center;
    padding: 60px;
    color: var(--text-secondary);
}
.ov-empty-text { font-size: 1.1rem; }

/* === SWOT view polish === */
.swot-step-clickable { cursor: pointer; }
.swot-top-bar {
    margin: -30px -30px 20px;
    border-radius: 0;
}
.swot-wizard-title {
    margin-bottom: 30px;
    text-align: center;
}
.swot-step-content {
    padding: 30px;
    min-height: 400px;
    /* This card is a flex child of .swot-container (flex column, height:100%,
       overflow-y:auto). Without flex-shrink:0 the browser shrinks the card to
       fit the viewport instead of growing it, so tall step content overflows
       past the card border and the parent scrollbar never appears. Pinning the
       shrink factor lets the card grow to its content and the container scroll. */
    flex-shrink: 0;
    animation: slideIn 0.3s ease-out;
}
.swot-step-heading {
    margin-bottom: 20px;
    color: var(--accent);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.swot-step-heading-hint {
    font-size: 0.75rem;
    color: var(--text-muted);
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
}
.swot-step-subtitle {
    color: var(--text-muted);
    margin-bottom: 20px;
}
/* SWOT step 1 stacks several field groups (idea, teams, members, import,
   context). Delimit them with breathing room + a hairline divider so the form
   reads as distinct fields instead of one crowded block. Scoped to .swot-fields
   so no other step or form is affected. */
.swot-fields { display: flex; flex-direction: column; }
.swot-fields .control-group {
    padding: 18px 0;
    border-bottom: 1px solid var(--border-subtle);
}
.swot-fields .control-group:first-child { padding-top: 0; }
.swot-fields .control-group:last-child { padding-bottom: 0; border-bottom: none; }
/* Opt-in checkbox rows inside the wizard (e.g. "Include my company profile").
   Overrides the uppercase/muted .control-group label styling for a normal,
   readable inline checkbox + text. */
.swot-check-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 12px;
    cursor: pointer;
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--text-primary);
    text-transform: none;
    letter-spacing: 0;
}
.swot-check-row input { margin: 0; flex-shrink: 0; }

.swot-step-actions {
    display: flex;
    justify-content: space-between;
    margin-top: 30px;
    gap: 12px;
}
.swot-step-actions-end { justify-content: flex-end; }
.swot-textarea-md {
    height: 100px;
    resize: none;
}
.swot-textarea-sm {
    height: 60px;
    resize: vertical;
}
.smart-card-spaced { margin-bottom: 20px; }
.smart-input {
    width: 90%;
    display: inline-block;
}
.smart-statement-label {
    font-size: 0.7rem;
    text-transform: uppercase;
    color: var(--text-muted);
    letter-spacing: 0.05em;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.smart-statement-input {
    width: 100%;
    min-height: 96px;
    resize: vertical;
    box-sizing: border-box;
    overflow: hidden;
}
.ai-reply-input { flex: 1; }

.swot-summary-panel {
    padding: 20px;
    margin-bottom: 20px;
}
.swot-summary-heading {
    color: var(--accent);
    margin-bottom: 10px;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.swot-summary-quote { font-style: italic; }
.swot-counts-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    font-size: 0.85rem;
}
.swot-dot { font-size: 0.85rem; }
.swot-dot-strengths     { color: var(--success); }
.swot-dot-weaknesses    { color: var(--danger); }
.swot-dot-opportunities { color: var(--warning); }
.swot-dot-threats       { color: var(--text-muted); }

.swot-target-card {
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
    padding: 20px;
    text-align: center;
}
.swot-target-label {
    font-size: 0.8rem;
    color: var(--text-secondary);
    margin-bottom: 6px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.swot-target-name {
    font-weight: 700;
    font-size: 1.1rem;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}

.swot-target-banner {
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--accent-cyan);
    border-radius: var(--radius-md);
    padding: 12px 16px;
    margin-bottom: 20px;
    display: flex;
    align-items: center;
    gap: 10px;
}
.swot-target-banner-icon { font-size: 1.1rem; }
.swot-target-banner-label {
    font-size: 0.7rem;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 600;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}
.swot-target-banner-name { font-weight: 600; }

.swot-simple-tasks-help {
    text-align: center;
    padding: 40px 20px;
    color: var(--text-secondary);
}

.swot-quadrant-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--border-subtle);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    text-transform: uppercase;
    font-size: 0.85rem;
    letter-spacing: 0.04em;
}
.swot-quadrant-title { flex: 1; }
.swot-quadrant-add-btn { flex: 0 0 auto; }
.swot-quadrant-strengths     { border-top: 3px solid var(--success); }
.swot-quadrant-weaknesses    { border-top: 3px solid var(--danger); }
.swot-quadrant-opportunities { border-top: 3px solid var(--warning); }
.swot-quadrant-threats       { border-top: 3px solid var(--text-muted); }
.swot-quadrant-header-strengths     { color: var(--success); }
.swot-quadrant-header-weaknesses    { color: var(--danger); }
.swot-quadrant-header-opportunities { color: var(--warning); }
.swot-quadrant-header-threats       { color: var(--text-secondary); }

.swot-drop-empty {
    padding: 20px;
    text-align: center;
    color: var(--text-muted);
    font-size: 0.8rem;
    font-style: italic;
}
.swot-item-text {
    flex: 1;
    outline: none;
    cursor: text;
    margin: 0 8px;
}

.gen-card-header {
    display: flex;
    gap: 10px;
    align-items: center;
}
.gen-card-checkbox {
    width: 20px;
    height: 20px;
    cursor: pointer;
    accent-color: var(--accent-cyan);
}
.gen-card-title-input {
    flex: 1;
    font-weight: 700;
}
.gen-card-desc-input {
    height: 60px;
    font-size: 0.8rem;
    resize: none;
}
.gen-add-btn {
    opacity: 0.7;
    margin-top: 6px;
}
.gen-add-btn:hover { opacity: 1; }
.gen-subtasks-bordered {
    margin-top: 10px;
    border-top: 1px solid var(--border-subtle);
    padding-top: 10px;
}

/* === My Tasks view polish === */
.mt-section-count {
    color: var(--text-muted);
    font-weight: 400;
    font-size: 0.8rem;
}
.mt-section-owner {
    color: var(--text-muted);
    font-size: 0.75rem;
    margin-left: 8px;
    font-weight: 400;
}
.mt-empty-state {
    color: var(--text-muted);
    padding: 24px;
    text-align: center;
    font-size: 0.9rem;
}
.swimlane-count { color: var(--text-muted); }
.swimlane-header-actions {
    display: flex;
    align-items: center;
}
.swimlane-toggle { margin-left: 10px; }

/* === Attachments view polish === */
.att-view-btn-label { margin-left: 6px; }
.att-loading {
    padding: 20px;
    color: var(--text-muted);
}
.att-empty-large {
    text-align: center;
    padding: 60px;
    color: var(--text-secondary);
    font-size: 0.95rem;
}
.att-empty-error { color: var(--danger); }
.att-empty {
    text-align: center;
    padding: 24px;
    color: var(--text-secondary);
    font-size: 0.9rem;
    border: 1px dashed var(--border-subtle);
    border-radius: var(--radius-lg);
}
.att-empty-inline {
    color: var(--text-muted);
    font-size: 0.8rem;
    text-align: center;
    padding: 8px;
}
.att-section-title {
    margin: 24px 0 8px;
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-secondary);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}

.att-upload-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
    padding: 12px;
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-lg);
}
.att-upload-bar-count {
    font-size: 0.85rem;
    color: var(--text-secondary);
}
.att-upload-bar-actions {
    display: flex;
    gap: 8px;
    align-items: center;
}
.att-upload-file { font-size: 0.8rem; }

/* #attachments-view is a .main-content flex column (overflow:hidden) with a
   fixed .top-bar header, so the container below it must own the scroll — else a
   long project attachment list overflows past the viewport and the bottom rows
   are clipped with no way to reach them. Mirrors #my-tasks-container. */
#attachments-container {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

.att-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 8px;
}
.att-toolbar-count {
    font-size: 0.85rem;
    color: var(--text-secondary);
}

.att-link {
    color: var(--text-primary);
    text-decoration: none;
}
.att-link:hover { color: var(--accent-cyan); }

.att-context-task {
    font-weight: 500;
    color: var(--text-primary);
}
.att-context-excerpt {
    font-size: 0.75rem;
    color: var(--text-muted);
}
.att-context-task-name { color: var(--text-primary); }

.attachment-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    border-bottom: 1px solid var(--border-subtle);
}
.attachment-row-emoji { font-size: 1.1rem; }
.attachment-row-main {
    flex: 1;
    min-width: 0;
}
.attachment-row-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.attachment-row-meta {
    font-size: 0.7rem;
    color: var(--text-secondary);
}

.att-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px;
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-pill);
    font-size: 0.75rem;
    margin: 2px 4px 2px 0;
}
.att-chip-delete {
    padding: 0 4px;
    font-size: 0.7rem;
    color: var(--danger);
    border: none;
    background: transparent;
}
.att-chip-delete:hover { background: var(--danger-soft); }
.att-chips { margin-top: 6px; }

/* === Admin view polish === */
.team-member-roles {
    color: var(--text-muted);
    font-size: 0.8em;
}

.admin-col-role-badge {
    text-align: center;
    font-size: 0.65rem;
    text-transform: uppercase;
    color: var(--text-muted);
    padding: 2px 6px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border-subtle);
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    letter-spacing: 0.04em;
}
.admin-col-protected {
    text-align: center;
    font-size: 0.75rem;
    color: var(--text-muted);
    font-style: italic;
}
.admin-col-delete-btn { width: 100%; }
.admin-col-row {
    display: grid;
    grid-template-columns: 16px 1fr 72px auto 80px;
    gap: 10px;
    align-items: center;
}
.admin-col-handle {
    text-align: center;
    color: var(--text-muted);
}
.admin-col-handle.is-draggable {
    cursor: grab;
    opacity: 0.7;
}
.admin-col-handle.is-draggable:active { cursor: grabbing; }
.admin-col-handle.is-fixed {
    cursor: default;
    opacity: 0.3;
}
.admin-col-name-input {
    width: 100%;
    min-width: 0;
}
.admin-col-adder {
    display: flex;
    justify-content: center;
    padding: 6px;
}
.admin-col-add-btn { opacity: 0.7; }
.admin-col-add-btn:hover { opacity: 1; }

/* Project Management form rows */
.pm-field {
    display: flex;
    flex-direction: column;
    min-width: 0;
}
.pm-field-grow { flex: 1; }
.pm-desc-input {
    height: 35px;
    resize: vertical;
}
.pm-date-row {
    display: flex;
    gap: 5px;
}
.pm-date-row .glass-input { flex: 1; min-width: 0; }
.pm-actions-row {
    display: flex;
    gap: 5px;
}

/* Manage projects reuses the overview's .ov-controls toolbar; it only needs the
   spacing adjusted for sitting inside a panel rather than under a page title. */
.pm-toolbar {
    padding-top: 0;
    margin-bottom: 14px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border-subtle);
}
.pm-no-match {
    padding: 14px 4px;
    font-size: 0.85rem;
    color: var(--text-secondary);
    text-align: center;
}

/* --- Project card: name first, details on demand -------------------------
   The name is the field you read and edit; it gets the full row and never
   shares horizontal space with a picker. Everything else lives in the
   collapsible panel below, so narrowing the window can only wrap the small
   action buttons — it can never squeeze the name. */
.pm-card-head {
    display: flex;
    align-items: flex-end;
    gap: 10px;
    flex-wrap: wrap;
}
/* Row context only (the card head). Grows into all the space and wraps the
   buttons onto their own line before it gives any width back. */
.pm-card-head .pm-name-field { flex: 1 1 260px; }
.pm-name-input {
    font-weight: 600;
    font-size: 0.98rem;
    width: 100%;
    box-sizing: border-box;
}
/* The name field is a <textarea> so a long project name WRAPS instead of
   scrolling sideways through a keyhole — see wireAutoGrowField (app.js), which
   sizes the height to the content and keeps newlines out of the value. These
   rules undo the multi-line-editor look inherited from textarea.glass-input so
   a short name is pixel-identical to the single-line input it replaced: one
   row tall, no resize grip, and the same 40px floor as .glass-input. */
textarea.pm-name-input {
    display: block;
    /* Same floor as .glass-input, and the single-line case lands exactly on it:
       0.98rem × 1.4 line ≈ 22px + 16px padding + 2px border ≈ 40px. So a
       one-line name is the same height as every other field on the card, and
       each extra wrapped line adds exactly one line-height. */
    min-height: 40px;
    padding: 8px 12px;
    line-height: 1.4;
    /* JS owns the height, so there is nothing to drag. */
    resize: none;
    /* Grows freely up to ~6 lines, then scrolls instead — one pathological name
       must not push every other card off the screen. No scrollbar appears below
       that cap because the JS height always equals the content height; the
       global `scrollbar-gutter: stable` is dropped so the unclamped case
       doesn't reserve an empty gutter either. */
    max-height: 148px;
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-gutter: auto;
    /* Long unbroken names (URLs, generated ids) break instead of forcing a
       horizontal scrollbar. break-word rather than anywhere: it wraps the same
       way without feeding back into the flex item's intrinsic minimum width. */
    overflow-wrap: break-word;
}
.pm-head-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}
/* Permissions is a door into the project, not one of its fields, so it sits in
   the open rather than behind the Details toggle — sharing the summary's line,
   pushed right under Save, instead of costing the card a row of its own.
   The button lives on this wrapper and not inside .pm-card-summary because the
   summary itself is display:none while the details panel is open, which would
   take the button down with it. */
.pm-card-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px 12px;
    margin-top: 8px;
}
/* margin-left:auto rather than justify-content:space-between, so the button
   still parks on the right when the summary beside it is hidden. */
.pm-card-meta .pm-permissions-btn {
    flex: 0 0 auto;
    margin-left: auto;
}
.pm-card-summary {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    /* Spacing is the .pm-card-meta row's job now. */
    margin-top: 0;
    font-size: 0.78rem;
    color: var(--text-secondary);
}
.pm-card-summary.hidden { display: none; }
.pm-summary-sep { color: var(--text-muted); }

/* The details panel itself — also used by the create-project form. */
.pm-collapsible {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.pm-collapsible.collapsed { display: none; }
.pm-card-details {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 10px 12px;
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--border-subtle);
}
.pm-details-full { grid-column: 1 / -1; }
/* The panel has room the old cramped row didn't — let the description breathe. */
.pm-card-details .pm-desc-input { height: 64px; }
.pm-details-actions {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    justify-content: flex-end;
}

/* Toggle that opens a details panel. Reads as a quiet link, not a button
   competing with Save. */
.pm-collapse-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: none;
    border: none;
    padding: 6px 4px;
    cursor: pointer;
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 0.82rem;
    font-weight: 600;
    transition: color 0.15s ease;
}
.pm-collapse-toggle:hover { color: var(--accent-cyan); }
.pm-collapse-caret {
    font-size: 0.7rem;
    color: var(--text-muted);
}
.pm-collapse-summary {
    font-weight: 500;
    color: var(--text-muted);
}
.pm-collapse-summary-missing { color: var(--warning, #f7b731); }

/* Manage projects → Trash (soft-deleted projects). Solid border since, unlike
   the status zones above, it isn't a drag-drop target. */
.admin-trash-zone {
    border-style: solid;
    border-width: 1px;
    border-color: var(--border-subtle);
}
.admin-trash-empty { color: var(--text-muted); font-size: 0.85rem; padding: 4px 2px; }
.admin-trash-card {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
}
.pm-trash-name { font-weight: 600; color: var(--text-primary); }

/* Team modal — role chips & catalog */
.team-role-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.75rem;
    padding: 4px 4px 4px 10px;
    border-radius: var(--radius-pill);
    background: var(--accent);
    color: #fff;
    border: 1px solid var(--accent);
}
.team-role-chip-remove {
    padding: 0 6px;
    font-size: 0.7rem;
    line-height: 1;
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
    border: none;
    border-radius: 50%;
}
.team-role-chip-remove:hover { background: rgba(255, 255, 255, 0.32); }
.team-role-empty {
    font-size: 0.75rem;
    color: var(--text-muted);
    font-style: italic;
}
.team-role-picker-wrap {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 0.75rem;
}
.team-role-picker {
    font-size: 0.75rem;
    padding: 2px 6px;
    min-width: 120px;
}
.team-member-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.team-member-name {
    font-weight: 600;
    font-size: 0.95rem;
}
.team-member-remove { padding: 2px 8px; }
.team-member-roles-row {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
    margin-top: 4px;
}
.team-role-catalog-empty {
    font-size: 0.85rem;
    color: var(--text-muted);
    padding: 8px 0;
    font-style: italic;
}
.team-role-catalog-row {
    display: flex;
    gap: 10px;
    align-items: center;
    padding: 6px 0;
    border-bottom: 1px solid var(--border-subtle);
}
.team-role-catalog-name {
    flex: 1;
    font-size: 0.9rem;
}

/* Project Permissions modal */
.pp-empty-text {
    color: var(--text-muted);
    font-size: 0.85rem;
}
.pp-th-name { text-align: left; }

/* === Sidebar / app.js polish === */
.project-list-manage {
    border-top: 1px solid var(--border-subtle);
    margin-top: 10px;
    padding-top: 10px;
}
.project-list-manage-label {
    color: var(--text-secondary);
    font-weight: 600;
    font-family: 'Space Grotesk', 'Inter', sans-serif;
}

/* =====================================================================
   28d. Task view — a regular .main-content route. The .hidden global rule
   handles show/hide. We just style its inner layout here.
   ===================================================================== */
.task-view {
    background: var(--bg-main);
    overflow: hidden;
    flex-direction: column;
    position: relative;
}
body.dark-theme .task-view { background: var(--bg-secondary); }

/* Cap readable width on big monitors */
.task-view .task-view-body {
    width: 100%;
    max-width: 960px;
    margin: 0 auto;
}
.task-view .task-view-header {
    width: 100%;
    flex-shrink: 0;
}
.task-view .task-view-header > * {
    flex-shrink: 0;
}

/* ---------------------------------------------------------------------
   29. Touch device tweaks (no hover, coarse pointer)
   --------------------------------------------------------------------- */
@media (hover: none) and (pointer: coarse) {
    .nav-section li { padding: 12px; min-height: 44px; }
    .glass-btn { padding: 11px 18px; min-height: 44px; }
    .glass-btn-sm { padding: 8px 12px; min-height: 36px; }
    .icon-btn { width: 44px; height: 44px; }
    .mobile-menu-toggle { width: 44px; height: 44px; }
    .glass-input,
    .glass-select,
    .custom-select-trigger { height: 44px; }
    .task-card { padding: 14px; }
    .task-row { padding: 12px 14px; }

    /* Hover lifts feel sticky on touch — disable */
    .task-card:hover {
        transform: none;
        box-shadow: var(--card-shadow);
    }
    .att-card:hover { transform: none; }
    .swarming-floating-btn:hover .swarming-floating-btn-expanded {
        transform: translateY(-50%);
    }
    .task-card,
    .task-row,
    .admin-project-card,
    .swot-item { cursor: default; }
}

/* ---------------------------------------------------------------------
   30. Print
   --------------------------------------------------------------------- */
@media print {
    .sidebar,
    .sidebar-overlay,
    .top-bar,
    .bulk-bar,
    .notification-container,
    .swarming-banner,
    .swarming-floating-btn,
    .task-view,
    .mobile-menu-toggle,
    .top-bar-actions,
    .timeline-controls,
    .doc-edit-toggle,
    .doc-add-wrap,
    .doc-add-btn { display: none !important; }
    .main-content { margin: 0; padding: 0; overflow: visible; }
    .task-card,
    .task-row,
    .swimlane,
    .workflow-section { break-inside: avoid; box-shadow: none; }
    /* The app shell is a fixed full-viewport flex column: `body` is
       height:100vh + overflow:hidden, and .app-container flexes inside it.
       In print that clamps everything to a single page, so the PDF only ever
       got page 1. Release the height/overflow clamp on both so the content
       can flow across as many pages as it needs. */
    body {
        background: #fff;
        color: #000;
        height: auto !important;
        overflow: visible !important;
        display: block !important;
    }
    .app-container {
        display: block !important;
        height: auto !important;
        min-height: 0 !important;
        overflow: visible !important;
    }
}

/* Document view: printable-paper layout. Strip the on-screen card chrome
   (background, border, shadow, max-width) so the article fills the page
   and reads like a real document. Keep task/subtask blocks together when
   possible — break-inside: avoid does the heavy lifting for short blocks;
   longer blocks will naturally break. */
@media print {
    body.printing-document #timeline-view,
    body.printing-document #kanban-view,
    body.printing-document #list-view,
    body.printing-document #calendar-view,
    body.printing-document #attachments-view,
    body.printing-document #financials-view,
    body.printing-document #admin-view,
    body.printing-document #team-view,
    body.printing-document #analytics-view,
    body.printing-document #swot-view,
    body.printing-document #overview-view,
    body.printing-document #project-management-view,
    body.printing-document #my-tasks-view { display: none !important; }

    /* #document-view is a flexed .main-content with `overflow-y: auto`, i.e. a
       viewport-height scroll container. Chrome prints only the scrolled-in
       portion of such a container, clipping the document to one page. The bare
       `#document-view` ID selector outweighs the `.main-content` overflow reset
       above, so re-assert overflow/height here (this rule's specificity wins)
       to let the full article paginate. */
    body.printing-document #document-view {
        display: block !important;
        overflow: visible !important;
        height: auto !important;
    }
    body.printing-document #document-view .top-bar { display: none !important; }

    body.printing-document .document-paper {
        max-width: 100% !important;
        width: 100% !important;
        background: #fff !important;
        color: #000 !important;
        border: none !important;
        border-radius: 0 !important;
        box-shadow: none !important;
        padding: 0 !important;
        font-size: 10.5pt;
        line-height: 1.5;
    }
    body.printing-document .doc-title {
        color: #000 !important;
        border-bottom: 2px solid #444 !important;
        padding-right: 0 !important;
        font-size: 20pt !important;
        page-break-after: avoid;
    }
    body.printing-document .document-paper h2 {
        color: #000 !important;
        font-size: 13pt !important;
        page-break-after: avoid;
        margin-top: 18pt;
    }
    body.printing-document .document-paper h3 {
        color: #000 !important;
        font-size: 11pt !important;
        page-break-after: avoid;
    }
    body.printing-document .doc-intro strong { color: #000 !important; }
    body.printing-document .doc-task,
    body.printing-document .doc-subtask,
    body.printing-document .doc-checklist-item { break-inside: avoid; }
    body.printing-document .doc-task-list,
    body.printing-document .doc-subtask-list { padding-left: 24pt; }
    body.printing-document a { color: #000 !important; text-decoration: none; }
}

/* Timeline / Gantt: landscape, full-bleed chart, no scroll containers. The
   sticky chart needs `overflow: visible` on every ancestor so the browser
   can paginate the long task list. Bars and dependency arrows stay anchored
   in percentage space, so the chart prints at whatever width the page gives
   us. */
@media print {
    body.printing-timeline #document-view,
    body.printing-timeline #kanban-view,
    body.printing-timeline #list-view,
    body.printing-timeline #calendar-view,
    body.printing-timeline #attachments-view,
    body.printing-timeline #financials-view,
    body.printing-timeline #admin-view,
    body.printing-timeline #team-view,
    body.printing-timeline #analytics-view,
    body.printing-timeline #swot-view,
    body.printing-timeline #overview-view,
    body.printing-timeline #project-management-view,
    body.printing-timeline #my-tasks-view { display: none !important; }

    body.printing-timeline #timeline-view { display: block !important; }
    body.printing-timeline #timeline-view .top-bar { display: none !important; }
    body.printing-timeline .timeline-container {
        height: auto !important;
        overflow: visible !important;
        padding: 0 !important;
    }
    body.printing-timeline .timeline-chart-area {
        height: auto !important;
        overflow: visible !important;
    }
    body.printing-timeline .timeline-chart-wrapper {
        /* Slimmer label column for landscape A4 so more of the page is
           available for the actual timeline bars. */
        --timeline-label-width: 280px;
        background: #fff !important;
        border: 1px solid #888 !important;
        border-radius: 0 !important;
        box-shadow: none !important;
        overflow: visible !important;
        page-break-inside: auto;
    }
    body.printing-timeline .timeline-body {
        overflow: visible !important;
        height: auto !important;
    }
    body.printing-timeline .timeline-header-row {
        background: #f0f0f0 !important;
        color: #000 !important;
        position: static !important;
        -webkit-print-color-adjust: exact !important;
        print-color-adjust: exact !important;
    }
    body.printing-timeline .timeline-row {
        break-inside: avoid;
        page-break-inside: avoid;
        background: #fff !important;
        /* No blanket color:#000 here — it would override the bars' own
           white-on-color labels. Sidebar labels get #000 from their own
           rule below; the bars keep their designed text colors. */
    }
    body.printing-timeline .timeline-row:hover { background: #fff !important; }
    body.printing-timeline .timeline-label,
    body.printing-timeline .timeline-sidebar-header,
    body.printing-timeline .timeline-timeline-header { color: #000 !important; }
    body.printing-timeline .timeline-bar {
        box-shadow: none !important;
        border: 1px solid #555 !important;
        /* Browsers drop background colors when printing unless told to keep
           them ("economy" is the default). Force exact so the colored Gantt
           bars actually render in the PDF instead of coming out white. */
        -webkit-print-color-adjust: exact !important;
        print-color-adjust: exact !important;
    }
    /* Re-assert the on-screen text colors: with backgrounds now printed,
       white labels belong on the filled task/done bars, dark labels on the
       light project/swimlane bars, cyan on the hollow subtask bars. */
    body.printing-timeline .timeline-bar.task,
    body.printing-timeline .timeline-bar.endless-task,
    body.printing-timeline .timeline-bar.task.is-resolved { color: #fff !important; }
    body.printing-timeline .timeline-bar.project,
    body.printing-timeline .timeline-bar.swimlane { color: #000 !important; }
    body.printing-timeline .timeline-bar.subtask {
        color: var(--accent-cyan) !important;
        background: transparent !important;
        border: 1.5px dashed var(--accent-cyan) !important;
    }
    body.printing-timeline .timeline-bar.subtask.is-resolved {
        color: var(--success) !important;
        border-color: var(--success) !important;
    }
    body.printing-timeline .timeline-today-line { display: none !important; }
    /* Print: undo the horizontal-scroll layout so the whole span fits the
       landscape page instead of clipping to one scroll viewport. The track
       reverts to flex:1 (fills the page), rows to auto width, sticky columns to
       static, and the dependency SVG back to (100% - label). */
    body.printing-timeline .timeline-chart-wrapper.is-scroll { overflow: visible !important; }
    body.printing-timeline .timeline-chart-wrapper.is-scroll .timeline-header-row,
    body.printing-timeline .timeline-chart-wrapper.is-scroll .timeline-body,
    body.printing-timeline .timeline-chart-wrapper.is-scroll .timeline-row { width: auto !important; min-width: 0 !important; }
    body.printing-timeline .timeline-chart-wrapper.is-scroll .timeline-timeline-header,
    body.printing-timeline .timeline-chart-wrapper.is-scroll .timeline-track { flex: 1 1 auto !important; width: auto !important; }
    body.printing-timeline .timeline-chart-wrapper.is-scroll .timeline-label,
    body.printing-timeline .timeline-chart-wrapper.is-scroll .timeline-sidebar-header { position: static !important; }
    body.printing-timeline .timeline-chart-wrapper.is-scroll .timeline-dependency-svg { width: calc(100% - var(--timeline-label-width)) !important; }
}

/* ---------------------------------------------------------------------
   Flatpickr date picker — match the calendar popup to the app theme
   --------------------------------------------------------------------- */
body.dark-theme .flatpickr-calendar {
    background: var(--bg-elevated);
    color: var(--text-primary);
    box-shadow: var(--modal-shadow);
    border: 1px solid var(--border-color);
    /* Tells Chrome/Edge/Safari to render the native popup for the embedded
       month <select> (and any other native form controls inside) using the
       dark UA palette. Without this hint, the OS-level dropdown stays light
       on light when the page is dark, since `option { background: … }` is
       ignored on those engines. */
    color-scheme: dark;
}
body.dark-theme .flatpickr-months,
body.dark-theme .flatpickr-month,
body.dark-theme .flatpickr-current-month,
body.dark-theme .flatpickr-current-month input.cur-year,
body.dark-theme .flatpickr-weekday {
    color: var(--text-primary);
    background: transparent;
    fill: var(--text-primary);
}
/* Month <select> needs explicit dark surface (not transparent) so the closed
   trigger reads correctly against the calendar background. The opened native
   popup is rendered by the OS, so we can't style it directly — instead we
   rely on `color-scheme: dark` on the element + `appearance: menulist` to
   tell Chrome/Edge/Safari/Firefox to use the dark UA popup. !important is
   needed because flatpickr's own stylesheet sets `appearance` and
   `background: transparent` on this select via a more-specific rule. */
body.dark-theme .flatpickr-monthDropdown-months {
    background: var(--bg-elevated) !important;
    color: var(--text-primary) !important;
    color-scheme: dark !important;
    -webkit-appearance: menulist !important;
    appearance: menulist !important;
    border: none;
}
body.dark-theme .flatpickr-monthDropdown-months option,
body.dark-theme .flatpickr-monthDropdown-months .flatpickr-monthDropdown-month {
    background-color: var(--bg-elevated) !important;
    color: var(--text-primary) !important;
}
body.dark-theme .flatpickr-prev-month svg,
body.dark-theme .flatpickr-next-month svg { fill: var(--text-primary); }
body.dark-theme .flatpickr-day {
    color: var(--text-primary);
    background: transparent;
    border-color: transparent;
}
body.dark-theme .flatpickr-day.prevMonthDay,
body.dark-theme .flatpickr-day.nextMonthDay,
body.dark-theme .flatpickr-day.flatpickr-disabled { color: var(--text-muted); }
body.dark-theme .flatpickr-day:hover,
body.dark-theme .flatpickr-day:focus {
    background: var(--hover-bg);
    border-color: transparent;
}
body.dark-theme .flatpickr-day.today {
    border-color: var(--accent-cyan);
    color: var(--accent-cyan);
}
body.dark-theme .flatpickr-day.selected,
body.dark-theme .flatpickr-day.selected:hover {
    background: var(--accent-cyan);
    color: var(--accent);
    border-color: var(--accent-cyan);
}

/* ---------------------------------------------------------------------
   AI Help Document (per-task) — sliding side panel + state machine
   --------------------------------------------------------------------- */
.ai-help-panel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    /* Wide enough that typical RACI/risk/decision matrices don't overflow.
       Caps at 92vw on narrow screens so it still leaves a peek of the task
       view behind it. */
    width: min(820px, 92vw);
    background: var(--bg-main);
    border-left: 1px solid var(--border-subtle);
    box-shadow: -8px 0 24px rgba(0, 0, 0, 0.18);
    display: flex;
    flex-direction: column;
    transform: translateX(100%);
    transition: transform 0.25s ease;
    z-index: 20;
    pointer-events: none;
}
body.dark-theme .ai-help-panel { background: var(--bg-secondary); }
.ai-help-panel.open {
    transform: translateX(0);
    pointer-events: auto;
}
.ai-help-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 18px;
    border-bottom: 1px solid var(--border-subtle);
    background: var(--bg-secondary);
    flex-shrink: 0;
}
body.dark-theme .ai-help-panel-header { background: var(--subtle-bg); }
.ai-help-panel-header h3 {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}
.ai-help-panel-body {
    flex: 1;
    overflow-y: auto;
    padding: 16px 18px;
}
@media (max-width: 640px) {
    .ai-help-panel { width: 100%; }
}

.ai-help-empty {
    padding: 4px 0;
}
.ai-help-loading {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 16px 4px;
    color: var(--text-muted);
    font-size: 0.85rem;
}
.ai-help-spinner {
    width: 18px;
    height: 18px;
    border: 2px solid var(--border-subtle);
    border-top-color: var(--accent-cyan);
    border-radius: 50%;
    animation: spin 0.9s linear infinite;
    flex: 0 0 auto;
}
.ai-help-meta {
    font-size: 0.75rem;
    color: var(--text-muted);
    margin-bottom: 8px;
}
.ai-help-view {
    padding: 12px 14px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: 6px;
    line-height: 1.5;
    font-size: 0.9rem;
}
.ai-help-view h1 { font-size: 1.4rem; margin: 0 0 10px; border-bottom: 1px solid var(--border-subtle); padding-bottom: 6px; }
.ai-help-view h2 { font-size: 1.1rem; margin: 16px 0 6px; color: var(--accent-cyan); }
.ai-help-view h3 { font-size: 0.98rem; margin: 12px 0 4px; }
.ai-help-view p,
.ai-help-view li { margin: 0 0 6px; }
.ai-help-view ul,
.ai-help-view ol { padding-left: 22px; margin: 4px 0 8px; }
/* Tables: make them block-level so a wide table can scroll horizontally
   inside the viewer instead of stretching the whole panel layout. Cells
   wrap to keep individual columns readable while the row group scrolls. */
.ai-help-view table {
    display: block;
    width: 100%;
    max-width: 100%;
    overflow-x: auto;
    border-collapse: collapse;
    margin: 8px 0;
}
.ai-help-view th,
.ai-help-view td {
    border: 1px solid var(--border-subtle);
    padding: 4px 8px;
    text-align: left;
    vertical-align: top;
    white-space: normal;
    word-break: break-word;
}
.ai-help-view th { background: var(--bg-elevated); }
.ai-help-view code {
    font-family: 'Menlo', 'Consolas', monospace;
    background: var(--bg-elevated);
    padding: 1px 4px;
    border-radius: 3px;
    font-size: 0.82rem;
}
.ai-help-view pre code { display: block; padding: 8px; overflow-x: auto; }
.ai-help-view blockquote {
    border-left: 3px solid var(--accent-cyan);
    margin: 8px 0;
    padding: 2px 10px;
    color: var(--text-muted);
}
.ai-help-editor {
    width: 100%;
    box-sizing: border-box;
    min-height: 280px;
    font-family: 'Menlo', 'Consolas', monospace;
    font-size: 0.85rem;
    line-height: 1.5;
    resize: vertical;
}
.ai-help-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 10px;
}
.ai-help-actions .danger {
    color: var(--danger);
    border-color: var(--danger);
}
.ai-help-actions .danger:hover {
    background: var(--danger-soft);
}

/* Deliverable section — appears below the help doc inside the same panel
   once a help doc exists. One of three child blocks is visible at a time
   (offer / not-applicable / generated-doc) based on classification + state. */
.ai-deliverable {
    margin-top: 18px;
}
.ai-deliverable-divider {
    border-top: 1px dashed var(--border-subtle);
    margin: 0 0 14px;
}
.ai-deliverable-offer {
    border: 1px solid var(--accent-cyan);
    border-radius: 8px;
    padding: 12px 14px;
    background: color-mix(in srgb, var(--accent-cyan) 6%, transparent);
}
.ai-deliverable-offer-title {
    font-weight: 700;
    font-size: 0.9rem;
    color: var(--accent-cyan);
    margin-bottom: 4px;
}
.ai-deliverable-offer-body {
    font-size: 0.85rem;
    color: var(--text-secondary);
    margin-bottom: 10px;
    line-height: 1.45;
}
.ai-deliverable-banner {
    border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--text-muted);
    border-radius: 6px;
    padding: 10px 12px;
    background: var(--bg-elevated);
}
.ai-deliverable-banner-title {
    font-weight: 700;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-secondary);
    margin-bottom: 4px;
}
.ai-deliverable-banner-body {
    font-size: 0.85rem;
    color: var(--text-secondary);
    line-height: 1.45;
}
.ai-deliverable-doc-header {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 6px;
}
.ai-deliverable-doc-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
}
.ai-deliverable-kind-chip {
    font-size: 0.65rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--accent-cyan);
    color: var(--bg-main);
    font-weight: 700;
}

/* ---------------------------------------------------------------------
   SWOT step 6 — view switcher + document-style preview
   --------------------------------------------------------------------- */

/* Tab-style toggle between cards and document views. */
.swot-view-switcher {
    display: inline-flex;
    gap: 4px;
    padding: 4px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    margin: 0 0 16px;
}
.swot-view-switcher-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm, 6px);
    color: var(--text-secondary);
    font-size: 0.85rem;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.swot-view-switcher-btn:hover { color: var(--text-primary); }
.swot-view-switcher-btn.active {
    background: var(--bg-elevated);
    border-color: var(--border-subtle);
    color: var(--text-primary);
    box-shadow: 0 1px 2px rgba(0,0,0,0.04);
}
.swot-view-switcher-icon { font-size: 1rem; opacity: 0.7; }

/* Document-style preview — reuses .document-paper / .doc-edit / etc. from
   the project Document view. The overrides below adjust spacing for SWOT
   and add a small per-task selection checkbox + the phase-heading style. */
.swot-doc {
    /* The paper sits inside .swot-generated-grid which has its own grid
       layout — undo it so the paper occupies the full width. */
    grid-column: 1 / -1;
    max-width: 920px;
    margin: 0 auto;
}
.swot-doc-title {
    text-align: left;
}
.swot-doc-phase-heading {
    margin-top: 28px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--border-subtle);
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}
.swot-doc .doc-swimlane-range,
.swot-doc-phase-heading .doc-swimlane-range {
    font-size: 0.78rem;
    color: var(--text-muted);
    font-weight: 500;
    white-space: nowrap;
}

.swot-doc-task {
    margin-bottom: 16px;
    padding-left: 6px;
}
.swot-doc-task.is-unselected {
    opacity: 0.5;
}
.swot-doc-task-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 4px;
}
.swot-doc-select {
    flex: 0 0 auto;
    margin: 0;
    transform: translateY(1px);
    cursor: pointer;
}
.swot-doc-chapter {
    flex: 0 0 auto;
    font-size: 0.72rem;
    font-weight: 600;
    padding: 1px 6px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: 4px;
    color: var(--text-secondary);
    letter-spacing: 0.04em;
}
.swot-doc-task-title {
    flex: 1 1 auto;
    font-weight: 600;
    font-size: 1.02rem;
    min-width: 0;
}
.swot-doc-task-meta {
    font-size: 0.83rem;
    color: var(--text-secondary);
    margin: 4px 0 6px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 6px;
}
.swot-doc-task-meta .doc-inline-select,
.swot-doc-task-meta .doc-inline-date {
    min-width: 0;
}
.swot-doc-task-desc {
    margin: 6px 0 8px;
}
.swot-doc-deliverable,
.swot-doc-deps {
    font-size: 0.85rem;
    margin: 4px 0;
}
.swot-doc-deliverable strong,
.swot-doc-deps strong {
    color: var(--text-secondary);
    margin-right: 6px;
}
.swot-doc-deliverable-text {
    /* contenteditable inherits font; keep it on-line with the label. */
    display: inline;
}

.swot-doc-checklist,
.swot-doc-subtasks-wrap {
    margin: 8px 0;
    padding: 8px 10px;
    background: var(--bg-secondary);
    border-radius: var(--radius-sm, 6px);
}
.swot-doc-sub-label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    font-weight: 600;
    margin-bottom: 6px;
}
.swot-doc-check-list,
.swot-doc-subtasks {
    list-style: none;
    padding: 0;
    margin: 0 0 6px;
}
.swot-doc-check-item {
    display: flex;
    gap: 6px;
    align-items: center;
    margin-bottom: 4px;
}
.swot-doc-check-input {
    flex: 1 1 auto;
    font-size: 0.85rem;
    padding: 4px 8px;
}
.swot-doc-subtask {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 10px;
    align-items: center;
    padding: 4px 0;
    border-bottom: 1px dashed var(--border-subtle);
}
.swot-doc-subtask:last-child { border-bottom: none; }
.swot-doc-subtask-title {
    flex: 1 1 200px;
    min-width: 0;
    font-weight: 500;
}
.swot-doc-subtask-meta {
    display: inline-flex;
    gap: 6px;
    align-items: center;
    flex: 0 0 auto;
}
.doc-intro-hint {
    font-size: 0.8rem;
    color: var(--text-muted);
    font-style: italic;
}

/* Task description — rendered (saved) view: shows the text + live widgets, with
   the raw [[coreidon-widget:REF]] tokens hydrated. The pencil icon opens the
   edit box (a textarea + widget preview pane). */
.task-desc-view {
    width: 100%;
    box-sizing: border-box;
    min-height: 40px;
    padding: 8px 10px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    background: var(--subtle-bg);
    color: var(--text-primary);
    /* Preserve the author's line breaks and indentation (paragraphs, lists pasted
       or typed into the description read as written). An embedded widget is a
       block and still sits on its own line between the surrounding text. */
    white-space: pre-wrap;
    word-break: break-word;
}
.task-desc-view .desc-placeholder { color: var(--text-secondary); opacity: 0.6; }

/* Contenteditable description editor (edit mode): grows with content and renders
   inserted widgets inline as chips. Overrides .glass-input's fixed 40px height;
   white-space:pre-wrap (like the view) so typed/pasted line breaks show while editing. */
#modal-desc[contenteditable] {
    height: auto;
    min-height: 72px;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    line-height: 1.5;
}
/* Placeholder for the contenteditable (no native placeholder on a <div>). */
#modal-desc:empty::before {
    content: attr(data-placeholder);
    color: var(--text-secondary);
    opacity: 0.6;
    pointer-events: none;
}

/* Comment contenteditable editors (composer + per-comment edit): grow with
   content, render inserted widgets inline as chips. Override .glass-input's
   fixed 40px height; white-space:pre-wrap so typed/pasted line breaks show while
   composing and match the rendered .chat-body. */
#comment-input[contenteditable], .comment-edit-input[contenteditable] {
    height: auto;
    min-height: 64px;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    line-height: 1.5;
}
#comment-input:empty::before, .comment-edit-input:empty::before {
    content: attr(data-placeholder);
    color: var(--text-secondary);
    opacity: 0.6;
    pointer-events: none;
}


/* ─── AI access: hide the SWOT/SMART project tab for denied users ────────────
   Set on <body> at bootstrap from currentUser.ai_swot_enabled (app.js). The
   task-help (✨) entry point is gated per task kind in task_help.js instead
   (project-task vs simple-task AI are separate categories). View/edit/download
   of already-generated artifacts stay (no new AI call). The server-side gate in
   ai_billing.billed_chat_completion is the real enforcement; this is UX.
   !important so JS that toggles `.hidden` can't reveal it. */
body.ai-no-swot #btn-create-tab-swot {
    display: none !important;
}

/* ─── Project membership: expandable team groups (perms modal + create + SWOT) ─
   A team renders as a collapsible group; expanding shows its members, each ON
   by default, unchecking carves them out (excluded_member_ids). */
.pp-team-groups { display: flex; flex-direction: column; gap: 8px; }
.pp-team-group {
    border: 1px solid var(--border-subtle, rgba(255,255,255,0.12));
    border-radius: 8px;
    background: rgba(255,255,255,0.03);
    overflow: hidden;
}
.pp-team-group__header {
    display: flex; align-items: center; gap: 8px;
    padding: 8px 10px;
}
.pp-team-group__toggle {
    background: none; border: none; cursor: pointer; padding: 0;
    color: var(--text-secondary); font-size: 0.85rem; width: 1em;
}
.pp-team-group__name { font-weight: 600; cursor: pointer; }
.pp-team-group__count {
    margin-left: auto; font-size: 0.75rem; color: var(--text-secondary);
    white-space: nowrap;
}
.pp-team-group__remove { margin-left: 4px; }
.pp-team-group__members {
    display: flex; flex-direction: column; gap: 2px;
    padding: 4px 10px 10px 26px;
    border-top: 1px solid var(--border-subtle, rgba(255,255,255,0.08));
}
.pp-team-member {
    display: flex; align-items: center; gap: 8px;
    font-size: 0.9rem; cursor: pointer; padding: 2px 0;
}
.pp-team-member input { cursor: pointer; }

/* ─── Help & How-To view ──────────────────────────────────────────────────
   Four tabs of documentation cards + a search that spans all of them. The
   markup is built by controllers/help.js; card bodies are trusted HTML from
   the locale files, so `.help-body` styles bare tags rather than classes. */
.help-wrap { max-width: 900px; margin: 0 auto; padding: 24px; }
.help-header {
    display: flex; align-items: flex-end; justify-content: space-between;
    gap: 20px; flex-wrap: wrap;
}
.help-header h1 { margin: 0 0 4px; }
.help-sub { color: var(--text-secondary); margin: 0; }
.help-search { width: 100%; max-width: 300px; }

/* Same segmented control as the project view switcher, scoped to help so the
   global `.view-btn.active` sweep in showHelpView() can't clear the active tab. */
.help-tabs {
    display: inline-flex; margin: 20px 0 4px; padding: 3px; gap: 0;
    background: var(--subtle-bg);
    border: 1px solid var(--border-subtle);
    border-radius: 8px;
}
.help-tab {
    padding: 7px 14px; border: none; border-radius: 6px; cursor: pointer;
    background: none; color: var(--text-muted);
    font-size: 0.7rem; font-weight: 600; letter-spacing: 0.04em;
    text-transform: uppercase;
    transition: color 0.15s ease, background 0.15s ease;
}
.help-tab:hover { color: var(--text-primary); background: var(--hover-bg); }
.help-tab.active {
    background: var(--bg-main); color: var(--accent);
    box-shadow: 0 1px 2px rgba(9, 28, 58, 0.10), 0 0 0 1px var(--border-subtle);
}
body.dark-theme .help-tab.active {
    background: var(--bg-elevated); color: var(--accent-cyan);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 0 0 1px var(--border-strong);
}
@media (max-width: 620px) {
    .help-tabs { display: grid; grid-template-columns: 1fr 1fr; width: 100%; }
    .help-search { max-width: none; }
}

.help-status { margin: 12px 0 0; color: var(--text-secondary); font-size: 0.88rem; }
.help-content { margin-top: 16px; }
.help-pane { display: flex; flex-direction: column; gap: 12px; }
/* An author `display` beats the UA rule for [hidden], so inactive panes need
   this to actually stay hidden. Cards are plain blocks and don't. */
.help-pane[hidden] { display: none; }

.help-card {
    padding: 18px 20px;
    border: 1px solid var(--border-subtle);
    border-radius: 10px;
    background: var(--subtle-bg);
}
/* Opt out of the global uppercase heading style: these titles are full
   sentences ("How to assign a team but exclude someone"), not short labels. */
.help-card__title {
    margin: 0 0 10px; font-size: 1rem; font-weight: 600;
    text-transform: none; letter-spacing: 0;
}

/* Trusted HTML from the locales — style the bare tags it may use. */
.help-body { color: var(--text-secondary); font-size: 0.92rem; line-height: 1.6; }
.help-body p { margin: 0 0 8px; }
.help-body ul, .help-body ol { margin: 0 0 8px; padding-left: 22px; }
.help-body li { margin: 0 0 4px; }
.help-body > :last-child { margin-bottom: 0; }
.help-body strong { color: var(--text-primary); font-weight: 600; }
.help-body code {
    padding: 1px 5px; border-radius: 4px;
    background: var(--hover-bg); color: var(--text-primary);
    font-size: 0.85em;
}

/* ── Forbidden overlay ─────────────────────────────────────────────────────
   Shown when a signed-in user has no Projex seat (403 from /me at bootstrap).
   Uses the theme variables, so it follows light/dark like the rest of the app. */
.forbidden-overlay {
    position: fixed;
    inset: 0;
    z-index: 10000;                 /* above the loading overlay (9999) */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: var(--bg-main);
}
.forbidden-card {
    max-width: 460px;
    width: 100%;
    text-align: center;
    padding: 40px 32px;
    border-radius: var(--radius-lg, 16px);
    background: var(--glass-bg);
    border: var(--glass-border);
    box-shadow: var(--card-shadow-hover);
}
.forbidden-logo {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 20px;
    letter-spacing: 0.5px;
    color: var(--text-primary);
    margin-bottom: 20px;
}
.forbidden-logo .highlight { color: var(--accent-cyan); }
.forbidden-code {
    font-family: 'Space Grotesk', 'Inter', sans-serif;
    font-weight: 700;
    font-size: 56px;
    line-height: 1;
    color: var(--accent-cyan);
    margin-bottom: 8px;
}
.forbidden-title {
    font-size: 22px;
    font-weight: 700;
    color: var(--text-primary);
    margin: 0 0 12px;
}
.forbidden-message {
    font-size: 15px;
    line-height: 1.55;
    color: var(--text-secondary);
    margin: 0 0 28px;
}
.forbidden-back {
    display: inline-block;
    text-decoration: none;
}
.forbidden-back[hidden] { display: none; }
