﻿/* ======================================
   Meta4D — Bootstrap 5.3 Variable Overrides
   Brand colors (Tailwind Slate gray scale, #2F6BFF primary),
   app layout tokens, and dark-mode surface flips.
   ====================================== */

:root {
    /* Override Bootstrap primary → brand blue */
    --bs-primary: #2F6BFF;
    --bs-primary-rgb: 47, 107, 255;

    /* DM brand tokens (used across platform + map viewer) */
    --primary: #2F6BFF;
    --primary-hover: #1E5CF5;
    --primary-muted: rgba(47, 107, 255, 0.08);
    --primary-subtle: rgba(47, 107, 255, 0.12);
    --danger: #dc2626;
    --success: #16a34a;
    --success-subtle: rgba(22, 163, 74, 0.12);
    --warning: #d97706;

    /* Header band for the floating map panels (zonal stats, transect, threshold, class breaks,
       vector style, histogram, feature identify).

       The band used to ramp --primary -> --primary-hover, but those two sit about 6%
       apart in lightness, so it rendered as a flat slab of blue rather than a gradient. This
       carries the same blue into indigo — an adjacent hue, so it cannot clash with the brand —
       giving the band depth while staying unmistakably Meta4D blue at the leading edge.

       Defined once, as a token, because seven panels share it and a gradient copied into seven
       stylesheets is a gradient that will disagree with itself within a month. */
    --accent-indigo: #6366F1;
    --panel-header: linear-gradient(100deg,
        var(--primary-hover) 0%,
        var(--primary) 42%,
        var(--accent-indigo) 100%);
    /* Tint of the same, for an icon well or a chip behind warning-coloured content */
    --warning-subtle: rgba(217, 119, 6, 0.12);

    /* Text and icons on a --bs-primary fill. Primary is a saturated blue in both themes,
       so one value serves both — the point is that #fff stops being typed into components. */
    --on-primary:  #ffffff;

    /* Motion tokens */
    --ease-fast:   120ms cubic-bezier(0.4, 0, 0.2, 1);
    --ease-base:   200ms cubic-bezier(0.4, 0, 0.2, 1);
    --ease-slow:   320ms cubic-bezier(0.4, 0, 0.2, 1);
    --ease-spring: 280ms cubic-bezier(0.34, 1.56, 0.64, 1);

    /* Override Bootstrap gray scale → Tailwind Slate */
    --bs-gray-50:  #f8fafc;
    --bs-gray-100: #edf1f5;
    --bs-gray-200: #e2e8f0;
    --bs-gray-300: #cbd5e1;
    --bs-gray-400: #94a3b8;
    --bs-gray-500: #64748b;
    --bs-gray-600: #475569;
    --bs-gray-700: #334155;
    --bs-gray-800: #1e293b;
    --bs-gray-900: #171a1f;

    /* Override Bootstrap body/text/border */
    --bs-body-color: #171a1f;
    --bs-body-color-rgb: 23, 26, 31;
    --bs-body-bg: #ffffff;
    --bs-body-bg-rgb: 255, 255, 255;
    --bs-secondary-color: #64748b;
    --bs-secondary-color-rgb: 100, 116, 139;
    --bs-tertiary-color: #334155;
    --bs-tertiary-color-rgb: 51, 65, 85;
    --bs-tertiary-bg: #ffffff;
    --bs-tertiary-bg-rgb: 255, 255, 255;
    --bs-border-color: #e2e8f0;
    --bs-emphasis-color: #171a1f;

    /* Font family */
    /* Noto Sans Arabic carries only Arabic glyphs (unicode-range), so Latin text keeps Manrope. */
    --bs-body-font-family: 'Manrope', 'Inter', 'Noto Sans Arabic', 'Segoe UI', system-ui, -apple-system, sans-serif;

    /* App layout dimensions (JS toggles these) */
    --sidebar-width: 250px;
    --sidebar-collapsed-width: 68px;
    --right-toolbar-width: 56px;

    /* Space behind the globe. One value in both themes: the sky outside the earth is not
       a UI surface and does not flip with the app. */
    --map-space: #060b16;

    /* Extruded buildings, keyed to height so a skyline has shape. Cool grey, because they
       sit on satellite imagery and must not compete with it. */
    --building-low:  #7d8797;
    --building-mid:  #98a3b3;
    --building-high: #c2cad6;

    /* App surfaces (need dark mode flip, no Bootstrap equivalent) */
    /* Sidebar is dark navy in both themes, so its border matches the dark theme too */
    --sidebar-bg: #0f172a;
    --sidebar-border: #1e293b;
    --card-bg: #ffffff;
}

[data-bs-theme="dark"] {
    /* Invert Slate gray scale */
    --bs-gray-50:  #0b1120;
    --bs-gray-100: #0f172a;
    --bs-gray-200: #1e293b;
    --bs-gray-300: #334155;
    --bs-gray-400: #475569;
    --bs-gray-500: #64748b;
    --bs-gray-600: #94a3b8;
    --bs-gray-700: #cbd5e1;
    --bs-gray-800: #e2e8f0;
    --bs-gray-900: #f1f5f9;

    /* Override Bootstrap dark body/text/border — all text white in dark mode */
    --bs-body-color: #ffffff;
    --bs-body-color-rgb: 255, 255, 255;
    --bs-body-bg: #0b1120;
    --bs-body-bg-rgb: 11, 17, 32;
    --bs-secondary-color: #ffffff;
    --bs-secondary-color-rgb: 255, 255, 255;
    --bs-tertiary-color: #ffffff;
    --bs-tertiary-color-rgb: 255, 255, 255;
    --bs-tertiary-bg: #1e293b;
    --bs-tertiary-bg-rgb: 30, 41, 59;
    --bs-border-color: #334155;
    --bs-emphasis-color: #ffffff;

    --warning-subtle: rgba(240, 160, 60, 0.16);

    /* Buildings sit against darker imagery in this theme and need to come down with it */
    --building-low:  #3c4757;
    --building-mid:  #556172;
    --building-high: #8894a6;

    /* App surfaces */
    --sidebar-bg: #0f172a;
    --sidebar-border: #1e293b;
    --card-bg: #1e293b;
}

/* ======================================
   Section 2: Base Reset & Typography
   ====================================== */
html {
    font-size: 16px;
    position: relative;
    min-height: 100%;
    scroll-behavior: smooth;
    font-optical-sizing: auto;
}

body {
    margin: 0;
    padding: 0;
    font-family: var(--bs-body-font-family);
    font-size: 0.9375rem;
    font-weight: 500;
    line-height: 1.6;
    background: var(--bs-body-bg);
    color: var(--bs-body-color);
    overflow-x: hidden;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6 { color: var(--bs-body-color); font-weight: 700; }
p, .lead { color: var(--bs-tertiary-color); font-weight: 500; }

a { color: var(--bs-primary); text-decoration: none; }
a:hover { color: var(--primary-hover, #1E5CF5); }

::selection {
    background: rgba(var(--bs-primary-rgb), 0.2);
    color: var(--bs-gray-900);
}

::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--bs-gray-300); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--bs-gray-400); }

/* ======================================
   Section 3: App Layout (Sidebar + Content, no top header)
   ====================================== */
.app {
    display: flex;
    min-height: 100vh;
}

/* ======================================
   Bootstrap 5 Tooltip Overrides
   ====================================== */
.tooltip {
    --bs-tooltip-bg: var(--bs-gray-800);
    --bs-tooltip-color: #fff;
    --bs-tooltip-border-radius: 6px;
    --bs-tooltip-padding-x: 8px;
    --bs-tooltip-padding-y: 3px;
    --bs-tooltip-font-size: 0.75rem;
    font-family: inherit;
    pointer-events: none;
}

.tooltip-inner {
    font-weight: 500;
    letter-spacing: 0.01em;
    max-width: 180px;
}

[data-bs-theme="dark"] .tooltip {
    --bs-tooltip-bg: var(--bs-gray-100);
    --bs-tooltip-color: var(--bs-gray-900);
}

/* Close button visibility in dark mode */
[data-bs-theme="dark"] .btn-close {
    filter: invert(1) grayscale(100%) brightness(200%);
}

/* form-select arrow — lighter stroke in dark mode */
[data-bs-theme="dark"] .form-select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}

/* ======================================
   Section 4: Header / Navbar (sticky top bar)
   ====================================== */
.header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 24px;
    background: var(--card-bg);
    border-bottom: 1px solid var(--bs-border-color);
    position: sticky;
    top: 0;
    z-index: 1030;
    height: 56px;
    min-height: 56px;
}

.header-left {
    display: flex;
    align-items: center;
    gap: 12px;
}

.header-toggle {
    width: 36px;
    height: 36px;
    border: none;
    background: transparent;
    color: var(--bs-body-color);
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 1.25rem;
    transition: all 0.2s ease;
}

.header-toggle:hover {
    background: var(--bs-gray-100);
    color: var(--bs-body-color);
}

.header-divider {
    width: 1px;
    height: 24px;
    background: var(--bs-gray-200);
}

.header-welcome {
    font-size: 0.875rem;
    color: var(--bs-tertiary-color);
    white-space: nowrap;
}

.header-welcome strong {
    color: var(--bs-body-color);
    font-weight: 600;
}

.header-right {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* User Section: name + role + Clerk avatar */
.user-section {
    display: flex;
    align-items: center;
    gap: 10px;
}

.user-info {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.2;
}

.user-name {
    font-size: 0.875rem;
    font-weight: 700;
    color: var(--bs-body-color);
    white-space: nowrap;
    letter-spacing: -0.01em;
}

.user-role {
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
    white-space: nowrap;
}

/* Avatar placeholder (shown before Clerk mounts UserButton) */
.avatar-placeholder {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--bs-primary);
}

/* Clerk UserButton mount target */
#clerk-user-button {
    display: flex;
    align-items: center;
    min-width: 32px;
    min-height: 32px;
}

.toolbar-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-inline-start: auto;
}

/* Page-specific toolbar elements (search, view toggles, etc.) */
.toolbar-search {
    display: flex;
    align-items: center;
    gap: 10px;
    background: var(--bs-gray-50);
    border: 1px solid var(--bs-border-color);
    border-radius: 10px;
    padding: 8px 16px;
    flex: 0 1 400px;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.toolbar-search:focus-within {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.1);
    background: var(--bs-body-bg);
}

.toolbar-search i {
    color: var(--bs-gray-400);
    font-size: 1rem;
    flex-shrink: 0;
}

.toolbar-search input {
    border: none;
    outline: none;
    background: transparent;
    color: var(--bs-gray-800);
    font-size: 0.9375rem;
    width: 100%;
    font-family: var(--bs-body-font-family);
}

.toolbar-search input::placeholder {
    color: var(--bs-gray-400);
}

/* View Toggle Buttons (grid / list) — used by Projects page */
.view-toggles {
    display: flex;
    align-items: center;
    background: var(--bs-gray-50);
    border: 1px solid var(--bs-border-color);
    border-radius: 8px;
    padding: 2px;
    gap: 2px;
}

.view-btn {
    width: 36px;
    height: 36px;
    border: none;
    background: transparent;
    color: var(--bs-tertiary-color);
    border-radius: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.15s ease;
    font-size: 1.1rem;
}

.view-btn:hover {
    color: var(--bs-body-color);
}

.view-btn.active {
    background: var(--bs-body-bg);
    color: var(--bs-gray-800);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

/* Auth Buttons */
.auth-buttons {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Tool Button (theme toggle, etc.) */
.tool-btn {
    width: 38px;
    height: 38px;
    border: none;
    background: transparent;
    color: var(--bs-tertiary-color);
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.2s ease;
    font-size: 1.2rem;
}

.tool-btn:hover {
    background: var(--bs-gray-100);
    color: var(--bs-body-color);
}

.tool-btn.active {
    background: rgba(var(--bs-primary-rgb), 0.12);
    color: var(--bs-primary);
}

/* ── Notification Bell & Panel ── */
.notification-wrapper {
    position: relative;
}

.notification-bell {
    position: relative;
}

.notification-badge {
    position: absolute;
    top: 4px;
    inset-inline-end: 3px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    font-size: 0.65rem;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
    color: #fff;
    background: var(--bs-danger);
    border-radius: 999px;
    pointer-events: none;
}

.notification-panel {
    position: absolute;
    top: calc(100% + 8px);
    inset-inline-end: 0;
    width: 360px;
    max-width: calc(100vw - 24px);
    max-height: 440px;
    background: var(--card-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 12px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
    z-index: 1050;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.notif-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 16px 10px;
    border-bottom: 1px solid var(--bs-border-color);
}

.notif-title {
    margin: 0;
    font-size: 0.9rem;
    font-weight: 700;
    color: var(--bs-body-color);
}

.notif-mark-all {
    border: none;
    background: none;
    color: var(--bs-primary);
    font-size: 0.75rem;
    font-weight: 600;
    cursor: pointer;
    padding: 2px 6px;
    border-radius: 6px;
    transition: background 0.15s;
}

.notif-mark-all:hover {
    background: rgba(var(--bs-primary-rgb), 0.08);
}

.notif-list {
    overflow-y: auto;
    flex: 1;
    max-height: 380px;
}

.notif-empty {
    padding: 32px 16px;
    text-align: center;
    color: var(--bs-secondary-color);
    font-size: 0.85rem;
}

/* Foot of the paged list: the spinner while the next page is in flight, and the line
   that says there is nothing older. Quieter than a row, because it is not one. */
.notif-foot {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 14px 16px;
    color: var(--bs-secondary-color);
    font-size: 0.75rem;
}

.notif-item {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 16px;
    cursor: pointer;
    transition: background 0.15s;
    border-bottom: 1px solid var(--bs-border-color);
}

.notif-item:last-child {
    border-bottom: none;
}

.notif-item:hover {
    background: var(--bs-gray-50);
}

.notif-item.unread {
    background: rgba(var(--bs-primary-rgb), 0.04);
}

.notif-item.unread:hover {
    background: rgba(var(--bs-primary-rgb), 0.08);
}

.notif-dot {
    flex-shrink: 0;
    width: 8px;
    height: 8px;
    margin-top: 6px;
    border-radius: 50%;
    background: transparent;
}

.notif-item.unread .notif-dot {
    background: var(--bs-primary);
}

.notif-content {
    flex: 1;
    min-width: 0;
}

.notif-item-title {
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--bs-body-color);
    margin-bottom: 2px;
}

.notif-msg {
    font-size: 0.78rem;
    color: var(--bs-secondary-color);
    line-height: 1.4;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.notif-time {
    font-size: 0.7rem;
    color: var(--bs-gray-400);
    margin-top: 4px;
}

/* ======================================
   Section 5: Left Sidebar (full height)
   ====================================== */
.sidebar {
    width: var(--sidebar-width);
    position: fixed;
    top: 0;
    inset-inline-start: 0;
    bottom: 0;
    background: var(--sidebar-bg);
    border-inline-end: 1px solid var(--sidebar-border);
    display: flex;
    flex-direction: column;
    transition: width 0.2s ease,
                transform 0.2s ease;
    overflow: hidden;
    z-index: 1040;
}

/* Sidebar Logo */
.sidebar-logo {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 6px 12px;
    text-decoration: none;
    overflow: hidden;
    border-radius: 0;
    border-bottom: 1px solid var(--bs-gray-100);
    min-height: 56px;
}

.sidebar-logo:hover {
    text-decoration: none;
}

/* ── Logo (cube mark + META4D wordmark) ──
   Two artworks: meta4d-logo-color-dark (white wordmark) and meta4d-logo-color (ink wordmark).
   Size each placement via font-size — 1em ≈ the cap height of META4D, since the
   lockup is about 2.9x taller than its wordmark once the cube mark sits beside it.
   Always-dark surfaces (sidebar, auth photo) render only the on-dark image. Surfaces that
   follow the theme add .logo--adaptive and carry both images. */
.logo {
    display: inline-flex;
    align-items: center;
    line-height: 0;
    transition: opacity 0.2s ease;
}
.logo img {
    display: block;
    height: 2.85em;
    width: auto;
    max-width: 100%;
    object-fit: contain;
}
/* Light is the default so a page that never stamps data-bs-theme still gets a readable wordmark */
.logo--adaptive .logo-on-dark { display: none; }
[data-bs-theme="dark"] .logo--adaptive .logo-on-dark { display: block; }
[data-bs-theme="dark"] .logo--adaptive .logo-on-light { display: none; }

/* Full logo (expanded sidebar) — 15px renders the artwork 43px tall, which with the logo box's
   6px padding lands on its 56px min-height, so the sidebar border stays level with .header. */
.logo-full {
    max-width: 100%;
    font-size: 15px;
}

/* Icon logo (collapsed sidebar) */
.logo-icon {
    display: none;
    width: 44px;
    height: 44px;
    object-fit: contain;
    transition: opacity 0.2s ease;
}

/* Dark theme */
[data-bs-theme="dark"] .sidebar-logo {
    background: transparent;
    border-bottom-color: var(--bs-gray-800);
}

/* Collapsed: swap full → icon */
.sidebar-collapsed .sidebar-logo {
    padding: 10px 0;
    justify-content: center;
}

.sidebar-collapsed .logo-full {
    display: none;
}

.sidebar-collapsed .logo-icon {
    display: none;
}

/* Sidebar Navigation */
.sidebar-nav {
    flex: 1;
    padding: 10px 12px;
    overflow-y: auto;
    overflow-x: hidden;
    display: flex;
    flex-direction: column;
}

.sidebar-nav-section {
    margin-bottom: 8px;
}

/* Footer utility zone (Support) — pinned to the bottom of the nav, divided from the rest */
.sidebar-nav-footer {
    margin-top: auto;
    margin-bottom: 0;
    padding-top: 6px;
    border-top: 1px solid var(--sidebar-border);
}
/* Compact footer row — Support is a utility, keep it low-profile */
.sidebar-nav-footer .sidebar-nav-item {
    padding-top: 7px;
    padding-bottom: 7px;
    margin-bottom: 0;
}

.sidebar-nav-label {
    font-size: 0.8125rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 1.2px;
    color: var(--primary, #2F6BFF);
    padding: 16px 14px 10px;
    white-space: nowrap;
    opacity: 1;
    transition: opacity 0.2s ease;
}

/* Plan Badge */
/* Plan Card Button (replaces static badge) */
.sidebar-plan-btn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 10px 12px;
    margin-bottom: 12px;
    border: 1px solid color-mix(in srgb, var(--bs-primary) 25%, transparent);
    border-radius: 10px;
    background: color-mix(in srgb, var(--bs-primary) 6%, transparent);
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
    text-align: start;
    gap: 6px;
}
.sidebar-plan-btn:hover {
    background: color-mix(in srgb, var(--bs-primary) 12%, transparent);
    border-color: color-mix(in srgb, var(--bs-primary) 40%, transparent);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
}
.sidebar-plan-name {
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--bs-primary);
    text-transform: uppercase;
    letter-spacing: 0.3px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sidebar-plan-hint {
    font-size: 0.6875rem;
    color: var(--bs-secondary-color);
    white-space: nowrap;
    display: flex;
    align-items: center;
    gap: 2px;
}
.sidebar-plan-hint i {
    font-size: 0.875rem;
    transition: transform 0.15s;
}
.sidebar-plan-btn:hover .sidebar-plan-hint i {
    transform: translateX(2px);
}
/* RTL: the nudge follows the reading direction; a flip-in-rtl arrow keeps its flip while it moves. */
html[dir="rtl"] .sidebar-plan-btn:hover .sidebar-plan-hint i {
    transform: translateX(-2px);
}
html[dir="rtl"] .sidebar-plan-btn:hover .sidebar-plan-hint i.flip-in-rtl {
    transform: scaleX(-1) translateX(2px);
}

/* Plan details modal — uses standard Bootstrap .modal classes now */
/* ── Plan Detail Modal ─────────────────────────────── */
.plan-modal {
    --plan-accent: var(--primary);
    border-radius: 20px; overflow: hidden; border: none;
    box-shadow: 0 24px 80px rgba(0,0,0,0.18);
}

/* Banner header — soft tinted, warm */
.plan-modal-banner {
    position: relative; overflow: hidden;
    background: var(--plan-banner-bg, #f0f4ff);
    padding: 28px 28px 24px;
}
.plan-banner-content {
    position: relative; z-index: 2;
    display: flex; align-items: center; gap: 16px;
    text-align: start;
}
.plan-banner-text { flex: 1; min-width: 0; }

/* Aurora/stars/noise — hidden on light banner */
.plan-banner-aurora, .plan-banner-aurora-2,
.plan-banner-stars, .plan-banner-noise { display: none; }

/* Close button */
.plan-modal-close {
    position: absolute; top: 14px; inset-inline-end: 14px; z-index: 10;
    width: 28px; height: 28px; border-radius: 8px;
    background: transparent; border: none;
    color: var(--bs-secondary-color); font-size: 1rem;
    display: flex; align-items: center; justify-content: center;
    cursor: pointer; transition: all 0.15s;
}
.plan-modal-close:hover {
    background: rgba(0,0,0,0.06); color: var(--bs-body-color);
}

/* Plan icon — tinted background */
.plan-modal-icon {
    position: relative; width: 52px; height: 52px; border-radius: 14px;
    background: var(--plan-accent, var(--primary));
    color: #fff; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 4px 14px rgba(var(--bs-primary-rgb), 0.25);
}
.plan-modal-icon svg { width: 30px; height: 30px; }
.plan-modal-icon-ring, .plan-modal-icon-ring-2 { display: none; }

/* Badge */
.plan-modal-badge {
    display: inline-block;
    font-size: 0.55rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: 1.2px; padding: 3px 10px; border-radius: 999px;
    background: var(--plan-accent, var(--primary)); color: #fff;
    margin-bottom: 6px;
}
/* Name + Tagline */
.plan-modal-name {
    font-size: 1.2rem; font-weight: 800; margin: 0 0 2px;
    color: var(--bs-emphasis-color); letter-spacing: -0.01em;
}
.plan-modal-tagline {
    font-size: 0.78rem; color: var(--bs-secondary-color);
    margin: 0; font-weight: 400; line-height: 1.4;
}

/* Storage bar */
.plan-banner-storage {
    position: relative; z-index: 2;
    margin-top: 14px; padding-top: 12px;
    border-top: 1px solid var(--bs-border-color-translucent);
}
.plan-banner-storage-row {
    display: flex; justify-content: space-between; align-items: center;
    margin-bottom: 6px;
}
.plan-banner-storage-label {
    font-size: 0.75rem; font-weight: 600; color: var(--bs-body-color);
}
.plan-banner-storage-pct {
    font-size: 0.7rem; font-weight: 700; color: var(--bs-secondary-color);
}
.plan-banner-storage-track {
    height: 5px; border-radius: 3px;
    background: var(--bs-secondary-bg);
    overflow: hidden;
}
.plan-banner-storage-fill {
    height: 100%; border-radius: 3px;
    background: var(--plan-accent, var(--primary));
    transition: width 0.4s ease;
}

/* Description */
.plan-modal-desc {
    font-size: 0.84rem; color: var(--bs-secondary-color);
    line-height: 1.5; padding: 20px 28px 0; margin: 0;
    text-align: center;
}

/* Feature pills */
.plan-modal-pills {
    display: flex; flex-wrap: wrap; gap: 10px;
    padding: 18px 28px 8px; justify-content: center;
}
.plan-pill {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 8px 16px; border-radius: 22px;
    font-size: 0.82rem; font-weight: 500;
    color: var(--bs-body-color);
    background: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color-translucent);
    /* GSAP handles entrance animation via animations.js §3 */
}
.plan-pill i {
    color: var(--plan-accent, #2F6BFF); font-size: 1rem;
}
/* plan-pill-in — migrated to GSAP (animations.js §3) */

/* Upgrade footer */
.plan-modal-footer {
    padding: 0 28px 24px;
    border-top: 1px solid var(--bs-border-color-translucent);
    margin-top: 8px;
}
.plan-modal-teaser {
    font-size: 0.7rem; color: var(--bs-secondary-color);
    text-align: center; margin: 16px 0 12px;
    line-height: 1.5;
    display: flex; align-items: center; justify-content: center; gap: 6px;
    flex-wrap: wrap;
}
.plan-modal-teaser strong { color: var(--bs-emphasis-color); }
.plan-modal-teaser i { font-size: 0.8rem; }
.plan-modal-upgrade-btn {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    width: 100%; padding: 12px; border-radius: 12px;
    font-size: 0.8125rem; font-weight: 600;
    color: #fff; background: var(--plan-accent);
    text-decoration: none; border: none; cursor: pointer;
    transition: all 0.2s ease;
}
.plan-modal-upgrade-btn i:last-child {
    margin-inline-start: auto;
    transition: transform 0.2s ease;
}
.plan-modal-upgrade-btn:hover {
    filter: brightness(1.08); transform: translateY(-1px);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
    color: #fff;
}
.plan-modal-upgrade-btn:hover i:last-child { transform: translateX(3px); }
html[dir="rtl"] .plan-modal-upgrade-btn:hover i:last-child { transform: translateX(-3px); }
html[dir="rtl"] .plan-modal-upgrade-btn:hover i.flip-in-rtl:last-child { transform: scaleX(-1) translateX(3px); }
.plan-modal-upgrade-btn:active { transform: scale(0.98); }

/* Dark mode */
[data-bs-theme="dark"] .plan-modal.modal-content { background: #1a1f2e !important; color: var(--bs-body-color); }
[data-bs-theme="dark"] .plan-modal-banner { background: #151926 !important; }
[data-bs-theme="dark"] .plan-modal .plan-modal-footer { border-color: var(--bs-gray-700); background: transparent; }
[data-bs-theme="dark"] .plan-modal .plan-modal-desc { color: var(--bs-gray-400); }
[data-bs-theme="dark"] .plan-modal .plan-modal-upgrade-btn { box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); }
[data-bs-theme="dark"] .plan-pill {
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.2);
    color: #f1f5f9;
}
[data-bs-theme="dark"] .plan-pill i {
    color: #60a5fa;
}
[data-bs-theme="dark"] .plan-modal-desc {
    color: #cbd5e1;
}
[data-bs-theme="dark"] .plan-modal-teaser {
    color: #94a3b8;
}
[data-bs-theme="dark"] .plan-modal-teaser strong {
    color: #f1f5f9;
}

/* Plan modal — compact on small screens */
@media (max-height: 680px) {
    .plan-modal-banner { padding: 16px 20px 12px; }
    .plan-banner-content { gap: 10px; }
    .plan-modal-icon { width: 36px; height: 36px; }
    .plan-modal-icon i, .plan-modal-icon svg { font-size: 1rem; width: 18px; height: 18px; }
    .plan-modal-name { font-size: 0.95rem; }
    .plan-modal-tagline { display: none; }
    .plan-banner-storage { margin-top: 8px; padding-top: 8px; }
    .plan-modal-desc { font-size: 0.75rem; padding: 10px 20px 0; }
    .plan-modal-pills { padding: 10px 20px 0; gap: 6px; }
    .plan-pill { padding: 4px 10px; font-size: 0.7rem; }
    .plan-modal-footer { padding: 0 20px 16px; }
    .plan-modal-teaser { margin: 10px 0 8px; }
}

/* ── Upgrade Comparison Table ─────────────────────── */
.upgrade-compare { padding: 0 24px 4px; }
.cmp-header {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    padding: 10px 0 8px;
    border-bottom: 1px solid var(--bs-border-color-translucent);
}
.cmp-label-col { }
.cmp-col {
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    text-align: center;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
}
.cmp-col--current { color: var(--bs-secondary-color); }
.cmp-col--new {
    color: var(--bs-primary);
    background: rgba(var(--bs-primary-rgb), 0.06);
    border-radius: 6px 6px 0 0;
    padding: 0 6px;
}
.cmp-col-inner { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.cmp-price-chip {
    font-size: 0.68rem; font-weight: 700; color: var(--bs-primary);
    background: rgba(var(--bs-primary-rgb), 0.13); padding: 1px 7px;
    border-radius: 999px; white-space: nowrap;
}
.cmp-new-badge {
    font-size: 0.6rem;
    font-weight: 700;
    background: var(--bs-primary);
    color: #fff;
    padding: 1px 5px;
    border-radius: 4px;
    letter-spacing: 0.5px;
}
.cmp-row {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    align-items: center;
    padding: 7px 0;
    border-bottom: 1px solid var(--bs-border-color-translucent);
}
.cmp-row:last-child { border-bottom: none; }
.cmp-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8rem;
    color: var(--bs-body-color);
}
.cmp-label i { font-size: 0.85rem; color: var(--bs-secondary-color); }
.cmp-cell { text-align: center; font-size: 0.8125rem; }
.cmp-cell--current { color: var(--bs-secondary-color); }
.cmp-cell--new {
    color: var(--bs-primary); font-weight: 600;
    background: rgba(var(--bs-primary-rgb), 0.05);
}
.cmp-check { color: var(--bs-success); font-size: 1rem; }
.cmp-check--new { color: var(--bs-primary); }
.cmp-cross { color: var(--bs-secondary-color); font-size: 1rem; opacity: 0.5; }
/* Delta improvement chip — green so it contrasts against the blue new-column */
.cmp-delta {
    display: inline-flex; align-items: center; gap: 2px;
    font-size: 0.6rem; font-weight: 700; vertical-align: middle;
    background: rgba(34,197,94,0.13); color: #16a34a;
    padding: 1px 5px; border-radius: 4px; margin-inline-start: 4px;
}
.cmp-delta i { font-size: 0.6rem; }
[data-bs-theme="dark"] .cmp-delta { background: rgba(34,197,94,0.18); color: #4ade80; }
/* "NEW" badge on gained features */
.cmp-new-feat-badge {
    display: inline-block; font-size: 0.55rem; font-weight: 700;
    background: var(--bs-success); color: #fff;
    padding: 1px 5px; border-radius: 4px; margin-inline-start: 3px;
    vertical-align: middle; letter-spacing: 0.3px;
}

/* ── Upgrade Card Note (paid→paid footer line) ────── */
.upgrade-card-note {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.775rem;
    color: var(--bs-secondary-color);
    margin: 0 0 10px;
}
.upgrade-card-note i { font-size: 0.875rem; }
.upgrade-card-note-link {
    color: var(--bs-primary);
    text-decoration: none;
    font-weight: 500;
    margin-inline-start: 2px;
}
.upgrade-card-note-link:hover { text-decoration: underline; }

/* Billing period note in downgrade footer */
.dg-billing-note {
    display: flex; align-items: flex-start; gap: 7px;
    font-size: 0.75rem; color: var(--bs-secondary-color);
    margin-bottom: 12px; line-height: 1.4;
}
.dg-billing-note i { color: #d97706; flex-shrink: 0; margin-top: 1px; }

/* ── Downgrade comparison — amber variant of cmp-col/cell ── */
.cmp-col--dg-new {
    color: #d97706;
    background: rgba(217,119,6,0.07);
    border-radius: 6px 6px 0 0;
    padding: 0 6px;
}
.cmp-cell--dg-new {
    color: #d97706; font-weight: 600;
    background: rgba(217,119,6,0.05);
    text-align: center; font-size: 0.8125rem;
}

[data-bs-theme="dark"] .cmp-col--new { background: rgba(var(--bs-primary-rgb), 0.1); }
[data-bs-theme="dark"] .cmp-cell--new { background: rgba(var(--bs-primary-rgb), 0.08); }
[data-bs-theme="dark"] .cmp-price-chip { background: rgba(var(--bs-primary-rgb), 0.2); }
[data-bs-theme="dark"] .cmp-delta { background: rgba(var(--bs-primary-rgb), 0.2); }
[data-bs-theme="dark"] .cmp-col--dg-new { background: rgba(217,119,6,0.12); }
[data-bs-theme="dark"] .cmp-cell--dg-new { background: rgba(217,119,6,0.08); }
[data-bs-theme="dark"] .cmp-row { border-color: var(--bs-border-color-translucent); }
[data-bs-theme="dark"] .cmp-header { border-color: var(--bs-border-color-translucent); }

/* Storage Widget */
.sidebar-storage {
    padding: 12px 16px 14px;
    border-top: 1px solid var(--sidebar-border);
    white-space: nowrap;
    overflow: hidden;
}

.storage-header {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 8px;
}

.storage-header i {
    font-size: 1rem;
    color: var(--bs-tertiary-color);
}

.storage-title {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--bs-body-color);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.storage-pct {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--bs-body-color);
    margin-inline-start: auto;
}

.storage-bar {
    width: 100%;
    height: 5px;
    background: var(--bs-gray-200);
    border-radius: 3px;
    overflow: hidden;
    margin-bottom: 5px;
}

.storage-fill {
    height: 100%;
    background: var(--bs-primary);
    border-radius: 3px;
    transition: width 0.3s ease, background 0.3s ease;
}

.storage-fill.danger {
    background: var(--bs-danger);
}

/* Over-quota percent label — replaces "X%" with "OVER QUOTA" */
.storage-pct.storage-pct--over {
    color: var(--bs-danger);
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.04em;
}

/* ── Over-Quota Site-Wide Banner ──────────────────────
   Shown below the header on every page when org storage is over the plan limit.
   Dismissible per-session; reappears on full page reload while state persists. */
.overquota-banner {
    display: flex;
    align-items: center;
    gap: 14px;
    padding-block: 12px;
    padding-inline: 18px 44px;
    background: linear-gradient(135deg, rgba(var(--bs-warning-rgb), 0.12) 0%, rgba(var(--bs-warning-rgb), 0.04) 100%);
    border-bottom: 1px solid rgba(var(--bs-warning-rgb), 0.35);
    position: relative;
    font-size: 0.8125rem;
    animation: overQuotaSlide 0.3s ease-out;
}
@keyframes overQuotaSlide {
    from { opacity: 0; transform: translateY(-6px); }
    to { opacity: 1; transform: translateY(0); }
}
.overquota-icon {
    width: 32px;
    height: 32px;
    border-radius: 8px;
    background: rgba(var(--bs-warning-rgb), 0.2);
    color: var(--bs-warning);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
    flex-shrink: 0;
}
.overquota-body { flex: 1; min-width: 0; }
.overquota-title {
    font-weight: 700;
    color: var(--bs-body-color);
    line-height: 1.3;
    letter-spacing: -0.01em;
}
.overquota-text {
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
    line-height: 1.3;
    margin-top: 1px;
}
.overquota-text strong { color: var(--bs-body-color); font-weight: 600; }
.overquota-actions {
    display: flex;
    gap: 8px;
    flex-shrink: 0;
}
.overquota-btn {
    white-space: nowrap;
    font-weight: 600;
    padding: 0.35rem 0.75rem;
    font-size: 0.75rem;
    border-radius: 8px;
}
.overquota-note {
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--bs-secondary-color);
}
.overquota-close {
    position: absolute;
    top: 8px;
    inset-inline-end: 12px;
    width: 20px;
    height: 20px;
    padding: 0;
    font-size: 0.5rem;
    opacity: 0.5;
    border-radius: 5px;
    transition: opacity 0.15s ease, background 0.15s ease;
}
.overquota-close:hover {
    opacity: 1;
    background: rgba(var(--bs-body-color-rgb, 33, 37, 41), 0.08);
}
/* Responsive stacking */
@media (max-width: 767px) {
    .overquota-banner {
        flex-wrap: wrap;
        padding-inline-end: 40px;
    }
    .overquota-actions { width: 100%; margin-top: 4px; }
    .overquota-btn { flex: 1; }
}
/* ── Free Space Modal ──────────────────────────────── */
.storage-tree-project-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px;
    border-bottom: 1px solid var(--bs-border-color-translucent);
    transition: background 0.12s;
}
.storage-tree-project-row:last-child { border-bottom: none; }
.storage-tree-project-row:hover { background: rgba(var(--bs-danger-rgb), 0.03); }
.storage-tree-project-info { flex: 1; min-width: 0; }
.storage-tree-project-name {
    font-weight: 600;
    font-size: 0.8125rem;
    color: var(--bs-body-color);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.storage-tree-project-meta {
    font-size: 0.6875rem;
    color: var(--bs-secondary-color);
    margin-top: 1px;
}
.storage-tree-project-right {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
}
.storage-tree-project-size {
    font-size: 0.8125rem;
    font-weight: 700;
    color: var(--bs-body-color);
    min-width: 60px;
    text-align: end;
}
.storage-tree-delete-btn {
    width: 30px; height: 30px;
    padding: 0;
    display: flex; align-items: center; justify-content: center;
    border-radius: 8px;
    font-size: 0.875rem;
}
/* Expandable project row */
.storage-tree-expandable { cursor: pointer; }
.storage-tree-expandable:hover { background: rgba(var(--bs-primary-rgb), 0.03); }
.storage-tree-expand-icon {
    font-size: 1rem;
    color: var(--bs-secondary-color);
    flex-shrink: 0;
    transition: transform 0.15s;
}
/* Dataset sub-rows (indented) */
.storage-tree-dataset-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-block: 8px;
    padding-inline: 36px 16px;
    border-bottom: 1px dashed var(--bs-border-color-translucent);
    background: var(--bs-tertiary-bg);
}
.storage-tree-dataset-row:last-child { border-bottom: none; }
.storage-tree-dataset-row:hover { background: rgba(var(--bs-danger-rgb), 0.04); }
.storage-tree-dataset-name {
    font-weight: 500;
    font-size: 0.75rem;
    color: var(--bs-body-color);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Dark mode */
[data-bs-theme="dark"] .overquota-banner {
    background: linear-gradient(135deg, rgba(var(--bs-warning-rgb), 0.16) 0%, rgba(var(--bs-warning-rgb), 0.05) 100%);
    border-bottom-color: rgba(var(--bs-warning-rgb), 0.4);
}
[data-bs-theme="dark"] .overquota-icon {
    background: rgba(var(--bs-warning-rgb), 0.22);
}
/* Free Space button — works in both light + dark */
.btn-free-space {
    color: #1e293b;
    background: rgba(255, 255, 255, 0.7);
    border: 1px solid rgba(0, 0, 0, 0.15);
    backdrop-filter: blur(4px);
}
.btn-free-space:hover {
    background: rgba(255, 255, 255, 0.9);
    color: #0f172a;
}
[data-bs-theme="dark"] .btn-free-space {
    color: #f1f5f9;
    background: rgba(255, 255, 255, 0.1);
    border-color: rgba(255, 255, 255, 0.25);
}
[data-bs-theme="dark"] .btn-free-space:hover {
    background: rgba(255, 255, 255, 0.2);
    color: #fff;
}

.storage-info {
    display: flex;
    justify-content: space-between;
    font-size: 0.6875rem;
    font-weight: 500;
    color: var(--bs-tertiary-color);
    text-transform: uppercase;
    letter-spacing: 0.3px;
}


.sidebar-nav-list {
    list-style: none;
    padding: 0;
    margin: 0;
}

.sidebar-nav-item {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 14px;
    color: var(--bs-body-color);
    text-decoration: none;
    border-radius: 8px;
    white-space: nowrap;
    position: relative;
    margin-bottom: 4px;
    transition: color 0.2s ease, transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
    z-index: 1;
}

/* Gooey blob background — scales up smoothly behind the item */
.sidebar-nav-item::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 8px;
    background: transparent;
    transform: scale(0.92);
    opacity: 0;
    transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1),
                opacity 0.2s ease,
                background 0.2s ease;
    z-index: -1;
}

.sidebar-nav-item:hover {
    color: var(--bs-body-color);
    text-decoration: none;
}

.sidebar-nav-item:hover::before {
    background: var(--bs-gray-100);
    transform: scale(1);
    opacity: 1;
}

/* Icon lift on hover */
.sidebar-nav-item:hover i {
    transform: scale(1.08);
}

/* Active state */
.sidebar-nav-item.active {
    color: var(--bs-primary);
    font-weight: 600;
}

.sidebar-nav-item.active::before {
    background: rgba(var(--bs-primary-rgb), 0.08);
    transform: scale(1);
    opacity: 1;
}

.sidebar-nav-item i {
    font-size: 1.3rem;
    width: 24px;
    text-align: center;
    flex-shrink: 0;
    color: var(--bs-body-color);
    transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.sidebar-nav-item.active i {
    color: var(--bs-primary);
}

.sidebar-nav-item span {
    font-size: 1rem;
    font-weight: 500;
    opacity: 1;
    transition: opacity 0.2s ease;
}

/* User profile — pinned to sidebar bottom */
.sidebar-bottom {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 14px;
    border-top: 1px solid var(--sidebar-border);
    white-space: nowrap;
    overflow: hidden;
}

.sidebar-user {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1;
    min-width: 0;
    overflow: hidden;
}

.user-avatar-sm {
    width: 36px;
    height: 36px;
    min-width: 36px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--bs-primary), var(--primary-hover));
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.9375rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.user-info {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    opacity: 1;
    transition: opacity 0.2s ease;
    min-width: 0;
}

.user-name {
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--bs-body-color);
    overflow: hidden;
    text-overflow: ellipsis;
    line-height: 1.3;
}

.user-role {
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--bs-tertiary-color);
    text-transform: capitalize;
    line-height: 1.3;
}


/* ======================================
   Section 6: Sidebar Collapsed State
   ====================================== */
.sidebar-collapsed .sidebar {
    width: var(--sidebar-collapsed-width);
}

/* Nav: hide labels and text */
.sidebar-collapsed .sidebar-nav-label,
.sidebar-collapsed .sidebar-nav-item span {
    opacity: 0;
    pointer-events: none;
    width: 0;
    overflow: hidden;
}

.sidebar-collapsed .sidebar-nav-item {
    justify-content: center;
    padding: 10px;
    gap: 0;
}

.sidebar-collapsed .sidebar-nav-item:hover {
    transform: none;
}

.sidebar-collapsed:not([data-page="map"]) .main {
    margin-inline-start: var(--sidebar-collapsed-width);
    max-width: calc(100vw - var(--sidebar-collapsed-width));
}

/* Storage: hide everything except just the icon */
.sidebar-collapsed .sidebar-storage {
    padding: 10px 8px;
    text-align: center;
}

.sidebar-collapsed .sidebar-plan-btn,
.sidebar-collapsed .storage-title,
.sidebar-collapsed .storage-pct,
.sidebar-collapsed .storage-bar,
.sidebar-collapsed .storage-info {
    display: none;
}

.sidebar-collapsed .storage-header {
    justify-content: center;
    margin-bottom: 0;
}

/* Bottom: hide user info and sign-out */
.sidebar-collapsed .sidebar-bottom {
    justify-content: center;
    padding: 12px 8px;
}

.sidebar-collapsed .sidebar-bottom .user-info {
    opacity: 0;
    pointer-events: none;
    width: 0;
    min-width: 0;
    overflow: hidden;
}

/* Collapsed tooltips */
.sidebar-collapsed .sidebar-nav-item {
    position: relative;
}

.sidebar-collapsed .sidebar-nav-item::after {
    content: attr(data-tooltip);
    position: absolute;
    inset-inline-start: calc(100% + 10px);
    top: 50%;
    transform: translateY(-50%);
    width: auto;
    height: auto;
    background: var(--card-bg);
    color: var(--bs-gray-800);
    padding: 5px 12px;
    border-radius: 6px;
    font-size: 0.8125rem;
    font-weight: 500;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
    z-index: 1050;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
    border: 1px solid var(--sidebar-border);
}

.sidebar-collapsed .sidebar-nav-item:hover::after {
    opacity: 1;
}

.sidebar-collapsed .user-avatar-sm {
    position: relative;
}

.sidebar-collapsed .user-avatar-sm::after {
    content: attr(data-tooltip);
    position: absolute;
    inset-inline-start: calc(100% + 10px);
    top: 50%;
    transform: translateY(-50%);
    background: var(--card-bg);
    color: var(--bs-gray-800);
    padding: 5px 12px;
    border-radius: 6px;
    font-size: 0.8125rem;
    font-weight: 500;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
    z-index: 1050;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
    border: 1px solid var(--sidebar-border);
}

.sidebar-collapsed .user-avatar-sm:hover::after {
    opacity: 1;
}

/* ======================================
   Section 6b: Dark Theme
   ====================================== */
/* Dark mode variable overrides are in the :root block at the top of this file */

/* Sidebar dark overrides */
[data-bs-theme="dark"] .sidebar-nav-item {
    color: var(--bs-gray-400);
}

[data-bs-theme="dark"] .sidebar-nav-item:hover {
    color: var(--bs-gray-900);
}

[data-bs-theme="dark"] .sidebar-nav-item:hover::before {
    background: rgba(255, 255, 255, 0.06);
}

[data-bs-theme="dark"] .sidebar-nav-item.active {
    color: var(--bs-primary);
}

[data-bs-theme="dark"] .sidebar-nav-item.active::before {
    background: rgba(var(--bs-primary-rgb), 0.15);
}

[data-bs-theme="dark"] .sidebar-nav-label {
    color: var(--bs-primary);
}

[data-bs-theme="dark"] .user-name {
    color: var(--bs-gray-800);
}

[data-bs-theme="dark"] .user-role {
    color: var(--bs-gray-600);
}

[data-bs-theme="dark"] .storage-title,
[data-bs-theme="dark"] .storage-header i {
    color: var(--bs-gray-600);
}

[data-bs-theme="dark"] .storage-pct {
    color: var(--bs-gray-800);
}

[data-bs-theme="dark"] .storage-bar {
    background: var(--bs-gray-300);
}

[data-bs-theme="dark"] .storage-info {
    color: var(--bs-gray-700);
}

[data-bs-theme="dark"] .sidebar-plan-btn {
    background: color-mix(in srgb, var(--bs-primary) 10%, transparent);
    border-color: color-mix(in srgb, var(--bs-primary) 30%, transparent);
}
[data-bs-theme="dark"] .sidebar-plan-btn:hover {
    background: color-mix(in srgb, var(--bs-primary) 18%, transparent);
    border-color: color-mix(in srgb, var(--bs-primary) 45%, transparent);
}
/* Plan detail modal dark overrides handled by standard .modal-content rules */

/* Sidebar light-mode overrides — the sidebar is dark navy in both themes, so
   mirror the dark-mode text treatment when the app is in light mode. Colors are
   the resolved dark-theme gray values so both modes look identical. */
[data-bs-theme="light"] .sidebar-nav-item {
    color: #cbd5e1;
}
[data-bs-theme="light"] .sidebar-nav-item:hover {
    color: #f1f5f9;
}
[data-bs-theme="light"] .sidebar-nav-item:hover::before {
    background: rgba(255, 255, 255, 0.06);
}
[data-bs-theme="light"] .sidebar-nav-item.active {
    color: var(--bs-primary);
}
[data-bs-theme="light"] .sidebar-nav-item.active::before {
    background: rgba(var(--bs-primary-rgb), 0.15);
}
[data-bs-theme="light"] .sidebar-nav-item i {
    color: #cbd5e1;
}
[data-bs-theme="light"] .sidebar-nav-item.active i {
    color: var(--bs-primary);
}
[data-bs-theme="light"] .sidebar-nav-label {
    color: var(--bs-primary);
}
/* The user block sits in the topbar, which is light in this theme -- the near-white values
   these carried were left over from when it lived in the always-dark sidebar below. Same
   Slate tokens as the dark rules, which invert on their own. */
[data-bs-theme="light"] .user-name {
    color: var(--bs-gray-800);
}
[data-bs-theme="light"] .user-role {
    color: var(--bs-gray-600);
}
[data-bs-theme="light"] .storage-title,
[data-bs-theme="light"] .storage-header i {
    color: #94a3b8;
}
[data-bs-theme="light"] .storage-pct {
    color: #e2e8f0;
}
[data-bs-theme="light"] .storage-bar {
    background: #334155;
}
[data-bs-theme="light"] .storage-info {
    color: #cbd5e1;
}
[data-bs-theme="light"] .sidebar-logo {
    border-bottom-color: #1e293b;
}

/* Header / Navbar dark overrides */
[data-bs-theme="dark"] .header {
    background: var(--bs-gray-100);
    border-bottom-color: var(--bs-gray-300);
}

[data-bs-theme="dark"] .header-toggle {
    color: var(--bs-gray-700);
}

[data-bs-theme="dark"] .header-toggle:hover {
    background: rgba(255, 255, 255, 0.08);
    color: var(--bs-gray-900);
}

[data-bs-theme="dark"] .header-divider {
    background: var(--bs-gray-400);
}

[data-bs-theme="dark"] .header-welcome {
    color: var(--bs-gray-600);
}

[data-bs-theme="dark"] .header-welcome strong {
    color: var(--bs-gray-800);
}

/* Toolbar search dark overrides */
[data-bs-theme="dark"] .toolbar-search {
    background: rgba(255, 255, 255, 0.05);
    border-color: var(--bs-gray-300);
}

[data-bs-theme="dark"] .toolbar-search:focus-within {
    background: rgba(255, 255, 255, 0.08);
}

[data-bs-theme="dark"] .toolbar-search input {
    color: var(--bs-gray-300);
}

[data-bs-theme="dark"] .view-toggles {
    background: rgba(255, 255, 255, 0.05);
    border-color: var(--bs-gray-300);
}

[data-bs-theme="dark"] .view-btn.active {
    background: var(--bs-gray-300);
    color: var(--bs-emphasis-color);
}

[data-bs-theme="dark"] .tool-btn {
    color: var(--bs-gray-700);
}

[data-bs-theme="dark"] .tool-btn:hover {
    background: rgba(255, 255, 255, 0.08);
    color: var(--bs-gray-900);
}

/* Notification panel dark overrides */
[data-bs-theme="dark"] .notification-panel {
    background: var(--bs-gray-100);
    border-color: var(--bs-gray-300);
    box-shadow: 0 8px 24px rgba(0,0,0,0.3);
}

[data-bs-theme="dark"] .notif-header {
    border-bottom-color: var(--bs-gray-300);
}

[data-bs-theme="dark"] .notif-item {
    border-bottom-color: var(--bs-gray-300);
}

[data-bs-theme="dark"] .notif-item:hover {
    background: rgba(255,255,255,0.04);
}

[data-bs-theme="dark"] .notif-item.unread {
    background: rgba(var(--bs-primary-rgb), 0.06);
}

[data-bs-theme="dark"] .notif-item.unread:hover {
    background: rgba(var(--bs-primary-rgb), 0.1);
}

/* ======================================
   Section 7: Main Content Area
   ====================================== */
.main {
    flex: 1;
    margin-inline-start: var(--sidebar-width);
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-width: 0;
    max-width: calc(100vw - var(--sidebar-width));
    transition: margin 0.2s ease,
                max-width 0.2s ease;
}

/* Full-width main — sidebar hidden (signup checkout flow) */
.main--full {
    margin-inline-start: 0 !important;
    max-width: 100vw !important;
}
.checkout-logo {
    display: flex;
    align-items: center;
}
.checkout-logo img {
    height: 40px;
}

/* When right toolbar is present */
.app.has-right-toolbar .main {
    margin-inline-end: var(--right-toolbar-width);
}

/* Content area */
.content {
    flex: 1;
    padding: 24px;
    min-width: 0;
    background: var(--bs-body-bg);
    color: var(--bs-gray-900);
    /* Global safeguard: long unbroken strings (IDs, URLs, emails) wrap instead of
       overflowing their container. overflow-wrap inherits to all descendants. */
    overflow-wrap: break-word;
}

.content h1,
.content h2,
.content h3,
.content h4,
.content h5,
.content h6 {
    color: var(--bs-body-color);
}

.content p {
    color: var(--bs-tertiary-color);
}

/* ======================================
   Section 8: Right Toolbar
   ====================================== */
.right-toolbar {
    position: fixed;
    top: 0;
    inset-inline-end: 0;
    width: var(--right-toolbar-width);
    height: 100vh;
    background: var(--sidebar-bg);
    border-inline-start: 1px solid var(--sidebar-border);
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 12px 0;
    z-index: 1020;
    gap: 6px;
}

.tool-divider {
    width: 28px;
    height: 1px;
    background: var(--sidebar-border);
    margin: 6px 0;
}

.tool-spacer {
    flex: 1;
}

/* ======================================
   Section 9: Footer
   ====================================== */
.footer {
    padding: 16px 24px;
    border-top: 1px solid var(--bs-border-color);
    color: var(--bs-tertiary-color);
    font-size: 0.875rem;
    font-weight: 500;
    background: var(--bs-body-bg);
}

.footer a { color: var(--bs-body-color); }
.footer a:hover { color: var(--bs-primary); }

/* ======================================
   Section 10: Bootstrap Component Overrides (Light Content Area)
   ====================================== */

/* Forms */
.form-control,
.form-select {
    background-color: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    color: var(--bs-gray-900);
}

.form-select {
    background: var(--bs-body-bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 0.75rem center / 16px 16px;
    padding-inline-end: 2.25rem;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
}

.form-control:focus,
.form-select:focus {
    background-color: var(--bs-body-bg);
    border-color: var(--bs-primary);
    color: var(--bs-gray-900);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.15);
}

.form-select:focus {
    background: var(--bs-body-bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%232F6BFF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 0.75rem center / 16px 16px;
}
/* The background shorthands above pin the chevron right; in RTL it moves left with the padding. */
html[dir="rtl"] .form-select,
html[dir="rtl"] .form-select:focus {
    background-position: left 0.75rem center;
}

.form-control::placeholder { color: var(--bs-gray-400); }
.form-label { color: var(--bs-body-color); font-weight: 600; }

/* ── Form controls dark mode ──────────────────────────── */
[data-bs-theme="dark"] .form-control,
[data-bs-theme="dark"] .form-select {
    background-color: var(--bs-gray-100);
    border-color: var(--bs-gray-300);
    color: var(--bs-gray-900);
}
[data-bs-theme="dark"] .form-control:focus,
[data-bs-theme="dark"] .form-select:focus {
    background-color: var(--bs-gray-100);
    border-color: var(--bs-primary);
}
[data-bs-theme="dark"] .form-select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}
[data-bs-theme="dark"] .form-control::placeholder {
    color: var(--bs-gray-500);
}

.input-group-text {
    background: var(--bs-body-bg);
    border-color: var(--bs-border-color);
    color: var(--bs-gray-600);
}

/* Buttons — keep Bootstrap 5.3 defaults */

.btn:focus,
.btn:active:focus,
.btn-link.nav-link:focus,
.form-control:focus,
.form-check-input:focus {
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.15);
}

/* Bootstrap Button Color Overrides — brand colour comes from the tokens defined in :root, never
   re-typed as hex here. A second copy of the hex is a rebrand waiting to go half-finished. */
.btn-primary {
    background-color: var(--primary);
    border-color: var(--primary);
    color: #fff;
}

.btn-primary:hover,
.btn-primary:active,
.btn-primary:first-child:active {
    background-color: var(--primary-hover);
    border-color: var(--primary-hover);
    color: #fff;
}

.btn-primary:focus {
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.3);
}

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

.btn-outline-primary:hover,
.btn-outline-primary:active {
    background-color: var(--primary);
    border-color: var(--primary);
    color: #fff;
}

.btn-outline-secondary {
    color: var(--bs-body-color);
    border-color: var(--bs-border-color);
}

/* Was --bs-tertiary-bg, which is #ffffff in light mode — i.e. the same colour as the card behind
   it, so the button had no perceptible hover at all. gray-100 is the tint .sidebar-nav-item already
   uses for hover, and it flips correctly in dark. */
.btn-outline-secondary:hover {
    background: var(--bs-gray-100);
    border-color: var(--bs-border-color);
    color: var(--bs-body-color);
}

.btn-outline-danger {
    color: #dc3545;
    border-color: #dc3545;
}

.btn-outline-danger:hover {
    background: #dc3545;
    border-color: #dc3545;
    color: #fff;
}

/* Override Bootstrap primary utilities */
.text-primary {
    color: var(--bs-primary) !important;
}

.bg-primary {
    background-color: var(--bs-primary) !important;
    color: #fff !important;
}

/* Bootstrap Pagination Override */
.page-item.active .page-link {
    background-color: var(--bs-primary);
    border-color: var(--bs-primary);
    color: #fff;
}

.page-link {
    color: var(--bs-primary);
}

.page-link:hover {
    color: var(--primary-hover);
}

/* Links inside content area */
.content a:not(.sidebar-nav-item):not(.header-link):not(.btn):not(.org-social-icon):not(.pj-proj-link) {
    color: var(--bs-primary);
}

.content a:not(.sidebar-nav-item):not(.header-link):not(.btn):not(.org-social-icon):not(.pj-proj-link):hover {
    color: var(--primary-hover);
}

/* ── Page Loader — centered full-content spinner ── */
/* Page and panel loaders: .page-loader in brand-loader.css (Shared/_PageLoader, page-loader.js). */

/* ── Modals — unified design system ──────────────── */
.modal {
    --bs-modal-bg: var(--card-bg);
    --bs-modal-color: var(--bs-gray-900);
    --bs-modal-border-color: transparent;
    --bs-body-bg: var(--card-bg);
    --bs-body-color: var(--bs-gray-900);
}

.modal-content {
    background: var(--card-bg);
    border: 1px solid var(--bs-border-color);
    color: var(--bs-body-color);
    border-radius: 12px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.12);
    overflow: hidden;
    max-height: calc(100vh - 3.5rem);
    display: flex;
    flex-direction: column;
}
[data-bs-theme="dark"] .modal-content {
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
}

.modal-header {
    border-bottom: 1px solid var(--bs-gray-100);
    padding: 24px 24px 16px;
    background: var(--bs-gray-50);
}

.modal-title {
    color: var(--bs-body-color);
    font-weight: 700;
    font-size: 1.25rem;
    line-height: 1.3;
}

.modal-title i {
    color: var(--bs-secondary-color);
    font-size: 1.1em;
}

.modal-body {
    padding: 20px 24px;
    overflow-y: auto;
    flex: 1 1 auto;
}

/* Uniform vertical rhythm for form groups inside modals */
.modal-body > div + div {
    margin-top: 14px;
}
.modal-body > div:last-child {
    margin-bottom: 0;
}

/* Textareas in modals — expandable vertically */
.modal textarea.form-control {
    resize: vertical;
    min-height: 60px;
    max-height: 200px;
}

.modal-footer {
    border-top: 1px solid var(--bs-gray-100);
    padding: 16px 24px 24px;
    gap: 12px;
    background: var(--bs-gray-50);
}

.btn-close {
    filter: none;
    opacity: 0.4;
    transition: opacity 0.15s;
}

.btn-close:hover {
    opacity: 0.8;
}
[data-bs-theme="dark"] .btn-close {
    filter: invert(1) grayscale(100%) brightness(200%);
}

/* Modal form controls */
.modal .form-label {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--bs-body-color);
    margin-bottom: 6px;
}

.modal .form-control,
.modal .form-select {
    background-color: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 10px;
    padding: 10px 14px;
    font-size: 0.9375rem;
    color: var(--bs-gray-900);
    transition: border-color 0.2s, box-shadow 0.2s;
}
.modal .form-control:disabled,
.modal .form-control[readonly]:disabled {
    background-color: var(--bs-gray-50);
}

.modal .form-control:focus,
.modal .form-select:focus {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.12);
}

.modal .form-control::placeholder {
    color: var(--bs-secondary-color);
    font-weight: 400;
}

/* Input-group inside modals — match form-control styling */
.modal .input-group .input-group-text {
    background-color: var(--bs-gray-50);
    border: 1px solid var(--bs-border-color);
    font-size: 0.9375rem;
    padding: 10px 12px;
}
.modal .input-group .input-group-text:first-child {
    border-start-start-radius: 10px;
    border-start-end-radius: 0;
    border-end-end-radius: 0;
    border-end-start-radius: 10px;
}
.modal .input-group .form-control:last-child {
    border-start-start-radius: 0;
    border-start-end-radius: 10px;
    border-end-end-radius: 10px;
    border-end-start-radius: 0;
}


/* ── Custom Multi-Select (category dropdown) ──────── */
.multi-select { position: relative; }
.multi-select-tags {
    display: flex; flex-wrap: wrap; gap: 4px; align-items: center;
    min-height: 42px; padding: 6px 12px;
    border: 1px solid var(--bs-border-color); border-radius: 10px;
    background: var(--bs-body-bg); cursor: pointer;
}
.multi-select-placeholder { color: var(--bs-secondary-color); font-size: 0.875rem; }
.multi-select-tags:focus-within .multi-select-placeholder { display: none; }
.multi-select-tag {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 2px 8px; border-radius: 6px; font-size: 0.8125rem;
    background: var(--bs-primary); color: #fff;
}
.multi-select-tag-remove {
    border: none; background: none; color: #fff; font-size: 1rem;
    cursor: pointer; padding: 0 2px; line-height: 1; opacity: 0.7;
}
.multi-select-tag-remove:hover { opacity: 1; }
.multi-select-input {
    border: none; outline: none; background: transparent;
    font-size: 0.8125rem; color: var(--bs-body-color);
    min-width: 2px; width: 2px; padding: 0; margin: 0;
    flex: 0 0 auto;
}
.multi-select-input:focus { flex: 1 1 40px; min-width: 40px; }
.multi-select-dropdown {
    position: absolute; top: calc(100% + 4px); inset-inline-start: 0; inset-inline-end: 0;
    background: var(--bs-body-bg); border: 1px solid var(--bs-border-color);
    border-radius: 10px; padding: 6px; z-index: 1090;
    box-shadow: 0 8px 24px rgba(0,0,0,0.15);
    max-height: 200px; overflow-y: auto;
}
.multi-select-option {
    display: flex; align-items: center; gap: 8px;
    padding: 8px 10px; border-radius: 6px; cursor: pointer;
    font-size: 0.875rem; color: var(--bs-body-color);
}
.multi-select-option:hover { background: var(--bs-tertiary-bg); }
.multi-select-option input[type="checkbox"] { accent-color: var(--bs-primary); width: 16px; height: 16px; }
.multi-select-empty { padding: 10px 14px; font-size: 0.8125rem; color: var(--bs-secondary-color); text-align: center; }


/* ── Search Select (AJAX dropdown — replaces Select2 AJAX) ───── */
.search-select { position: relative; }
.search-select-input {
    width: 100%; padding: 0.375rem 0.75rem; border: 1px solid var(--bs-border-color);
    border-radius: 10px; font-size: 0.875rem; color: var(--bs-body-color);
    background: var(--bs-body-bg); outline: none; transition: border-color 0.15s;
    min-height: calc(1.5em + 0.75rem + 2px); /* match form-control */
}
.search-select-input:focus { border-color: var(--bs-primary); box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.12); }
.search-select-input::placeholder { color: var(--bs-secondary-color); }
.search-select-dropdown {
    display: none; position: absolute; top: calc(100% + 4px); inset-inline-start: 0; inset-inline-end: 0;
    background: var(--bs-body-bg); border: 1px solid var(--bs-border-color);
    border-radius: 10px; padding: 4px; z-index: 1090;
    box-shadow: 0 8px 24px rgba(0,0,0,0.15); max-height: 220px; overflow-y: auto;
}
.search-select-dropdown.show { display: block; }
.search-select-item {
    padding: 8px 10px; border-radius: 6px; cursor: pointer;
    font-size: 0.875rem; color: var(--bs-body-color);
}
/* No dark overrides on these four surfaces, deliberately. They previously set
   background: var(--bs-gray-800) — but the Slate ramp INVERTS in dark, where --bs-gray-800 is
   #e2e8f0, near white, while the text stayed --bs-body-color (#f1f5f9). Near-white on near-white:
   the fields were effectively unreadable in dark mode. The base rules already use --bs-body-bg
   and --bs-border-color, both of which flip correctly, so the overrides were not just wrong but
   unnecessary. Anything added here must be checked against the dark values, not the light ones. */
.search-select-item:hover, .search-select-item.active { background: var(--bs-primary); color: #fff; }
.search-select-empty { padding: 12px; text-align: center; font-size: 0.8125rem; color: var(--bs-secondary-color); }
.search-select-loader { padding: 10px; text-align: center; font-size: 0.75rem; color: var(--bs-secondary-color); }
.search-select-input.has-value { font-weight: 500; }
.search-select-clear {
    position: absolute; inset-inline-end: 10px; top: 50%; transform: translateY(-50%);
    border: none; background: none; color: var(--bs-secondary-color); cursor: pointer;
    font-size: 1rem; line-height: 1; padding: 2px; display: none;
}
.search-select.has-value .search-select-clear { display: block; }

/* ── Coordinate system picker ────────────────────────────
   Deliberately thin. A project's grid is permanent, but the choice still belongs in one
   ordinary search field — an earlier pass wrapped it in a mode toggle and an explainer card and
   read as far more ceremony than the decision deserves. Only two net-new pieces survive. */

/* Optional second line on a search-select result. Opacity rather than a fixed colour so it
   stays legible against the primary fill the row takes on hover. */
.search-select-sub {
    display: block;
    font-size: 0.72rem;
    opacity: 0.75;
    margin-top: 1px;
}

/* The coordinate system, how it was found, and the height system are one decision made across
   several fields. Boxing them off the page says so — without it the modal reads as five loose
   controls between Capture Date and Description.

   Tinted with the brand blue rather than grey: grey reads as disabled, and amber or mustard
   would read as a warning, which a required field is not. --primary-muted and
   --primary-subtle already existed for exactly this and had no users. Both are translucent,
   so the tint sits correctly over the light page and the dark one without a theme override,
   while the fields keep their own opaque surface and stay forward of it. */
.crs-group {
    padding: 12px 14px;
    border: 1px solid var(--primary-subtle);
    border-radius: 10px;
    background: var(--primary-muted);
}

/* Last caption in the group has nothing after it, so its margin only adds slack. */
.crs-group > :last-child { margin-bottom: 0; }

/* Search-mode switch — a sliding segmented control. The pill is a pseudo-element that moves,
   rather than a background swapped between two buttons, so the change reads as one control with
   a position instead of two that light up independently. */
.crs-searchmode {
    position: relative;
    display: inline-flex;
    padding: 3px;
    border-radius: 8px;
    /* Sits inside the tinted group, so its track takes the card surface rather than the page
       grey it was originally set against — grey on tint reads as a second, unrelated panel. */
    background: var(--card-bg);
    border: 1px solid var(--primary-subtle);
}

.crs-searchmode::before {
    content: "";
    position: absolute;
    top: 3px;
    inset-inline-start: 3px;
    width: calc(50% - 3px);
    height: calc(100% - 6px);
    border-radius: 6px;
    background: var(--primary-subtle);
    transition: transform var(--ease-base);
}

.crs-searchmode[data-mode="point"]::before { transform: translateX(100%); }
html[dir="rtl"] .crs-searchmode[data-mode="point"]::before { transform: translateX(-100%); }

.crs-searchmode button {
    position: relative;   /* above the sliding pill */
    z-index: 1;
    flex: 1 1 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    border: none;
    background: transparent;
    padding: 4px 12px;
    border-radius: 6px;
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
    color: var(--bs-secondary-color);
    cursor: pointer;
    transition: color var(--ease-fast);
}

.crs-searchmode button i { font-size: 0.9rem; }
.crs-searchmode button:hover { color: var(--bs-body-color); }
.crs-searchmode button.is-on { color: var(--bs-primary); }

/* The point a place search resolved to. Shown so the pilot can sanity-check it before the
   grid list is trusted — a wrong town is otherwise invisible. */
.crs-point {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
    margin-top: 6px;
}

.crs-point i { color: var(--bs-primary); }
.crs-point .tnum { font-variant-numeric: tabular-nums; }

/* Editing an existing project: the grid is shown as fact, because it cannot be changed. */
.crs-locked {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 12px;
    border: 1px solid var(--bs-border-color);
    border-radius: 8px;
    background: var(--bs-gray-100);
    font-size: 0.8125rem;
    color: var(--bs-body-color);
}

.crs-locked i { color: var(--bs-secondary-color); }

/* No dark block: --bs-gray-100 already flips (#edf1f5 → #0f172a). Naming a gray-800/900 here
   would invert it — the Slate ramp reverses in dark, where --bs-gray-900 is #f1f5f9, near white. */

/* Disabled form controls — clearly muted */
.modal .form-control:disabled,
.modal .form-control[readonly][disabled],
.modal .form-select:disabled {
    background-color: var(--bs-gray-100) !important;
    color: var(--bs-gray-400) !important;
    border-color: var(--bs-gray-100) !important;
    cursor: not-allowed;
    opacity: 1;
}

/* Character counter (below inputs with maxlength)
   height:0 + overflow:visible keeps it visible but removes it
   from flow so every form-group row has the same height budget. */
/* Helper text under a form field.

   NOT .char-counter - that is a zero-height, right-aligned overlay built for a live
   character count, so a sentence placed in it has no height and lands on top of whatever
   comes next in the form. */
.input-hint {
    display: block;
    font-size: 0.75rem;
    color: var(--bs-gray-600);
    margin-top: 0.35rem;
    line-height: 1.35;
}

/* A boolean sharing a form row with real inputs.

   Deliberately NOT styled as a field. It was given a border to match the input-group beside
   it, which only made it read as an input that cannot be typed into. What it actually needs
   from its neighbour is height, not chrome: min-height matches .form-control so the control
   sits on the same baseline as the input next to it, and align-items centres the switch in
   that space instead of hanging from the top. */
.switch-field {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: calc(1.5em + 0.75rem + 2px);
}

.switch-field > i {
    color: var(--bs-gray-600);
    font-size: 1rem;
    line-height: 1;
}

.switch-field-text {
    font-size: 0.875rem;
    color: var(--bs-body-color);
    cursor: pointer;
}

/* Pushed to the trailing edge of the row, so the switch lines up with the right-hand end of
   the input beside it rather than trailing its own label.

   Flex here as well as on the parent, and for a different reason: the parent centres this
   wrapper in the row, but Bootstrap aligns .form-check-input to the TOP of its own line box,
   which left the switch sitting visibly high. Centring inside the wrapper too settles it. */
.switch-field .form-check {
    display: flex;
    align-items: center;
    margin-inline-start: auto;
    margin-bottom: 0;
    padding-inline-start: 0;
    min-height: 0;
}

.switch-field .form-check-input {
    margin: 0;
    float: none;
    cursor: pointer;
}

/* Private / Public as two radio cards (New Project, on Home and Projects). Both choices and what
   each one means stay on screen; the chosen card takes the primary border and tint. The native
   radio is kept, only drawn as the ring, so keyboard and screen readers behave as a radio group. */
.visibility-cards {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
}

.visibility-card {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 10px;
    row-gap: 2px;
    align-items: center;
    padding: 12px 14px;
    border: 1px solid var(--bs-border-color);
    border-radius: 10px;
    background: var(--bs-body-bg);
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease;
}

.visibility-card:hover { border-color: rgba(var(--bs-primary-rgb), .5); }

.visibility-card input {
    grid-row: span 2;
    align-self: start;
    appearance: none;
    width: 16px;
    height: 16px;
    margin: 2px 0 0;
    border: 2px solid var(--bs-secondary-color);
    border-radius: 50%;
    background: var(--bs-body-bg);
    cursor: pointer;
}

.visibility-card input:checked {
    border-color: var(--bs-primary);
    background: radial-gradient(var(--bs-primary) 0 3.5px, transparent 4.5px);
}

.visibility-card input:focus-visible { outline: 2px solid var(--bs-primary); outline-offset: 2px; }

.visibility-card-title {
    display: flex;
    align-items: center;
    gap: 6px;
    font-weight: 600;
    color: var(--bs-body-color);
}

.visibility-card-hint {
    font-size: 0.78rem;
    line-height: 1.4;
    color: var(--bs-secondary-color);
}

.visibility-card:has(input:checked) {
    border-color: var(--bs-primary);
    background: rgba(var(--bs-primary-rgb), .07);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), .18);
}

.visibility-card:has(input:checked) .visibility-card-title { color: var(--bs-primary); }

@media (max-width: 479.98px) {
    .visibility-cards { grid-template-columns: minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
    .visibility-card { transition: none; }
}



.char-counter {
    display: block;
    text-align: end;
    font-size: 0.625rem;
    color: var(--bs-gray-400);
    margin-top: 2px;
    height: 0;
    overflow: visible;
    line-height: 1;
    transition: color 0.15s;
}
.char-counter.is-warn {
    color: #e67e22;
}
.char-counter.is-limit {
    color: var(--bs-danger);
    font-weight: 600;
}

/* Primary action button disabled state */
.modal .btn-primary:disabled,
.modal .btn-primary.disabled {
    background-color: var(--bs-gray-200) !important;
    border-color: var(--bs-border-color) !important;
    color: var(--bs-gray-400) !important;
    cursor: not-allowed;
    opacity: 1;
}

/* Danger zone in modals */
.modal .danger-zone {
    border: 1px solid var(--bs-border-color);
    border-radius: 12px;
    padding: 16px;
    background: rgba(239, 68, 68, 0.03);
}

.modal .danger-zone-title {
    font-size: 0.875rem;
    font-weight: 600;
    color: #dc2626;
    margin-bottom: 10px;
}


/* Upload drop zone */
.upload-zone {
    border: 2px dashed var(--sidebar-border);
    border-radius: 12px;
    padding: 40px 20px;
    text-align: center;
    color: var(--bs-gray-400);
    margin-bottom: 20px;
    transition: border-color 0.2s ease;
    cursor: pointer;
}

.upload-zone:hover {
    border-color: var(--bs-primary);
}

.upload-zone i {
    font-size: 3rem;
    color: var(--sidebar-border);
    display: block;
    margin-bottom: 8px;
}

.upload-zone p {
    margin: 0;
    font-size: 0.9375rem;
    color: var(--bs-gray-500);
}

/* Alerts */
.alert-danger {
    background: #FEF2F2;
    border-color: #FECACA;
    color: #991B1B;
}

.alert-success {
    background: #F0FDF4;
    border-color: #BBF7D0;
    color: #166534;
}

.alert-warning {
    background: #FFFBEB;
    border-color: #FDE68A;
    color: #92400E;
}

.alert-info {
    background: #EFF6FF;
    border-color: #BFDBFE;
    color: #1E40AF;
}

/* Tables */
.table {
    color: var(--bs-gray-900);
    border-color: var(--bs-border-color);
}

.table > thead { color: var(--bs-body-color); font-weight: 600; }
.table-striped > tbody > tr:nth-of-type(odd) { background: rgba(245, 246, 250, 0.5); }
.table-hover > tbody > tr:hover { background: var(--bs-body-bg); }

/* Cards */
.card {
    background: var(--card-bg);
    border: 1px solid var(--bs-border-color);
    color: var(--bs-gray-900);
}

.card-header {
    background: var(--bs-body-bg);
    border-bottom-color: var(--bs-border-color);
}

.card-footer {
    background: var(--bs-body-bg);
    border-top-color: var(--bs-border-color);
}

/* Text utilities */
.text-muted { color: var(--bs-tertiary-color) !important; }
.text-danger { color: #ef4444 !important; }
.text-success { color: #22c55e !important; }
.text-warning { color: #f59e0b !important; }
.text-info { color: var(--bs-primary) !important; }

/* Direction glyphs (back arrows, chevrons, pager arrows) turn to face the reading direction. */
/* inline-block because a transform does nothing on a plain inline <i>. */
html[dir="rtl"] .flip-in-rtl { display: inline-block; transform: scaleX(-1); }

/* Letter-spacing pulls Arabic letters apart: the uppercase micro-labels drop it in Arabic. */
html[dir="rtl"] .sidebar-nav-label,
html[dir="rtl"] .storage-title,
html[dir="rtl"] .storage-info,
html[dir="rtl"] .sidebar-plan-name,
html[dir="rtl"] .data-table-table thead th,
html[dir="rtl"] .language-picker-heading {
    letter-spacing: normal;
}

/* Dropdown */
.dropdown-menu {
    background: var(--card-bg);
    border-color: var(--bs-border-color);
}

.dropdown-item { color: var(--bs-body-color); }

.dropdown-item:hover,
.dropdown-item:focus {
    background: var(--bs-body-bg);
    color: var(--bs-gray-900);
}

.dropdown-divider { border-top-color: var(--bs-border-color); }

/* Progress bar */
.progress {
    background: var(--bs-gray-200);
}

.progress-bar {
    background: var(--bs-primary);
}

/* ======================================
   Section 11: DM Component Utilities
   ====================================== */
.panel-card {
    background: var(--card-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 12px;
    padding: 1.5rem;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.panel-card:hover {
    border-color: var(--bs-gray-300);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.pill-badge {
    display: inline-flex;
    align-items: center;
    padding: 4px 12px;
    border-radius: 6px;
    font-size: 0.8125rem;
    font-weight: 600;
    background: rgba(var(--bs-primary-rgb), 0.1);
    color: var(--bs-primary);
}

/* ======================================
   Section 12: Dashboard / Project Cards
   ====================================== */

/* Dashboard Summary Stat Cards */
.stat-card {
    border-radius: 10px;
    overflow: hidden;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.stat-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.stat-card-body {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1.25rem 1.5rem;
    min-height: 120px;
}
.stat-card-info {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.stat-card-label {
    font-size: 0.875rem;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.85);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.stat-card-value {
    font-size: 1.5rem;
    font-weight: 700;
    color: #fff;
    line-height: 1.2;
}
.stat-card-icon {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.25);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.stat-card-icon i {
    font-size: 1.5rem;
    color: #fff;
}

/* Color Variants — uses Bootstrap variable overrides */
.stat-card--success { background: #16a34a; }
.stat-card--primary { background: var(--bs-primary); }
.stat-card--info    { background: #0891b2; }
.stat-card--warning { background: #d97706; }

.page-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 24px;
}

.page-header h1 {
    font-size: 1.5rem;
    font-weight: 800;
    margin: 0;
    color: var(--bs-body-color);
}


/* ======================================
   Shared Page Header (used by all inner pages)
   ====================================== */
.page-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 24px;
}

.page-title {
    font-size: 1.625rem;
    font-weight: 700;
    color: var(--bs-body-color);
    letter-spacing: -0.02em;
    line-height: 1.2;
    margin: 0 0 4px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.page-subtitle {
    color: var(--bs-secondary-color);
    font-size: 0.9375rem;
    font-weight: 400;
    margin: 0;
}

/* Shared action button layout helper (icon + text alignment) */
.btn-action {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
    padding: 10px 20px;
    font-size: 0.9375rem;
    font-weight: 500;
}

.btn-action i {
    font-size: 1.1rem;
}

/* ── Projects Page Header ───── */
.proj-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 24px;
}

.proj-header-left {
    flex-shrink: 0;
}

.proj-header-right {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-shrink: 0;
}

/* Search input — pill shape, subtle bg */
.proj-search {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    background: rgba(var(--bs-primary-rgb), 0.03);
    border: 1px solid rgba(var(--bs-primary-rgb), 0.08);
    border-radius: 9999px;
    padding: 0 16px;
    height: 40px;
    min-width: 256px;
    transition: border-color 0.2s, box-shadow 0.2s;
}

.proj-search:focus-within {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 1px var(--bs-primary);
}

.proj-search i {
    color: var(--bs-secondary-color);
    font-size: 1rem;
    flex-shrink: 0;
}

.proj-search input {
    border: none;
    outline: none;
    background: transparent;
    color: var(--bs-body-color);
    font-size: 0.875rem;
    font-family: var(--bs-body-font-family);
    font-weight: 400;
    width: 100%;
}

.proj-search input::placeholder {
    color: var(--bs-secondary-color);
}

/* Grid/List toggle group */
.proj-view-toggles {
    display: flex;
    align-items: center;
    background: rgba(var(--bs-primary-rgb), 0.04);
    border: 1px solid rgba(var(--bs-primary-rgb), 0.08);
    border-radius: 10px;
    padding: 4px;
    gap: 4px;
    height: 40px;
}

.proj-view-btn {
    width: 32px;
    height: 32px;
    min-width: 32px;
    border: none;
    background: transparent;
    color: var(--bs-secondary-color);
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.15s;
    font-size: 1rem;
    padding: 0 10px;
}

.proj-view-btn:hover {
    color: var(--bs-tertiary-color);
    background: rgba(var(--bs-primary-rgb), 0.04);
}

.proj-view-btn.active {
    background: var(--card-bg);
    color: var(--bs-body-color);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}

/* ── Project Cards Grid ───────────────── */
.projects-grid {
    display: grid;
    grid-template-columns: repeat(1, 1fr);
    gap: 20px;
    padding-bottom: 2.5rem;
}

@media (min-width: 768px) {
    .projects-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 992px) {
    .projects-grid { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 1400px) {
    .projects-grid { grid-template-columns: repeat(4, 1fr); }
}

/* ── Base Card ───────────────── */
.project-card {
    background: var(--card-bg);
    border: 1px solid rgba(226, 232, 240, 0.4);
    border-radius: 16px;
    overflow: hidden;
    transition: all 0.5s ease;
    display: flex;
    flex-direction: column;
    height: 280px;
    cursor: pointer;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
}

.project-card:hover {
    border-color: rgba(226, 232, 240, 0.8);
    box-shadow: 0 20px 40px rgba(var(--bs-primary-rgb), 0.05);
}

/* ── "New Workspace" card ───── */
.project-card--new {
    border: 2px dashed rgba(226, 232, 240, 0.4);
    background: transparent;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 280px;
    box-shadow: none;
}

.project-card--new:hover {
    border-color: rgba(var(--bs-primary-rgb), 0.5);
    background: rgba(var(--bs-primary-rgb), 0.02);
}

.project-new-inner {
    text-align: center;
    padding: 2rem;
}

.project-new-icon {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--bs-gray-100);
    color: var(--bs-tertiary-color);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
    margin: 0 auto 16px;
    transition: all 0.3s ease;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}

.project-card--new:hover .project-new-icon {
    background: var(--bs-primary);
    color: #fff;
    transform: scale(1.1);
}

.project-new-title {
    font-weight: 600;
    color: var(--bs-secondary-color);
    font-size: 1.125rem;
    margin: 0 0 8px;
    transition: color 0.3s;
}

.project-card--new:hover .project-new-title {
    color: var(--bs-body-color);
}

.project-new-desc {
    color: var(--bs-secondary-color);
    opacity: 0.7;
    font-size: 0.875rem;
    font-weight: 400;
    margin: 0;
    line-height: 1.5;
    padding: 0 1.5rem;
}

/* ── Top bar: status + member count ── */
.project-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 16px 0;
}

.project-status {
    display: inline-flex;
    align-items: center;
    padding: 2px 10px;
    border-radius: 6px;
    border: 1px solid var(--bs-border-color);
    background: var(--card-bg);
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--bs-body-color);
}

.project-members {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: 9999px;
    background: var(--card-bg);
    border: 1px solid var(--bs-border-color);
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--bs-body-color);
}

.project-members i {
    font-size: 0.75rem;
    color: var(--bs-primary);
}

/* ── Card Image Area ───────── */
.project-card-img {
    position: relative;
    height: 120px;
    flex-shrink: 0;
    overflow: hidden;
    background: var(--bs-gray-100);
}

.project-card-img img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Hover overlay with "Open Viewer" */
.project-hover-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.3);
    backdrop-filter: blur(1px);
    opacity: 0;
    transition: opacity 0.3s ease;
    z-index: 10;
}

.project-card:hover .project-hover-overlay {
    opacity: 1;
}

.project-open-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 6px 18px;
    border: 1px solid var(--bs-primary);
    background: rgba(var(--bs-primary-rgb), 0.9);
    color: #fff;
    border-radius: 6px;
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
    box-shadow: 0 8px 24px rgba(var(--bs-primary-rgb), 0.2);
    transition: all 0.2s ease;
}

.project-open-btn:hover {
    background: var(--bs-primary);
    transform: scale(1.05);
}

/* ── Card Body ─────────────── */
.project-card-body {
    padding: 16px 16px 8px;
    flex-grow: 1;
    display: flex;
    flex-direction: column;
}

.project-title-row {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
}

.project-card-body h5 {
    font-size: 1.125rem;
    font-weight: 600;
    margin: 0;
    color: var(--bs-body-color);
    line-height: 1.3;
    letter-spacing: -0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1;
    min-width: 0;
    padding-inline-end: 8px;
}

.project-card-body p {
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
    font-weight: 400;
    margin: 4px 0 0;
    line-height: 1.45;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* 3-dot menu */
.card-menu {
    width: 32px;
    height: 32px;
    min-width: 32px;
    border: none;
    background: transparent;
    color: var(--bs-secondary-color);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 1rem;
    transition: all 0.2s;
    margin-top: -4px;
    margin-inline-end: -8px;
    flex-shrink: 0;
}

.card-menu:hover {
    color: var(--bs-body-color);
}

/* ── Footer: date + storage ── */
.project-footer {
    padding: 0 16px 14px;
    margin-top: auto;
    border-top: 1px solid var(--bs-gray-100);
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}

.project-footer-inner {
    display: flex;
    align-items: center;
    gap: 16px;
    padding-top: 12px;
}

.project-meta {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8125rem;
    font-weight: 400;
    color: var(--bs-secondary-color);
}

.project-meta i {
    font-size: 0.875rem;
}

/* ── List view ─────────────── */
.projects-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.projects-list .project-card {
    flex-direction: row;
    align-items: center;
    height: auto;
}

.projects-list .project-card--new {
    min-height: auto;
    height: auto;
    padding: 1.5rem;
}

.projects-list .project-card-img {
    width: 120px;
    height: 80px;
    flex-shrink: 0;
    margin: 12px;
}

.projects-list .project-card-body {
    padding: 12px 14px;
}

.projects-list .project-card-body p {
    -webkit-line-clamp: 1;
}

.projects-list .project-footer {
    border-top: none;
    padding-block: 0;
    padding-inline: 0 14px;
}

.projects-list .project-hover-overlay {
    display: none;
}

/* ── Flatpickr overrides ────────────────────────────── */
.flatpickr-input[readonly] {
    background-color: var(--bs-body-bg);
    cursor: pointer;
}
input.flatpickr-input.form-control + input.form-control.input {
    background-color: var(--bs-body-bg);
    cursor: pointer;
}

/* Context Menu */
.context-menu {
    position: fixed;
    z-index: 1060;
    background: var(--card-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 6px;
    padding: 3px;
    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
    opacity: 0;
    visibility: hidden;
    transform: scale(0.92);
    transform-origin: top right;
    transition: opacity 0.12s ease, transform 0.12s ease, visibility 0.12s ease;
    pointer-events: none;
}

.context-menu.active {
    opacity: 1;
    visibility: visible;
    transform: scale(1);
    pointer-events: auto;
}

.context-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 6px 12px;
    border: none;
    border-radius: 4px;
    background: transparent;
    color: var(--bs-gray-700);
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.1s ease;
    white-space: nowrap;
}

.context-item i {
    font-size: 0.9375rem;
    color: var(--bs-gray-500);
}

.context-item:hover {
    background: var(--bs-gray-100);
    color: var(--bs-emphasis-color);
}

.context-item:hover i {
    color: var(--bs-gray-700);
}

.context-item.context-danger {
    color: #EF4444;
}

.context-item.context-danger i {
    color: #EF4444;
}

.context-item.context-danger:hover {
    background: #FEF2F2;
}

.context-divider {
    height: 1px;
    background: var(--bs-gray-200);
    margin: 2px 4px;
}

/* ======================================
   Section 13: (Reserved - all styles are hardcoded, no theme switching needed)
   ====================================== */

/* ======================================
   Section 14: Page-Specific Overrides
   ====================================== */

/* Map page: full-screen workspace — hide app chrome, map has its own topbar */
.app[data-page="map"] .sidebar,
.app[data-page="map"] .header,
.app[data-page="map"] .footer,
.app[data-page="map"] .right-toolbar { display: none !important; }

.app[data-page="map"] .main {
    margin: 0 !important;
    max-width: none !important;
    width: 100vw !important;
    height: 100vh !important;
    flex: none !important;
}
.app[data-page="map"] .content {
    padding: 0 !important;
    overflow: hidden;
    position: relative;
    height: 100vh !important;
    width: 100vw !important;
}

/* Map viewer CSS is in map-viewer.css (loaded only on Map page) */

/* ======================================
   Section 15: Mobile Overlay
   ====================================== */
.overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    z-index: 1045;
    backdrop-filter: blur(2px);
    opacity: 0;
    transition: opacity 0.2s ease;
}

/* ======================================
   Section 16: Responsive Breakpoints
   ====================================== */

/* Tablet */
@media (max-width: 991.98px) {
    .proj-header {
        flex-direction: column;
        gap: 16px;
    }

    .proj-header-right {
        flex-wrap: wrap;
    }

    .proj-search {
        min-width: 180px;
        flex: 1;
    }
}

/* Tablet + mobile (≤991px): sidebar becomes an off-canvas drawer + backdrop, opened by the header
   hamburger. Fixes the 768–991 dead zone where the sidebar stayed pinned over the content with no
   reachable toggle. The icon-rail collapse stays desktop-only (>991). */
@media (max-width: 991.98px) {
    /* Slim icon rail, always visible (like the desktop collapsed rail). JS keeps .sidebar-collapsed
       on for the rail look; the hamburger removes it + adds .sidebar-mobile-open to expand into the
       full labelled drawer, which overlays the content (content keeps its rail-width margin). */
    .sidebar {
        transform: none;
        z-index: 1050;
        animation: none;
        transition: width 0.2s ease;
    }
    .app:not([data-page="map"]) .main {
        margin-inline-start: var(--sidebar-collapsed-width, 68px);
        max-width: calc(100vw - var(--sidebar-collapsed-width, 68px));
    }
    .app.sidebar-mobile-open .sidebar { width: var(--sidebar-width); }
    .app.sidebar-mobile-open .overlay { display: block; opacity: 1; }
    .app.sidebar-mobile-open { overflow: hidden; }

    /* No sideways page scroll; wide data tables scroll inside their own card */
    .main, .content { overflow-x: hidden; }
    .data-table-card { overflow-x: auto; }
}

/* Drawer close (✕) — sits top-right inside the off-canvas sidebar, shown only on mobile/tablet.
   (The header hamburger is hidden behind the open drawer, so the drawer needs its own close.) */
/* Lives OUTSIDE the sidebar (child of .app) so the sidebar's overflow:hidden
   can't clip it — floats just past the open drawer's right edge, over the dim
   overlay, and only while the mobile drawer is open. */
.drawer-close {
    display: none;
    position: fixed;
    top: 14px;
    inset-inline-start: calc(var(--sidebar-width) + 10px);
    width: 36px;
    height: 36px;
    align-items: center;
    justify-content: center;
    border: 1px solid rgba(255, 255, 255, 0.18);
    background: rgba(17, 20, 26, 0.5);
    color: #fff;
    border-radius: 9px;
    font-size: 1.35rem;
    cursor: pointer;
    z-index: 1045;
    transition: background 0.15s ease;
}
.drawer-close:hover { background: rgba(17, 20, 26, 0.72); color: #fff; }
@media (max-width: 991.98px) {
    #app.sidebar-mobile-open .drawer-close { display: flex; }
}

/* Mobile — sidebar behaviour is handled by the ≤991 icon-rail rules above; only content
   refinements live here. */
@media (max-width: 767.98px) {
    .app.sidebar-mobile-open .overlay {
        display: block;
        opacity: 1;
    }

    .content {
        padding: 16px;
    }

    /* Compact header on mobile */
    .header {
        padding: 0 16px;
        height: 50px;
        min-height: 50px;
    }

    .header-welcome {
        display: none;
    }

    .header-divider {
        display: none;
    }

    .user-info {
        display: none;
    }

    .toolbar-search {
        flex: 1;
        min-width: 0;
    }

    .proj-header {
        flex-direction: column;
        gap: 12px;
    }

    .proj-header-right {
        flex-wrap: wrap;
        width: 100%;
    }

    .proj-search {
        flex: 1;
        min-width: 0;
    }

    .project-card--new {
        min-height: 200px;
        height: auto;
    }

    .project-card {
        height: auto;
        min-height: 280px;
    }

    /* Right toolbar becomes bottom bar on mobile */
    .right-toolbar {
        position: fixed;
        top: auto;
        inset-inline-end: auto;
        bottom: 0;
        inset-inline-start: 0;
        width: 100%;
        height: 52px;
        flex-direction: row;
        justify-content: center;
        border-inline-start: none;
        border-top: 1px solid var(--sidebar-border);
        padding: 0 8px;
        gap: 4px;
        overflow-x: auto;
    }

    .app.has-right-toolbar .main {
        margin-inline-end: 0;
        padding-bottom: 52px;
    }

    .tool-divider {
        width: 1px;
        height: 24px;
        margin: 0 4px;
    }

    .tool-spacer {
        display: none;
    }
}

/* ── Shared responsive: page headers + data-table screens (Users, Details, etc.) ── */
@media (max-width: 767.98px) {
    /* Page header stacks: title block above, actions below and full-width */
    .page-header { flex-direction: column; align-items: stretch; gap: 12px; }
    .page-header > div { min-width: 0; }
    .page-header .d-flex.align-items-center.gap-2 { flex-wrap: wrap; }
    .page-header .btn-action { flex: 1 1 auto; justify-content: center; }

    /* Data-table toolbar stacks: title, then search + filters wrap full-width */
    .data-table-toolbar { flex-direction: column; align-items: stretch; gap: 12px; }
    .data-table-toolbar-right { flex-wrap: wrap; gap: 8px; width: 100%; }
    .data-table-toolbar-right .data-table-search { flex: 1 1 100%; max-width: none; }
    .data-table-toolbar-right .data-table-filter-wrap { flex: 1 1 auto; }
    .data-table-toolbar-right .data-table-filter-select { width: 100%; }

    /* Wide tables scroll inside their card instead of stretching the page */
    .data-table-card { overflow-x: auto; }
    .data-table-table { min-width: 620px; }
}

@media (max-width: 575.98px) {
    .auth-buttons .btn {
        font-size: 0.8125rem;
        padding: 5px 12px;
    }
}

/* DataTables light theme */
.dataTables_wrapper {
    color: var(--bs-gray-900);
}
.dataTables_wrapper .dataTables_length,
.dataTables_wrapper .dataTables_filter,
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_paginate {
    color: var(--bs-gray-600);
}
.dataTables_wrapper .dataTables_length select,
.dataTables_wrapper .dataTables_filter input {
    background-color: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    color: var(--bs-gray-900);
}
/* Legacy pager colours, for tables not yet on the data-table footer. Excluded from the ones
   that are: these selectors carry one more class than the .data-table-footer-pages rules in
   section 26, so with !important on both sides they silently won and the design-system
   colours never applied. */
.data-table-footer-pages .paginate_button.current,
.dataTables_wrapper:not(:has(.data-table-footer)) .dataTables_paginate .paginate_button.current,
.dataTables_wrapper:not(:has(.data-table-footer)) .dataTables_paginate .paginate_button.current:hover,
.page-item.active .page-link,
table.dataTable + .dataTables_wrapper .page-item.active .page-link {
    color: var(--on-primary) !important;
}
.dataTables_wrapper:not(:has(.data-table-footer)) .dataTables_paginate .paginate_button {
    color: var(--bs-gray-600) !important;
}

/* ======================================
   Section 17: SweetAlert2 Theme (Light + colorful accents)
   ====================================== */

/* Confirmation dialogs — clean white, rounded, matching site modals */
.swal-popup {
    max-width: 400px !important;
    padding: 24px 24px 20px !important;
    border-radius: 12px !important;
    border: 1px solid var(--bs-border-color) !important;
    font-family: inherit !important;
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.12) !important;
}

.swal-popup .swal2-icon {
    width: 48px !important;
    height: 48px !important;
    margin: 0 auto 12px !important;
    border-width: 3px !important;
}
.swal-popup .swal2-icon .swal2-icon-content { font-size: 1.5rem !important; }
.swal-popup .swal2-icon.swal2-warning .swal2-icon-content { font-size: 1.75rem !important; }

.swal-title {
    font-weight: 700 !important;
    font-size: 1rem !important;
    color: var(--bs-body-color) !important;
    padding: 0 !important;
    margin-bottom: 4px !important;
}

.swal-popup .swal2-html-container,
.swal-popup #swal2-content {
    font-size: 0.8125rem !important;
    margin: 0 !important;
    padding: 0 !important;
}

.swal-actions {
    gap: 10px;
    margin-top: 20px !important;
    padding: 0 !important;
}

.swal-actions .btn {
    font-size: 0.8125rem !important;
    padding: 6px 20px !important;
    min-width: 0 !important;
}

/* Loading spinner popup */
.swal-loading {
    max-width: 320px !important;
    padding: 32px 24px !important;
    border-radius: 12px !important;
    border: 1px solid var(--bs-border-color) !important;
    font-family: inherit !important;
    box-shadow: 0 16px 48px rgba(0, 0, 0, 0.12) !important;
}
.swal-loading .swal2-title {
    font-size: 0.875rem !important;
    font-weight: 600 !important;
    color: var(--bs-secondary-color) !important;
}

/* Toast notifications — rich colored backgrounds with vibrant icons */
.swal-toast {
    border-radius: 12px !important;
    font-family: var(--bs-body-font-family) !important;
    font-size: 0.9rem !important;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18) !important;
    min-width: 320px !important;
    max-width: 450px !important;
    border: none !important;
    padding: 0.85rem 1rem !important;
}

.swal-toast .swal2-title {
    font-size: 0.9rem !important;
    font-weight: 600 !important;
    /* File names have no spaces to break at ("Block1_lidar_full_repaired.laz") and ran out past the toast's edge. */
    overflow-wrap: anywhere;
}

/* Make toast icons smaller + vibrant */
.swal-toast .swal2-icon {
    width: 1.6rem !important;
    height: 1.6rem !important;
    margin-block: 0 !important;
    margin-inline: 0 0.6rem !important;
    border-width: 2px !important;
}
.swal-toast .swal2-icon .swal2-icon-content { font-size: 0.9rem !important; }

/* Close button styling */
.swal-toast .swal2-close {
    font-size: 1.1rem !important;
    color: inherit !important;
    opacity: 0.5 !important;
}
.swal-toast .swal2-close:hover { opacity: 1 !important; }

/* Timer progress bar — match the accent color */
.swal-toast .swal2-timer-progress-bar { border-radius: 0 0 12px 12px !important; }

/* Success toast — deeper green */
.swal-toast.swal2-icon-success {
    background: linear-gradient(135deg, #dcfce7 0%, #badbcc 100%) !important;
    border-inline-start: 5px solid #16a34a !important;
}
.swal-toast.swal2-icon-success .swal2-title { color: #14532d !important; }
.swal-toast.swal2-icon-success .swal2-timer-progress-bar { background: #16a34a !important; }

/* Error toast — deeper red */
.swal-toast.swal2-icon-error {
    background: linear-gradient(135deg, #fee2e2 0%, #f1c0c5 100%) !important;
    border-inline-start: 5px solid #dc2626 !important;
}
.swal-toast.swal2-icon-error .swal2-title { color: #7f1d1d !important; }
.swal-toast.swal2-icon-error .swal2-timer-progress-bar { background: #dc2626 !important; }

/* Warning toast — deeper amber */
.swal-toast.swal2-icon-warning {
    background: linear-gradient(135deg, #fef3c7 0%, #ffe9a0 100%) !important;
    border-inline-start: 5px solid #d97706 !important;
}
.swal-toast.swal2-icon-warning .swal2-title { color: #713f12 !important; }
.swal-toast.swal2-icon-warning .swal2-timer-progress-bar { background: #d97706 !important; }

/* Info toast — deeper blue */
.swal-toast.swal2-icon-info {
    background: linear-gradient(135deg, #cffafe 0%, #a8e8f8 100%) !important;
    border-inline-start: 5px solid #0891b2 !important;
}
.swal-toast.swal2-icon-info .swal2-title { color: #164e63 !important; }
.swal-toast.swal2-icon-info .swal2-timer-progress-bar { background: #0891b2 !important; }

/* Confirmation popup description text */
.swal-popup .swal2-html-container {
    color: var(--bs-secondary-color) !important;
}

.swal-popup .swal2-html-container strong {
    color: var(--bs-body-color) !important;
}

/* Input fields inside SweetAlert (e.g. social media URL prompt) */
.swal-popup .swal2-input {
    font-size: 0.8125rem !important;
    border-radius: 10px !important;
    border: 1px solid var(--bs-border-color) !important;
    padding: 8px 12px !important;
    height: auto !important;
    margin: 12px 0 0 !important;
}
.swal-popup .swal2-input:focus {
    border-color: var(--bs-primary) !important;
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.12) !important;
}
.swal-popup .swal2-validation-message {
    font-size: 0.75rem !important;
    margin: 4px 0 0 !important;
    padding: 6px 12px !important;
}

/* ======================================
   Section 18: Organization Page
   ====================================== */

/* Content state */
.org-content {
    display: none;
}

.org-content.show {
    display: block;
}

/* Bootstrap 5 nav-tabs — themed overrides */
.nav-tabs {
    border-bottom: 2px solid var(--bs-gray-100);
    gap: 0;
}

.nav-tabs .nav-link {
    border: none;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    margin-bottom: -2px;
    color: var(--bs-body-color);
    font-weight: 500;
    font-size: 0.9375rem;
    padding: 0.75rem 1.25rem;
    transition: color 0.15s ease, border-color 0.15s ease;
    background: none;
}

.nav-tabs .nav-link:hover,
.nav-tabs .nav-link:focus {
    color: var(--bs-body-color);
    border-bottom-color: var(--bs-gray-300);
    isolation: auto;
}

.nav-tabs .nav-link.active {
    color: var(--bs-primary);
    font-weight: 600;
    border-bottom-color: var(--bs-primary);
    background: none;
}

/* ── General Tab: Hero ─────────────────── */
.org-hero {
    position: relative;
    background: var(--card-bg);
    border: 1px solid var(--bs-gray-100);
    border-radius: 16px;
    overflow: hidden;
}

/* A 4px brand rule instead of a 104px photo-less banner. The old cover was pure decoration and
   pushed every real fact below the fold; this keeps the brand colour and gives the space back.
   It runs down the left edge rather than across the top, and only on the hero — the one card that
   identifies the organization. On the settings cards below it the same bar read as decoration
   repeated three times, so it earns its place here and nowhere else.
   Drawn as a pseudo-element so the markup carries no empty decorative div. */
.org-hero::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline: 0 auto;
    width: 4px;
    background: linear-gradient(180deg, var(--bs-primary) 0%, #6366f1 100%);
    pointer-events: none;
}

.org-hero-main {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    padding: 1.5rem;
}

.org-hero-identity {
    flex: 1;
    min-width: 0;
}

.org-hero-title {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.org-hero-title .org-profile-name { font-size: 1.375rem; }

/* Badge sits inline with the name here, so it must not carry the stacked-layout top margin. */
.org-hero-title .org-profile-badge { margin-top: 0; }

.org-hero-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.25rem 0.75rem;
    margin-top: 2px;
}

.org-hero-meta .org-profile-id {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-top: 0;
}

.org-hero-actions {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
}

.org-hero-actions-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* Cancel discards unsaved edits — the hover state should say so before it's pressed. */
#btn-cancel-edit:hover,
#btn-cancel-edit:focus-visible {
    background: var(--danger);
    border-color: var(--danger);
    color: #fff;
}

/* Pairs with the disabled Save button: one tells you nothing has changed, the other says why. */
.org-dirty-indicator {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--warning);
    white-space: nowrap;
}

.org-dirty-indicator::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--warning);
}

@media (max-width: 767.98px) {
    .org-hero-main {
        flex-direction: column;
        align-items: flex-start;
    }
    .org-hero-actions { width: 100%; }
    .org-hero-actions .btn { flex: 1; }
}

/* Settings row: label rail | controls. The two columns are independent by design — the rail holds
   a heading and one line of prose, so however tall the controls get, nothing is stretched to match. */
.org-setting-row {
    display: grid;
    grid-template-columns: minmax(180px, 260px) 1fr;
    gap: 1.5rem 2.5rem;
    padding: 1.5rem;
    border-bottom: 1px solid var(--bs-border-color);
}

.org-setting-row:last-child { border-bottom: 0; }

.org-setting-label h6 {
    margin-bottom: 4px;
    font-size: 0.9375rem;
    font-weight: 700;
    color: var(--bs-emphasis-color);
}

.org-setting-label p {
    margin-bottom: 0;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--bs-secondary-color);
}

.org-setting-optional {
    margin-inline-start: 0.375rem;
    padding: 1px 6px;
    border-radius: 9999px;
    background: var(--bs-secondary-bg);
    font-size: 0.625rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--bs-secondary-color);
    vertical-align: middle;
}

/* Stacks below the lg breakpoint — a 180px rail beside inputs is unusable on a phone. */
@media (max-width: 991.98px) {
    .org-setting-row {
        grid-template-columns: 1fr;
        gap: 0.875rem;
    }
}

/* The row already supplies the padding; .org-form-body is kept on the fields container purely so
   the existing field/label/readonly styling keeps applying. */
.org-setting-row .org-form-body { padding: 0; }

/* Two-up field grid inside the controls column. */
.org-field-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
    gap: 1rem 1.5rem;
}

.org-field-grid .span-2 { grid-column: 1 / -1; }


/* ── General Tab: Profile Card ─────────── */
.org-profile-logo {
    position: relative;
    flex: 0 0 auto;
    width: 108px;
    height: 108px;
    border-radius: 16px;
    background: var(--card-bg);
    border: 4px solid var(--card-bg);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
}

.org-profile-initial {
    color: var(--bs-primary);
    font-size: 2.5rem;
    font-weight: 700;
    text-transform: uppercase;
}

.org-profile-logo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: calc(16px - 4px);
}

/* Logo edit overlay — shown on profile logo in edit mode */
.org-logo-edit-overlay {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.35);
    /* Matches the logo's radius minus its 4px border, so the scrim doesn't square off the corners. */
    border-radius: calc(16px - 4px);
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 1.5rem;
    cursor: pointer;
    transition: background 0.2s;
}

.org-logo-edit-overlay:hover {
    background: rgba(0, 0, 0, 0.5);
}

.org-profile-logo.editable {
    cursor: pointer;
}

/* File text shown below logo in edit mode */
.org-logo-file-text {
    font-size: 0.8125rem;
    color: var(--bs-gray-500);
    margin-bottom: 4px;
}

.org-profile-name {
    font-weight: 800;
    color: var(--bs-body-color);
    margin-bottom: 0;
    font-size: 1.125rem;
}

.org-profile-id {
    font-size: 0.8125rem;
    color: var(--bs-tertiary-color);
    font-weight: 500;
    margin-top: 2px;
}

/* Org status pill. Default is the healthy state; JS swaps a modifier for trial/warning/danger.
   Kept on rgba tints of the semantic tokens so both themes work without a dark-mode override. */
.org-profile-badge {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin-top: 6px;
    padding: 3px 10px;
    border-radius: 9999px;
    background: rgba(22, 163, 74, 0.12);
    color: var(--success);
    font-size: 0.8125rem;
    font-weight: 600;
}

.org-profile-badge.is-warning {
    background: rgba(217, 119, 6, 0.12);
    color: var(--warning);
}

.org-profile-badge.is-danger {
    background: rgba(220, 38, 38, 0.12);
    color: var(--danger);
}

.org-profile-badge.is-neutral {
    background: var(--bs-secondary-bg);
    color: var(--bs-secondary-color);
}

/* Org ID chip — the whole thing is the copy button, so there's no separate control to aim at. */
.org-id-line {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-top: 4px;
    padding: 2px 8px;
    border: 1px solid var(--bs-border-color);
    border-radius: 9999px;
    background: none;
    color: var(--bs-secondary-color);
    font-size: 0.6875rem;
    cursor: pointer;
    transition: border-color var(--ease-fast), color var(--ease-fast);
}

.org-id-line > span {
    font-weight: 700;
    letter-spacing: 0.04em;
    opacity: 0.7;
}

.org-id-line code {
    color: inherit;
    font-size: 0.6875rem;
}

.org-id-line:hover {
    border-color: var(--primary);
    color: var(--primary);
}

/* Plan-lock hint should lead somewhere, not dead-end on the restriction. */
.org-lock-link {
    color: var(--warning);
    font-weight: 700;
    text-decoration: underline;
}


/* ── General Tab: Form Card ────────────── */
.org-form-card {
    background: var(--card-bg);
    border-radius: 16px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
    border: 1px solid var(--bs-gray-100);
    overflow: visible;
    transition: box-shadow 0.2s ease, border-color 0.2s ease;
}

.org-form-card:hover {
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
    border-color: var(--bs-border-color);
}

/* No equal-height rule here on purpose. Forcing it is what stretched whichever card sat opposite
   the tallest column into an empty box; the sections are full width now and size to their content. */

.org-form-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--bs-border-color);
    border-radius: 16px 16px 0 0;
}

.org-form-header h5 {
    font-weight: 800;
    color: var(--bs-body-color);
    margin-bottom: 0;
    font-size: 1.125rem;
}

.org-form-body {
    padding: 1.25rem;
    flex: 1;
}

/* Form labels — dark and bold */
.org-form-body .form-label {
    color: var(--bs-gray-500);
    font-weight: 600;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 0.15rem;
}

.org-profile-field {
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--bs-gray-100);
}

.org-profile-field:last-of-type {
    border-bottom: none;
}

/* Logo upload (General tab) */
.org-logo-upload {
    width: 100px;
    height: 100px;
    border: 2px dashed var(--bs-gray-300);
    border-radius: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.2s ease;
    overflow: hidden;
    position: relative;
    background: var(--bs-gray-50);
}

.org-logo-upload:hover {
    border-color: var(--bs-primary);
    background: rgba(var(--bs-primary-rgb), 0.1);
}

.org-logo-upload img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.org-logo-placeholder {
    text-align: center;
    color: var(--bs-gray-400);
}

.org-logo-placeholder i {
    font-size: 1.75rem;
    display: block;
    margin-bottom: 2px;
}

.org-logo-placeholder span {
    font-size: 0.8125rem;
}

.org-logo-remove {
    position: absolute;
    top: 4px;
    inset-inline-end: 4px;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: rgba(239, 68, 68, 0.9);
    color: #fff;
    border: none;
    font-size: 0.65rem;
    display: none;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 2;
}

.org-logo-upload:hover .org-logo-remove {
    display: flex;
}


/* Org form inputs */
.org-form-body .form-control,
.org-form-body .form-select {
    border-radius: 10px;
    border: 1.5px solid var(--bs-border-color);
    padding: 0.625rem 1rem;
    font-size: 0.9375rem;
    transition: all 0.2s ease;
}

.org-form-body .form-control:focus,
.org-form-body .form-select:focus {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.1);
}

/* Readonly fields — clean profile display */
.org-form-body .form-control[readonly]:not(.editing) {
    background: transparent;
    border: none;
    border-radius: 0;
    cursor: default;
    color: var(--bs-emphasis-color);
    font-weight: 500;
    font-size: 0.9375rem;
    padding: 0;
    height: auto;
    min-height: unset;
    resize: none;
    overflow: hidden;
}

.org-form-body .form-control[readonly]:not(.editing):focus {
    box-shadow: none;
}

/* No hover/pointer affordance in view mode — values are read-only text, and Edit Profile is the
   only entry point. A hover cue here would advertise a click that does nothing. */

.org-form-body .form-control[readonly]:not(.editing)::placeholder {
    color: transparent;
}

/* Editing state — restore form input look */
.org-form-body .form-control.editing {
    background: var(--bs-gray-50);
    border: 1.5px solid var(--bs-border-color);
    border-radius: 10px;
    padding: 0.625rem 1rem;
    cursor: text;
}

.org-form-body .form-control.editing:focus {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.1);
}

.org-form-body textarea.form-control.editing {
    resize: vertical;
    min-height: 80px;
}

/* Choice fields swap to a <select> in edit mode — match the .editing input chrome exactly so the
   form doesn't read as two different styles stacked on top of each other. */
.org-form-body .form-select {
    background-color: var(--bs-gray-50);
    border: 1.5px solid var(--bs-border-color);
    border-radius: 10px;
    padding-block: 0.625rem;
    padding-inline: 1rem 2.25rem;
    font-size: 0.9375rem;
}

.org-form-body .form-select:focus {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.1);
}

/* "Not set" muted style for empty view-mode fields */
.org-form-body .form-control.empty-view {
    color: var(--bs-gray-400) !important;
    font-style: italic;
    font-weight: 400;
}

/* ── Connected Accounts Tab ────────────── */
/* Social profile picker — one icon per platform. Colour carries the state, so this row replaces
   five cards, five buttons and four "Not set" labels. */
.social-row {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}

.social-item {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

.social-btn {
    width: 52px;
    height: 52px;
    border-radius: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.375rem;
    cursor: pointer;
    /* Unset: dashed outline reads as an empty slot to fill, not as something broken. */
    background: var(--bs-tertiary-bg);
    border: 1.5px dashed var(--bs-border-color);
    color: var(--bs-secondary-color);
    transition: transform var(--ease-fast), border-color var(--ease-fast), color var(--ease-fast);
}

.social-btn:hover {
    transform: translateY(-2px);
    border-color: var(--primary);
    color: var(--primary);
}

.social-btn.is-active {
    border-style: solid;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.12);
}

/* Set: solid brand fill. These hexes are the platforms' own brand colours, not app tokens. */
.social-btn.is-set {
    border-style: solid;
    border-color: transparent;
    color: #fff;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.14);
}

.social-btn.is-set:hover { color: #fff; }

.social-btn.linkedin-bg.is-set  { background: #0A66C2; }
.social-btn.facebook-bg.is-set  { background: #1877F2; }
.social-btn.instagram-bg.is-set { background: #E4405F; }
.social-btn.xtwitter-bg.is-set  { background: #1D1D1F; }
.social-btn.youtube-bg.is-set   { background: #FF0000; }

.social-remove {
    position: absolute;
    top: -6px;
    inset-inline-end: -6px;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.875rem;
    background: var(--danger);
    color: #fff;
    border: 2px solid var(--card-bg);
    cursor: pointer;
    opacity: 0;
    transition: opacity var(--ease-fast);
}

/* Revealed on hover, but also on keyboard focus — hover-only would strand tab users. */
.social-item:hover .social-remove,
.social-remove:focus-visible { opacity: 1; }

.social-name {
    font-size: 0.6875rem;
    font-weight: 600;
    color: var(--bs-secondary-color);
}

.social-editor {
    margin-top: 1rem;
    padding: 1rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 12px;
    background: var(--bs-tertiary-bg);
}

.social-editor-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.social-editor-controls .form-control { flex: 1 1 240px; }

/* ── Plans & Billing Tab ───────────────── */
.plan-current-badge {
    width: 48px;
    height: 48px;
    border-radius: 10px;
    background: rgba(var(--bs-primary-rgb), 0.1);
    color: var(--bs-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
}

.plan-card {
    background: var(--card-bg);
    border-radius: 16px;
    border: 1.5px solid var(--bs-border-color);
    padding: 1.5rem;
    display: flex;
    flex-direction: column;
    height: 100%;
    position: relative;
    transition: all 0.2s ease;
}

.plan-card:hover {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.plan-card--active {
    border: 2px dashed var(--bs-primary);
    box-shadow: none;
    padding-top: 2.25rem;
    overflow: visible;
}

.plan-card-badge {
    position: absolute;
    top: -13px;
    left: 50%;
    transform: translateX(-50%);
    padding: 5px 20px;
    border-radius: 9999px;
    background: var(--bs-primary);
    color: #fff;
    font-size: 0.6875rem;
    font-weight: 800;
    text-align: center;
    text-transform: uppercase;
    letter-spacing: 0.8px;
    white-space: nowrap;
    z-index: 2;
    box-shadow: 0 2px 6px rgba(var(--bs-primary-rgb), 0.3);
}

.plan-card-header {
    margin-bottom: 1rem;
}

.plan-card-name {
    font-weight: 800;
    color: var(--bs-body-color);
    margin-bottom: 4px;
}

.plan-card-name--active {
    color: var(--bs-body-color);
}

.plan-card-price {
    font-size: 2.5rem;
    font-weight: 800;
    color: var(--bs-body-color);
    line-height: 1.2;
}

.plan-card-price span {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--bs-tertiary-color);
}

.plan-card-desc {
    font-size: 0.875rem;
    color: var(--bs-tertiary-color);
    margin-bottom: 0;
    margin-top: 6px;
}

.plan-card-features {
    list-style: none;
    padding: 0;
    margin: 0 0 1.25rem;
    flex: 1;
}

.plan-card-features li {
    padding: 5px 0;
    font-size: 0.875rem;
    color: var(--bs-body-color);
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Your standing against this tier's limit. Sits after the limit and stays subordinate to it —
   it is context, not a competing claim. Amber only when the tier genuinely doesn't fit. */
.plan-usage-note {
    margin-inline-start: auto;
    padding: 1px 7px;
    border-radius: 9999px;
    background: var(--bs-secondary-bg);
    font-size: 0.6875rem;
    font-weight: 600;
    white-space: nowrap;
    color: var(--bs-secondary-color);
}

.plan-usage-note.is-exceeded {
    background: rgba(217, 119, 6, 0.12);
    color: var(--warning);
}

.plan-card--dark .plan-usage-note {
    background: rgba(255, 255, 255, 0.12);
    color: rgba(255, 255, 255, 0.85);
}

.plan-card-features li i {
    color: var(--bs-tertiary-color);
    font-size: 1rem;
    width: 1rem;
    text-align: center;
    flex-shrink: 0;
}

.plan-card-features--active li i {
    color: var(--bs-primary);
}

/* "Pricing TBD" smaller text instead of dollar amount */
.plan-card-price--tbd {
    font-size: 1.75rem;
}

/* Excluded feature (red X) */
.plan-feature-excluded {
    color: #ef4444 !important;
}

.plan-feature-excluded i {
    color: #ef4444 !important;
}

/* Dark card — Enterprise / Custom */
.plan-card--dark {
    background: #0f172a;
    border-color: #1e293b;
    color: #f1f5f9;
}

.plan-card--dark:hover {
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
}

.plan-card--dark .plan-card-name {
    color: var(--bs-primary);
}

.plan-card--dark .plan-card-price {
    color: #f1f5f9;
}

.plan-card--dark .plan-card-desc {
    color: #94a3b8;
}

.plan-card--dark .plan-card-features li {
    color: #cbd5e1;
}

.plan-card--dark .plan-card-features li i {
    color: var(--bs-primary);
}

/* Three-dot menu on current paid plan cards */
.plan-card-menu {
    position: absolute;
    top: 12px;
    inset-inline-end: 12px;
    z-index: 3;
}

.plan-card-menu-btn {
    width: 32px;
    height: 32px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--bs-border-color);
    border-radius: 8px;
    background: var(--card-bg);
    color: var(--bs-tertiary-color);
    font-size: 1.1rem;
    transition: all 0.15s ease;
}

.plan-card-menu-btn:hover {
    background: var(--bs-gray-100);
    color: var(--bs-body-color);
}

.plan-card-dropdown {
    border-radius: 10px;
    border: 1px solid var(--bs-border-color);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
    padding: 4px;
    min-width: 140px;
}

.plan-card-dropdown .dropdown-item {
    border-radius: 6px;
    font-size: 0.875rem;
    font-weight: 500;
    padding: 8px 12px;
}

.plan-card-dropdown .dropdown-item:hover {
    background: rgba(239, 68, 68, 0.08);
}

/* Free trial expiry alert */
.plan-trial-alert {
    display: flex;
    align-items: center;
    gap: 12px;
    background: #fef3e2;
    border: 1px solid #fde5c3;
    border-radius: 10px;
    padding: 10px 14px;
    margin-bottom: 1rem;
}

.plan-trial-icon {
    width: 36px;
    height: 38px;
    border-radius: 6px;
    background: #1e293b;
    display: flex;
    flex-direction: column;
    align-items: center;
    overflow: hidden;
    flex-shrink: 0;
}

.plan-trial-icon-top {
    width: 100%;
    height: 10px;
    background: #1e293b;
    border-bottom: 2px solid #334155;
}

.plan-trial-icon-day {
    font-size: 0.875rem;
    font-weight: 800;
    color: #ef4444;
    line-height: 1;
    padding-top: 3px;
}

.plan-trial-label {
    font-size: 0.6875rem;
    font-weight: 600;
    color: var(--bs-gray-500);
    letter-spacing: 0.5px;
    text-transform: uppercase;
    line-height: 1.2;
}

.plan-trial-date {
    font-size: 0.9375rem;
    font-weight: 700;
    color: var(--bs-body-color);
    line-height: 1.3;
}

/* Trial expiry alert — dark mode */
[data-bs-theme="dark"] .plan-trial-alert {
    background: rgba(251, 191, 36, 0.1);
    border-color: rgba(251, 191, 36, 0.2);
}
[data-bs-theme="dark"] .plan-trial-icon {
    background: #0f172a;
}
[data-bs-theme="dark"] .plan-trial-icon-top {
    background: #0f172a;
    border-bottom-color: #475569;
}
[data-bs-theme="dark"] .plan-trial-label {
    color: var(--bs-gray-600);
}
[data-bs-theme="dark"] .plan-trial-date {
    color: var(--bs-gray-900);
}

/* ── Trial countdown ring ── */
.plan-trial-ring-wrap {
    display: flex;
    align-items: center;
    gap: 12px;
    background: #fef3e2;
    border: 1px solid #fde5c3;
    border-radius: 10px;
    padding: 10px 14px;
    margin-bottom: 1rem;
}
.plan-trial-ring-svg {
    width: 52px;
    height: 52px;
    flex-shrink: 0;
}
.plan-trial-ring-track {
    stroke: #e2e8f0;
}
.plan-trial-ring-num {
    font-size: 11px;
    font-weight: 800;
    fill: var(--bs-body-color);
}
.plan-trial-ring-label {
    font-size: 6.5px;
    font-weight: 600;
    fill: var(--bs-secondary-color);
    text-transform: uppercase;
    letter-spacing: 0.3px;
}
.plan-trial-ring-info { flex: 1; min-width: 0; text-align: center; }
.trial-ring-green .plan-trial-ring-track { stroke: #dcfce7; }
.trial-ring-amber .plan-trial-ring-track { stroke: #fef3c7; }
.trial-ring-red .plan-trial-ring-track   { stroke: #fee2e2; }

/* Dark mode ring */
[data-bs-theme="dark"] .plan-trial-ring-wrap {
    background: rgba(251, 191, 36, 0.08);
    border-color: rgba(251, 191, 36, 0.18);
}
[data-bs-theme="dark"] .plan-trial-ring-track { stroke: #1e293b; }
[data-bs-theme="dark"] .trial-ring-green .plan-trial-ring-track { stroke: rgba(34,197,94,0.15); }
[data-bs-theme="dark"] .trial-ring-amber .plan-trial-ring-track { stroke: rgba(245,158,11,0.15); }
[data-bs-theme="dark"] .trial-ring-red   .plan-trial-ring-track { stroke: rgba(239,68,68,0.15); }
[data-bs-theme="dark"] .plan-trial-ring-num  { fill: var(--bs-body-color); }
[data-bs-theme="dark"] .plan-trial-ring-label { fill: var(--bs-secondary-color); }

/* ── Trial urgency banner ── */
.trial-urgency-banner {
    border-inline-start-color: #f59e0b;
}
.trial-urgency-banner .overquota-icon {
    background: rgba(245, 158, 11, 0.12);
    color: #d97706;
}
.trial-urgency-banner .overquota-title {
    color: #d97706;
}
.trial-urgency-banner .overquota-btn {
    background: #d97706;
    color: #fff;
    border-color: transparent;
}
.trial-urgency-banner .overquota-btn:hover {
    background: #b45309;
    color: #fff;
}
[data-bs-theme="dark"] .trial-urgency-banner {
    background: rgba(245, 158, 11, 0.06);
    border-inline-start-color: #f59e0b;
}
[data-bs-theme="dark"] .trial-urgency-banner .overquota-icon {
    background: rgba(245, 158, 11, 0.16);
    color: #fbbf24;
}
[data-bs-theme="dark"] .trial-urgency-banner .overquota-title {
    color: #fbbf24;
}

.plan-card-btn {
    width: 100%;
}

/* ── Storage Tab ──────────────────────────── */
.storage-plan-icon {
    width: 44px;
    height: 44px;
    border-radius: 10px;
    background: rgba(var(--bs-primary-rgb), 0.1);
    color: var(--bs-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.25rem;
}

.storage-progress-track {
    width: 100%;
    height: 10px;
    background: var(--bs-gray-100);
    border-radius: 9999px;
    overflow: hidden;
}

.storage-progress-bar {
    height: 100%;
    background: var(--bs-primary);
    border-radius: 9999px;
    transition: width 0.6s ease;
}

/* Expandable project item wrapper */
.storage-project-item {
    border-bottom: 1px solid var(--bs-border-color);
}

.storage-project-item:last-child {
    border-bottom: none;
}

/* Storage by project rows */
.storage-project-row {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 1rem 1.25rem;
    cursor: pointer;
    transition: background-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}

.storage-project-row:hover {
    background-color: var(--bs-gray-50);
    transform: translateY(-1px);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}

/* Chevron icon for expand/collapse */
.storage-project-chevron {
    font-size: 1.15rem;
    color: var(--bs-gray-400);
    transition: transform 0.2s ease;
    flex-shrink: 0;
}

.storage-project-item.expanded .storage-project-chevron {
    transform: rotate(90deg);
    color: var(--bs-primary);
}

.storage-project-info {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 10px;
}

.storage-project-name {
    font-weight: 700;
    color: var(--bs-body-color);
    font-size: 1.125rem;
    letter-spacing: -0.01em;
    line-height: 1.3;
    transition: color 0.15s ease;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.storage-project-meta {
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
    font-weight: 500;
    margin-top: 2px;
}

.storage-project-row:hover .storage-project-name {
    color: var(--bs-primary);
}

/* Expandable detail panel */
.storage-project-detail {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.25s ease, padding 0.25s ease;
    background: var(--bs-gray-50);
    padding-block: 0;
    padding-inline: 3.25rem 1.25rem;
}

.storage-project-detail.open {
    max-height: 200px;
    padding-block: 0.75rem 1rem;
    padding-inline: 3.25rem 1.25rem;
}

/* ── macOS-style segmented storage detail ──────────────── */

/* Segmented bar — uploaded vs processed (project-level) */
.sd-segmented-bar {
    display: flex;
    height: 12px;
    border-radius: 6px;
    overflow: hidden;
    background: var(--bs-gray-200);
    margin-bottom: 0.75rem;
}

.sd-segment {
    height: 100%;
    min-width: 0;
    transition: width 0.3s ease;
}

.sd-segment--uploaded {
    background: var(--bs-primary);
    border-start-start-radius: 6px;
    border-start-end-radius: 0;
    border-end-end-radius: 0;
    border-end-start-radius: 6px;
}

.sd-segment--processed {
    background: #16a34a;
}

/* When uploaded is 0 and processed is first, round left */
.sd-segment--uploaded:first-child {
    border-start-start-radius: 6px;
    border-start-end-radius: 0;
    border-end-end-radius: 0;
    border-end-start-radius: 6px;
}

/* Legend — colored dots + label + size + time */
.sd-legend {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.sd-legend-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.875rem;
}

.sd-legend-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
}

.sd-legend-dot--uploaded {
    background: var(--bs-primary);
}

.sd-legend-dot--processed {
    background: #16a34a;
}

.sd-legend-dot--free {
    background: var(--bs-gray-200);
}

.sd-legend-label {
    color: var(--bs-body-color);
    font-weight: 500;
    min-width: 110px;
}

.sd-legend-size {
    font-weight: 600;
    color: var(--bs-body-color);
    min-width: 60px;
}

.sd-legend-time {
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-inline-start: auto;
}

.sd-legend-time i {
    font-size: 0.875rem;
}

.storage-project-status {
    display: inline-flex;
    align-items: center;
    padding: 2px 10px;
    border-radius: 9999px;
    font-size: 0.8125rem;
    font-weight: 500;
    border: 1px solid;
    white-space: nowrap;
}

.storage-project-status.status-active {
    color: #16a34a;
    border-color: rgba(22, 163, 74, 0.3);
    background: rgba(22, 163, 74, 0.05);
}

.storage-project-status.status-archived {
    color: var(--bs-gray-500);
    border-color: var(--bs-border-color);
    background: var(--bs-gray-50);
}

.storage-project-status.status-processing {
    color: #d97706;
    border-color: rgba(217, 119, 6, 0.3);
    background: rgba(217, 119, 6, 0.05);
}

.storage-project-status.status-completed {
    color: var(--bs-primary);
    border-color: rgba(var(--bs-primary-rgb), 0.3);
    background: rgba(var(--bs-primary-rgb), 0.05);
}

.storage-project-bar {
    width: 100px;
    height: 6px;
    background: var(--bs-gray-100);
    border-radius: 9999px;
    overflow: hidden;
    flex-shrink: 0;
}

.storage-project-bar-fill {
    height: 100%;
    background: var(--bs-primary);
    border-radius: 9999px;
}

.storage-project-size {
    font-weight: 600;
    color: var(--bs-body-color);
    font-size: 0.875rem;
    white-space: nowrap;
    min-width: 60px;
    text-align: end;
}

/* ── Team Members Tab ──────────────────── */
.member-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.875rem 1.5rem;
    border-bottom: 1px solid var(--bs-border-color);
    transition: background 0.2s ease;
}

.member-row:hover {
    background: var(--bs-gray-50);
}

.member-info {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}

.member-avatar {
    width: 38px;
    height: 38px;
    min-width: 38px;
    border-radius: 50%;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.875rem;
    font-weight: 700;
    text-transform: uppercase;
}

.member-avatar-img {
    width: 38px;
    height: 38px;
    border-radius: 50%;
    object-fit: cover;
}

.member-name {
    font-weight: 700;
    color: var(--bs-body-color);
    font-size: 0.9375rem;
}

.member-email {
    font-size: 0.8125rem;
    color: var(--bs-tertiary-color);
    font-weight: 500;
}

.member-you-badge {
    display: inline-block;
    padding: 1px 8px;
    border-radius: 9999px;
    background: rgba(var(--bs-primary-rgb), 0.1);
    color: var(--bs-primary);
    font-size: 0.6875rem;
    font-weight: 600;
    margin-inline-start: 6px;
    vertical-align: middle;
}

.member-meta {
    display: flex;
    align-items: center;
    gap: 10px;
}

.member-role-badge {
    display: inline-block;
    padding: 4px 14px;
    border-radius: 9999px;
    font-size: 0.8125rem;
    font-weight: 600;
    border: 1px solid var(--bs-border-color);
    background: var(--card-bg);
    color: var(--bs-tertiary-color);
}

.member-role-badge.role-admin {
    border-color: rgba(var(--bs-primary-rgb), 0.3);
    color: var(--bs-primary);
    background: rgba(var(--bs-primary-rgb), 0.04);
}

.member-more-btn {
    width: 32px;
    height: 32px;
    border: none;
    background: none;
    color: var(--bs-tertiary-color);
    border-radius: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 1.25rem;
    transition: all 0.2s ease;
}

.member-more-btn:hover {
    background: var(--bs-gray-100);
    color: var(--bs-gray-700);
}

/* ── Social brand colors (shared) ──────── */
.linkedin-color { color: #0A66C2; }
.facebook-color { color: #1877F2; }
.instagram-color { color: #E4405F; }
.twitter-color { color: #000000; }

/* ======================================
   Section 19: Users Page
   ====================================== */
.action-icon {
    width: 32px;
    height: 32px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--bs-border-color);
    background: var(--card-bg);
    color: var(--bs-secondary-color);
    cursor: pointer;
    transition: all 0.2s ease;
    font-size: 15px;
}

.action-icon:hover:not(:disabled) {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

/* A row mid-upload has nothing to download yet, but dropping the button shifts every
   other action along and reads as a missing feature. Keep the slot, state why. */
.action-icon:disabled {
    opacity: 0.4;
    cursor: not-allowed;
    box-shadow: none;
}

.action-icon.view:hover { color: var(--bs-primary); border-color: var(--bs-primary); background: rgba(var(--bs-primary-rgb), 0.06); }
.action-icon.edit:hover { color: #8B5CF6; border-color: #8B5CF6; background: rgba(139, 92, 246, 0.06); }
.action-icon.members:hover { color: #0891b2; border-color: #0891b2; background: rgba(8, 145, 178, 0.06); }
.action-icon.download:hover { color: #059669; border-color: #059669; background: rgba(5, 150, 105, 0.06); }

/* Action icon color variants — neutral by default, colored on hover (consistent with view/edit/members) */
.action-icon-danger:hover  { color: #ef4444; border-color: #ef4444; background: rgba(239, 68, 68, 0.06); }
.action-icon-primary:hover { color: var(--bs-primary); border-color: var(--bs-primary); background: rgba(var(--bs-primary-rgb), 0.06); }

.detail-card {
    background: var(--bs-gray-50);
    border-radius: 10px;
    padding: 1rem 1.25rem;
    border: 1px solid var(--bs-gray-100);
}

.detail-card-inner {
    display: flex;
    align-items: center;
    gap: 14px;
    /* Lets the text block shrink instead of shoving the icon out of the card. */
    min-width: 0;
}

.detail-card-inner > div:last-child {
    min-width: 0;
}

.detail-icon {
    width: 44px;
    height: 44px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.25rem;
    flex-shrink: 0;
}

.detail-icon-primary { background: rgba(var(--bs-primary-rgb), 0.1); color: var(--bs-primary); }
.detail-icon-success { background: rgba(var(--bs-success-rgb), 0.1); color: var(--bs-success); }
.detail-icon-warning { background: rgba(var(--bs-warning-rgb), 0.1); color: var(--bs-warning); }
.detail-icon-danger  { background: rgba(var(--bs-danger-rgb), 0.1);  color: var(--bs-danger); }

.detail-label {
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 600;
    margin-bottom: 0.25rem;
}

.detail-value {
    font-size: 1.125rem;
    font-weight: 700;
    color: var(--bs-emphasis-color);
    margin-bottom: 0;
}

/* Stat card row — four across on desktop, two on tablet, one on phone. Explicit
   breakpoints rather than auto-fit: auto-fit would drop to an odd three-across at
   some widths, leaving one card stranded on its own row. */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 1rem;
}

@media (max-width: 1399.98px) {
    .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 575.98px) {
    .stat-grid { grid-template-columns: minmax(0, 1fr); }
}

/* Second line on a stat card — context for the number above it (quota share, who
   touched it). Collapses to nothing when empty so cards without one keep their height. */
.detail-sub {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--bs-secondary-color);
    margin-top: 0.125rem;
}

.detail-sub:empty {
    display: none;
}

.detail-sub.is-warning {
    color: var(--warning);
}

/* Text column of a stat card. Named rather than left as `> div:last-child` because the cards
   now hold four different shapes and one of them (Storage) has a bar between value and sub. */
.stat-body { min-width: 0; }

/* Bar under the Storage figure — this project's share of everything the team has stored, the
   same percentage the line below it states. Measured against usage rather than the plan; the
   plan figure is the sidebar widget's job. `hidden` until storageQuota resolves, so a slow lookup
   shows no bar rather than an empty trough. */
.quota-bar {
    height: 4px;
    border-radius: 999px;
    background: var(--bs-secondary-bg);
    overflow: hidden;
    margin: 0.375rem 0 0.25rem;
}

.quota-fill {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: var(--bs-primary);
    transition: width 0.4s ease;
}

/* What a project delete is about to destroy, listed in the confirmation. The generic warning
   above it reads identically whether the project is empty or holds a year of survey work, so
   it cannot help anyone notice they picked the wrong row. */
.ph-del-grid { display: flex; flex-wrap: wrap; gap: 6px; }
.ph-del-item {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 4px 9px; border-radius: 6px;
    background: rgba(var(--bs-danger-rgb), 0.08);
    color: var(--bs-body-color);
    font-size: 0.75rem; line-height: 1.3;
}
.ph-del-item i { font-size: 0.875rem; color: var(--bs-danger); }
.ph-del-item strong { font-weight: 700; }
.ph-del-item.ph-del-empty { background: var(--bs-secondary-bg); }
.ph-del-item.ph-del-empty i { color: var(--bs-secondary-color); }

/* Consent, not decoration: the confirm button stays disabled until this is ticked. */
.ph-del-consent {
    display: flex; align-items: flex-start; gap: 8px;
    padding: 8px 10px; border-radius: 8px;
    border: 1px solid var(--bs-border-color);
    font-size: 0.8125rem; cursor: pointer;
}
.ph-del-consent:hover { border-color: var(--bs-danger); }
.ph-del-consent input { margin-top: 2px; flex-shrink: 0; accent-color: var(--bs-danger); }

/* ── View Map button (project details) ──────────────── */
.btn-map {
    background: linear-gradient(135deg, #0d9488, #14b8a6);
    color: #fff !important; border: none;
    box-shadow: 0 2px 8px rgba(20, 184, 166, 0.2);
    transition: all 0.25s ease;
    text-decoration: none;
    position: relative; overflow: hidden;
}
.btn-map::before {
    content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
    background: linear-gradient(90deg, transparent, rgba(255,255,255,0.15), transparent);
    animation: map-shimmer 3s ease-in-out infinite;
}
@keyframes map-shimmer {
    0% { left: -100%; }
    50%, 100% { left: 100%; }
}

/* ═══════════════════════════════════════════════════
   Skeleton Loading System — Facebook/Instagram pattern
   - .skel       = static gray bone (no animation)
   - .skel-wave  = parent container; ::after sweeps one
                      unified light wave across all bones
   ═══════════════════════════════════════════════════ */

@keyframes skel-sweep {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(100%); }
}

/* Bone — static gray shape, no animation */
.skel {
    background: #dde3ec;
    border-radius: 4px;
    display: inline-block;
    position: relative;
    overflow: hidden;
}

/* Wave container — one shimmer sweeps all bones inside */
.skel-wave {
    position: relative;
    overflow: hidden;
}
.skel-wave::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(
        90deg,
        transparent 20%,
        rgba(255, 255, 255, 0.55) 50%,
        transparent 80%
    );
    animation: skel-sweep 1.6s ease-in-out infinite;
    pointer-events: none;
    z-index: 1;
}

/* Dark mode */
[data-bs-theme="dark"] .skel {
    background: #1e293b;
}
[data-bs-theme="dark"] .skel-wave::after {
    background: linear-gradient(
        90deg,
        transparent 20%,
        rgba(255, 255, 255, 0.07) 50%,
        transparent 80%
    );
}

/* ── Bone size tokens ── */
.skel-name         { width: 90px;  height: 13px; }
.skel-role         { width: 52px;  height: 11px; margin-top: 3px; }
.skel-avatar       { width: 28px;  height: 28px; border-radius: 50%; flex-shrink: 0; }
.skel-badge        { width: 72px;  height: 12px; }
.skel-pct          { width: 36px;  height: 11px; }
.skel-storage-text { width: 60px;  height: 11px; }
.skel-pill         { width: 90px;  height: 24px; border-radius: 20px; vertical-align: middle; margin: 2px 3px; display: inline-flex; }

/* ── Notification row bones ── */
.notif-skel-item {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 14px;
}
.notif-skel-icon  { width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0; }
.notif-skel-body  { flex: 1; display: flex; flex-direction: column; gap: 5px; padding-top: 3px; }
.notif-skel-line1 { height: 11px; width: 80%; border-radius: 4px; }
.notif-skel-line2 { height: 10px; width: 50%; border-radius: 4px; }
.btn-map i {
    animation: map-pulse 2s ease-in-out infinite;
}
@keyframes map-pulse {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.15); }
}
.btn-map:hover {
    background: linear-gradient(135deg, #0f766e, #0d9488);
    box-shadow: 0 4px 16px rgba(20, 184, 166, 0.35);
    transform: translateY(-1px);
    color: #fff !important;
}

/* ── Dataset Details: back arrow ─────────────────────── */
.ds-back-arrow {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--bs-border-color);
    background: var(--card-bg);
    color: var(--bs-secondary-color);
    text-decoration: none;
    font-size: 1.2rem;
    transition: all 0.2s ease;
    flex-shrink: 0;
}
.ds-back-arrow:hover {
    color: var(--bs-primary);
    border-color: var(--bs-primary);
    background: rgba(var(--bs-primary-rgb), 0.06);
    transform: translateY(-1px);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

/* ── Upload Dataset modal: Geo Spatial API ───────────── */
/* The verdict after connecting. Laid out as the selected-file card above it is (#dsSelectedFile):
   the same padding, radius, icon size and two lines of text. Tinted by outcome - the success tint
   is the status badges' (.status-badge--active), the danger one this panel's own error box. */
.api-status {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 10px 14px;
    border-radius: 10px;
    border: 1px solid rgba(var(--bs-primary-rgb), 0.15);
    background: rgba(var(--bs-primary-rgb), 0.04);
}
.api-status-icon { font-size: 1.5rem; line-height: 1; flex-shrink: 0; color: var(--bs-primary); }
.api-status-body { min-width: 0; }
.api-status-title { font-size: 0.875rem; font-weight: 600; color: var(--bs-body-color); }
.api-status-text { font-size: 0.75rem; color: var(--bs-secondary-color); overflow-wrap: anywhere; }
.api-status-text strong { font-weight: 600; color: var(--bs-body-color); }

.api-status.is-ok {
    border-color: color-mix(in srgb, var(--success) 30%, transparent);
    background: color-mix(in srgb, var(--success) 5%, transparent);
}
.api-status.is-ok .api-status-icon { color: var(--success); }

.api-status.is-blocked {
    border-color: var(--bs-danger-border-subtle);
    background: var(--bs-danger-bg-subtle);
}
.api-status.is-blocked .api-status-icon { color: var(--danger); }
.api-status.is-blocked .api-status-text { color: var(--bs-body-color); }

/* The token dialog. The method is a fixed tag on the URL, not a choice: signing in is a POST. */
.api-token-method {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: var(--bs-secondary-color);
}
/* "Token added" on the Authentication row, in the success colour the verdict card uses. */
.api-token-ready { color: var(--success); font-weight: 600; }
/* A hint that is a warning or an error. The warning takes the emphasis shade the unique-field
   hint already uses: plain --warning is too light to read as text at this size. */
.form-hint.hint-warn { color: var(--bs-warning-text-emphasis); }
.form-hint.hint-error { color: var(--danger); }
.form-hint.hint-ok { color: var(--success); }
.form-hint strong { color: var(--bs-body-color); font-weight: 600; }

/* The Unique identifier "dropdown": a button in the form-select's clothes, so it sits beside Sync
   frequency as its twin, and opens the dialog below instead of a native list. */
.api-key-select {
    display: block;
    text-align: start;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The unique-identifier dialog: folder-picker rows (dsx-picker-node) holding a radio, the field, a
   sample of what it holds, and its verdict. The chosen row takes the picker's selected tint. */
.api-key-option { cursor: pointer; margin: 0; }
.api-key-option .form-check-input { flex: none; margin: 0; }
.api-key-option:has(.form-check-input:checked) {
    background: rgba(var(--bs-primary-rgb), 0.09);
    border-color: rgba(var(--bs-primary-rgb), 0.4);
}
.api-key-option.is-excluded:hover { background: transparent; border-color: transparent; }
.api-key-sample {
    margin-inline-start: 0.5rem;
    font-size: 0.75rem;
    font-weight: 400;
    color: var(--bs-secondary-color);
}
.api-key-state {
    flex: none;
    padding: 0.0625rem 0.375rem;
    border-radius: 6px;
    font-size: 0.6875rem;
    font-weight: 600;
    white-space: nowrap;
}
.api-key-state.is-ok {
    color: var(--success);
    background: color-mix(in srgb, var(--success) 10%, transparent);
}
.api-key-state.is-bad {
    color: var(--danger);
    background: color-mix(in srgb, var(--danger) 10%, transparent);
}

/* The attribute picker (#dsApiAttrModal). Everything that can be shared with the folder picker
   is: the tree box, the rows, the guide rails, the icons and the counts are its dsx-picker-*
   classes. What is here is only what a checkbox tree beside a JSON pane needs on top. */
.api-picker-panes {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 14px;
}
.api-pane { display: flex; flex-direction: column; min-width: 0; }
/* One height on both sides, so the two boxes start level. */
.api-pane-head {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    min-height: 1.5rem;
    margin-bottom: 0.375rem;
}
/* Small text actions beside a label - the review step's "edit" link (.review-edit), as a button. */
.api-pane-link {
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--bs-primary);
    cursor: pointer;
}
.api-pane-link:hover { text-decoration: underline; }
.api-pane-link:focus-visible {
    outline: 3px solid rgba(var(--bs-primary-rgb), 0.35);
    outline-offset: 2px;
    border-radius: 4px;
}
/* Both panes one height, so the dialog does not resize as the selection changes. */
.api-pane .dsx-picker-tree,
.api-json {
    height: min(360px, calc(100vh - 22rem));
    min-height: 200px;
    max-height: none;
}
@media (max-width: 767.98px) {
    .api-picker-panes { grid-template-columns: minmax(0, 1fr); }
    .api-pane .dsx-picker-tree,
    .api-json { height: 240px; }
}

/* A folder row is a button; this one is a row holding a checkbox, so it gains a gap for it. */
.api-node { cursor: pointer; }
.api-node .form-check-input { flex: none; margin: 0; }
.api-node .dsx-picker-name { cursor: pointer; margin: 0; }
.api-node:has(.form-check-input:disabled) { cursor: default; }

/* Which field the location comes from - the brand badge, at the size of a picker count. */
.api-node-badge {
    flex: none;
    padding: 0.0625rem 0.375rem;
    border-radius: 6px;
    background: rgba(var(--bs-primary-rgb), 0.1);
    color: var(--bs-primary);
    font-size: 0.6875rem;
    font-weight: 600;
}

/* The live preview: the tree's box, holding JSON. */
.api-json {
    margin: 0;
    padding: 0.5rem 0.625rem;
    overflow: auto;
    border: 1px solid var(--bs-border-color);
    border-radius: 10px;
    background: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
    font-family: var(--bs-font-monospace);
    font-size: 0.75rem;
    line-height: 1.55;
    white-space: pre-wrap;
    word-break: break-word;
}
.json-key { color: var(--bs-primary); font-weight: 600; }
.json-str { color: var(--success); }
.json-num { color: var(--warning); }
.json-bool { color: var(--danger); }
.json-null { color: var(--bs-secondary-color); }

/* ── Upload Dataset modal: drop zone ─────────────────── */

.api-kv {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
/* An empty table says so, rather than leaving a label above nothing. */
.api-kv:empty::before {
    content: "None added \2014 use the button above to add one.";
    display: block;
    padding: 8px 10px;
    border: 1px dashed var(--bs-border-color);
    border-radius: 8px;
    font-size: 0.6875rem;
    color: var(--bs-secondary-color);
}
/* Key narrower than value: header names are short, tokens are not. */
.api-kv [data-kv-key] { flex: 0 0 32%; min-width: 0; }
.api-kv [data-kv-value] { flex: 1 1 auto; min-width: 0; }
.api-kv [data-kv-remove] { flex: 0 0 auto; }
.api-kv input[readonly] { background: var(--bs-secondary-bg); }

.ds-upload-zone {
    border: 2px dashed var(--bs-primary);
    border-radius: 12px;
    padding: 24px 16px 16px;
    text-align: center;
    cursor: pointer;
    background: rgba(var(--bs-primary-rgb), 0.02);
    transition: background 0.2s, border-color 0.2s;
}
.ds-upload-zone:hover {
    background: rgba(var(--bs-primary-rgb), 0.06);
}
.ds-upload-zone.dragover {
    background: rgba(var(--bs-primary-rgb), 0.08);
    border-color: var(--bs-primary);
}

/* ── Upload Dataset modal: the photograph batch ───────────────
   Photographs ride the same wizard as a dataset, but arrive many at a time, so the
   single selected-file card cannot represent them. Same card language as that one —
   tinted primary panel, same radius — repeated per file. */
.ds-photo-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    margin-bottom: 6px;
    border-radius: 10px;
    background: rgba(var(--bs-primary-rgb), 0.04);
    border: 1px solid rgba(var(--bs-primary-rgb), 0.15);
}
.ds-photo-row:last-child { margin-bottom: 0; }
.ds-photo-icon { flex: none; font-size: 1.1rem; color: var(--bs-primary); }
.ds-photo-name {
    flex: 1 1 auto; min-width: 0;
    font-size: 0.8125rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* A frame that already carries its own position. Absence is not an error — plenty of
   cameras record none — so it is a quiet mark, never a warning. */
.ds-photo-gps { flex: none; font-size: 0.9rem; color: var(--bs-success); }
/* The frame's own capture date, read from the file in the browser. "no date" is a
   statement about the file, not a fault, so it steps back rather than shouting. */
.ds-photo-date {
    flex: none;
    font-size: 0.72rem; color: var(--bs-secondary-color);
    white-space: nowrap;
}
.ds-photo-date.is-missing { font-style: italic; opacity: 0.75; }
.ds-photo-size {
    flex: none;
    font-size: 0.75rem; color: var(--bs-secondary-color);
    font-variant-numeric: tabular-nums;
}
.ds-photo-remove {
    flex: none;
    padding: 0 2px;
    border: none; background: none; line-height: 1; cursor: pointer;
    color: var(--bs-secondary-color);
}
.ds-photo-remove:hover { color: var(--bs-danger); }
.ds-ext-tag {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 4px;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--bs-primary);
    background: rgba(var(--bs-primary-rgb), 0.1);
}

/* ── Upload Stepper Wizard ──────────────────────────────── */
.stepper-header {
    display: flex; align-items: center; justify-content: center;
    padding: 0.5rem 1rem 0.75rem; margin-bottom: 0;
    border-bottom: 1px solid var(--bs-border-color);
}
.stepper-step {
    display: flex; align-items: center; gap: 0.5rem;
    cursor: default; opacity: 0.45;
    transition: opacity 0.2s ease;
}
.stepper-step.active,
.stepper-step.completed { opacity: 1; }
.stepper-circle {
    width: 26px; height: 26px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    font-size: 0.75rem; font-weight: 700;
    border: 2px solid var(--bs-gray-400); color: var(--bs-gray-500);
    background: transparent; transition: all 0.2s ease; flex-shrink: 0;
}
.stepper-step.active .stepper-circle {
    border-color: var(--bs-primary); background: var(--bs-primary); color: #fff;
}
.stepper-step.completed .stepper-circle {
    border-color: #16a34a; background: #16a34a; color: #fff;
}
.stepper-label {
    font-size: 0.8125rem; font-weight: 500; color: var(--bs-body-color); white-space: nowrap;
}
.stepper-line {
    flex: 1; height: 2px; background: var(--bs-gray-300);
    margin: 0 0.75rem; min-width: 32px; transition: background 0.2s ease;
}
.stepper-line.completed { background: #16a34a; }
/* One height for all three steps.
   The panels are naturally different lengths -- Classify is a type grid, Upload adds a file
   card and three fields, Review is a short read-only list -- so the dialog resized under the
   cursor on every Next. Going from Upload to Review shrank it enough that the pointer ended
   up on the backdrop, and the click that landed there dismissed the whole modal mid-upload.
   A 340px floor alone still let the dialog grow on Upload and shrink back on Review.

   So every step sits in the same grid cell and the cell is as tall as the tallest one: the
   steps not on show are invisible (visibility, not display, so they keep their height, and
   hidden also takes them out of the tab order and away from screen readers). No fixed pixel
   height to keep in step with the markup. On a short screen the dialog is capped by Bootstrap's
   modal-dialog-scrollable and the step scrolls inside, with the stepper and buttons held still. */
.step-body {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    overflow: hidden;
}
/* overflow-y alone would make the step scroll sideways too: Bootstrap rows hang 4-8px past
   their parent by design. The 8px of room each side, borrowed from the body's padding, holds
   them, and sideways scrolling is switched off outright. */
.step-body > .step-panel {
    grid-row: 2;
    grid-column: 1;
    min-height: 340px;
    overflow-x: hidden;
    overflow-y: auto;
    padding-inline: 8px;
    margin-inline: -8px;
    visibility: hidden;
}
.step-body > .step-panel.active { visibility: visible; }
/* safe: once the format row makes the step taller than its cell, plain centring pushes the top
   out above the scroll area where it can never be scrolled back to (#145). */
#dsStep1 { display: flex; flex-direction: column; justify-content: center; justify-content: safe center; }
.review-grid {
    display: grid; grid-template-columns: 140px 1fr;
    gap: 0.625rem 1rem; font-size: 0.8125rem;
}
.review-label { color: var(--bs-secondary-color); font-weight: 500; }
.review-value { color: var(--bs-body-color); word-break: break-word; }
.review-edit {
    font-size: 0.75rem; cursor: pointer; color: var(--bs-primary); margin-inline-start: 0.5rem;
}
.review-edit:hover { text-decoration: underline; }
.review-file-card {
    display: flex; align-items: center; gap: 0.75rem;
    padding: 12px 16px; border-radius: 10px;
    background: rgba(var(--bs-primary-rgb), 0.05);
    border: 1px solid rgba(var(--bs-primary-rgb), 0.15);
    margin-bottom: 1rem;
}
.review-file-icon { font-size: 1.5rem; color: var(--bs-primary); }
.review-file-name { font-weight: 600; font-size: 0.875rem; }
.review-file-size { font-size: 0.75rem; color: var(--bs-secondary-color); }
[data-bs-theme="dark"] .stepper-circle { border-color: var(--bs-gray-600); color: var(--bs-gray-400); }
[data-bs-theme="dark"] .stepper-line { background: var(--bs-gray-600); }
[data-bs-theme="dark"] .review-file-card { background: rgba(var(--bs-primary-rgb), 0.08); border-color: rgba(var(--bs-primary-rgb), 0.2); }

/* ── Dataset Type Grid (Step 1 visual picker) ───────────── */
/* Seven types on a step that also has to show a format dropdown underneath. The cards
   are sized so the whole of Step 1 fits without scrolling — and shrink again, into four
   columns, the moment a format has to be chosen, because a dropdown nobody scrolls to is
   a dropdown nobody fills in. */
.type-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    transition: gap 0.2s ease-out;
}
.type-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 10px 10px 9px;
    border: 1.5px solid var(--bs-border-color);
    border-radius: 12px;
    background: var(--bs-body-bg);
    cursor: pointer;
    transition: border-color 0.2s ease-out, box-shadow 0.2s ease-out, background 0.2s ease-out, transform 0.15s ease-out;
    position: relative;
    text-align: center;
    min-height: 74px;
    overflow: hidden;
}
.type-card:hover {
    border-color: rgba(var(--bs-primary-rgb), 0.4);
    background: rgba(var(--bs-primary-rgb), 0.04);
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
}
.type-card:focus-visible {
    outline: 3px solid rgba(var(--bs-primary-rgb), 0.4);
    outline-offset: 2px;
}
.type-card.selected {
    border-color: var(--bs-primary);
    background: rgba(var(--bs-primary-rgb), 0.07);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.15), 0 2px 8px rgba(var(--bs-primary-rgb), 0.1);
    transform: translateY(-1px);
}
/* Icon circle container */
.type-card-icon-wrap {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(var(--bs-secondary-rgb), 0.08);
    transition: background 0.25s, transform 0.2s;
}
.type-card:hover .type-card-icon-wrap {
    background: rgba(var(--bs-primary-rgb), 0.1);
    transform: scale(1.08);
}
.type-card.selected .type-card-icon-wrap {
    background: rgba(var(--bs-primary-rgb), 0.15);
    transform: scale(1.1);
}
.type-card.selected .type-card-icon {
    color: var(--bs-primary);
}
.type-card-icon {
    font-size: 1.05rem;
    color: var(--bs-secondary-color);
    transition: color 0.2s;
    line-height: 1;
}
.type-card:hover .type-card-icon { color: var(--bs-primary); }
/* Selected checkmark */
.type-card-check {
    position: absolute;
    top: 6px;
    inset-inline-end: 8px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--bs-primary);
    color: #fff;
    display: none;
    align-items: center;
    justify-content: center;
    font-size: 0.625rem;
    line-height: 1;
}
.type-card.selected .type-card-check { display: flex; }
.type-card-name {
    font-weight: 600;
    font-size: 0.8125rem;
    line-height: 1.2;
    color: var(--bs-body-color);
    transition: color 0.2s;
}
.type-card.selected .type-card-name { color: var(--bs-primary); }
/* Label, then what the data is for, then the format codes: three sizes, three weights, each
   one line so every card in a row ends at the same height. */
.type-card-subtitle {
    margin-top: -2px;
    font-size: 0.6875rem;
    color: var(--bs-secondary-color);
    line-height: 1.2;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    transition: color 0.2s;
}
.type-card.selected .type-card-subtitle { color: rgba(var(--bs-primary-rgb), 0.85); }
.type-card-hint {
    font-size: 0.625rem;
    color: var(--bs-tertiary-color);
    line-height: 1.2;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    letter-spacing: 0.01em;
    transition: color 0.2s;
}
.type-card.selected .type-card-hint { color: rgba(var(--bs-primary-rgb), 0.7); }

/* Compact: a format still has to be chosen, so the grid gives its height to the dropdown.
   Four columns, no icon circle, no format hint — the dropdown below now lists the formats
   the hint was summarising, so keeping both would be saying it twice. */
.type-grid.is-compact { grid-template-columns: repeat(4, 1fr); gap: 6px; }
.type-grid.is-compact .type-card {
    min-height: 0;
    padding: 7px 8px;
    gap: 2px;
}
.type-grid.is-compact .type-card-icon-wrap {
    width: 24px;
    height: 24px;
    background: none;
}
.type-grid.is-compact .type-card-icon { font-size: 0.95rem; }
/* The chosen card keeps saying what it covers; the others give up the line, because the
   dropdown underneath is now the question. Their hint stays available on hover. */
.type-grid.is-compact .type-card:not(.selected) .type-card-hint { display: none; }
/* The subtitle explains the choice; once a card is chosen the dropdown is the question. */
.type-grid.is-compact .type-card-subtitle { display: none; }
.type-grid.is-compact .type-card-hint { font-size: 0.625rem; }
.type-grid.is-compact .type-card-name { font-size: 0.75rem; }
.type-grid.is-compact .type-card-check { top: 3px; inset-inline-end: 4px; width: 14px; height: 14px; font-size: 0.5rem; }

/* The format row, once it is the only thing left to answer. The ring fades on its own so
   it points without becoming permanent decoration. */
#dsFormatRow.is-awaiting .form-select {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.18);
}
/* Click ripple overlay */
.type-card-ripple {
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: radial-gradient(circle at var(--ripple-x, 50%) var(--ripple-y, 50%), rgba(var(--bs-primary-rgb), 0.15) 0%, transparent 70%);
    opacity: 0;
    pointer-events: none;
}
.type-card-badge {
    position: absolute;
    top: 4px;
    inset-inline-end: 6px;
    font-size: 0.5625rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.02em;
    color: var(--bs-success);
}
/* Dark mode */
[data-bs-theme="dark"] .type-card {
    border-color: var(--bs-gray-600);
    background: rgba(255, 255, 255, 0.025);
}
[data-bs-theme="dark"] .type-card:hover {
    border-color: rgba(var(--bs-primary-rgb), 0.5);
    background: rgba(var(--bs-primary-rgb), 0.08);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
[data-bs-theme="dark"] .type-card.selected {
    background: rgba(var(--bs-primary-rgb), 0.14);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.2), 0 2px 8px rgba(var(--bs-primary-rgb), 0.15);
}
[data-bs-theme="dark"] .type-card-icon-wrap {
    background: rgba(255, 255, 255, 0.06);
}
[data-bs-theme="dark"] .type-card:hover .type-card-icon-wrap {
    background: rgba(var(--bs-primary-rgb), 0.15);
}
[data-bs-theme="dark"] .type-card.selected .type-card-icon-wrap {
    background: rgba(var(--bs-primary-rgb), 0.22);
}

/* ── Band validation inline result ──────────────────────── */
.band-ok { color: var(--bs-success); }
.band-err { color: var(--bs-danger); }

/* Several files in one upload: one card each, green when that file is ready, red when it cannot
   go (bands, no location). The colour is never the only signal — every row also says it in words. */
.ds-bulk-list {
    list-style: none;
    margin: 8px 0 0;
    padding: 0 2px 0 0;
    max-height: 260px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.ds-bulk-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--bs-border-color);
    border-left-width: 3px;
    border-radius: 10px;
    background: var(--bs-body-bg);
}
.ds-bulk-row.is-ok {
    border-color: rgba(var(--bs-success-rgb), 0.35);
    border-left-color: var(--bs-success);
    background: rgba(var(--bs-success-rgb), 0.05);
}
.ds-bulk-row.is-bad {
    border-color: rgba(var(--bs-danger-rgb), 0.35);
    border-left-color: var(--bs-danger);
    background: rgba(var(--bs-danger-rgb), 0.06);
}
.ds-bulk-status-icon {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    font-size: 1rem;
}
.ds-bulk-row.is-ok .ds-bulk-status-icon { background: rgba(var(--bs-success-rgb), 0.14); color: var(--bs-success); }
.ds-bulk-row.is-bad .ds-bulk-status-icon { background: rgba(var(--bs-danger-rgb), 0.14); color: var(--bs-danger); }
.ds-bulk-status {
    flex: 0 0 auto;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: 0.6875rem;
    font-weight: 600;
    white-space: nowrap;
}
.ds-bulk-row.is-ok .ds-bulk-status { background: rgba(var(--bs-success-rgb), 0.12); color: var(--bs-success-text-emphasis); }
.ds-bulk-row.is-bad .ds-bulk-status { background: rgba(var(--bs-danger-rgb), 0.12); color: var(--bs-danger-text-emphasis); }
.ds-bulk-text { flex: 1 1 auto; min-width: 0; }
.ds-bulk-name-row { display: flex; align-items: center; gap: 4px; min-width: 0; }
.ds-bulk-name {
    font-size: 0.8125rem;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ds-bulk-rename {
    flex: 0 0 auto;
    border: 0;
    background: none;
    padding: 0 4px;
    border-radius: 4px;
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    line-height: 1;
}
.ds-bulk-rename:hover { color: var(--bs-primary); background: var(--bs-secondary-bg); }
.ds-bulk-rename:focus-visible { outline: 2px solid var(--bs-primary); outline-offset: 1px; }
.ds-bulk-name-input { font-size: 0.8125rem; padding: 2px 6px; height: auto; }
.ds-bulk-facts { font-size: 0.6875rem; color: var(--bs-secondary-color); }
.ds-bulk-remove { flex: 0 0 auto; font-size: 0.6rem; }

/* ── Upload modal form utilities ─────────────────────────── */
.field-label {
    font-size: 0.8125rem;
    font-weight: 600;
    margin-bottom: 2px;
    color: var(--bs-body-color);
}
.form-hint {
    font-size: 0.6875rem;
    color: var(--bs-secondary-color);
}

/* ── Upload modal: a section that opens ──────────────────
   A bordered row with a chevron, so it reads as something to press - an icon and a line of text
   on their own read as a label. Border, radius and hover are the step-1 type cards' (.type-card)
   so it belongs to the same wizard; the chevron turns with aria-expanded, which the script already
   keeps in step, so there is no second piece of state to fall out of sync. */
.disclosure {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    padding: 10px 14px;
    border: 1.5px solid var(--bs-border-color);
    border-radius: 10px;
    background: var(--bs-body-bg);
    color: var(--bs-body-color);
    font: inherit;
    text-align: start;
    cursor: pointer;
    transition: border-color 0.2s ease-out, background 0.2s ease-out;
}
.disclosure:hover {
    border-color: rgba(var(--bs-primary-rgb), 0.4);
    background: rgba(var(--bs-primary-rgb), 0.04);
}
.disclosure:focus-visible {
    outline: 3px solid rgba(var(--bs-primary-rgb), 0.4);
    outline-offset: 2px;
}
.disclosure[aria-expanded="true"] {
    border-color: rgba(var(--bs-primary-rgb), 0.4);
    background: rgba(var(--bs-primary-rgb), 0.04);
}
.disclosure-icon {
    flex-shrink: 0;
    font-size: 1.05rem;
    line-height: 1;
    color: var(--bs-secondary-color);
    transition: color 0.2s;
}
.disclosure:hover .disclosure-icon,
.disclosure[aria-expanded="true"] .disclosure-icon { color: var(--bs-primary); }
.disclosure-text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.disclosure-title { font-size: 0.8125rem; font-weight: 600; line-height: 1.3; }
.disclosure-hint { font-size: 0.6875rem; color: var(--bs-secondary-color); line-height: 1.3; }
/* What is already set inside, while it is shut - the brand badge, at the size of a hint. */
.disclosure-summary {
    flex-shrink: 0;
    padding: 0.0625rem 0.5rem;
    border-radius: 6px;
    background: rgba(var(--bs-primary-rgb), 0.1);
    color: var(--bs-primary);
    font-size: 0.6875rem;
    font-weight: 600;
    white-space: nowrap;
}
.disclosure-caret {
    flex-shrink: 0;
    font-size: 1.25rem;
    line-height: 1;
    color: var(--bs-secondary-color);
    transition: transform 0.2s ease-out;
}
.disclosure[aria-expanded="true"] .disclosure-caret { transform: rotate(180deg); }
[data-bs-theme="dark"] .disclosure { border-color: var(--bs-gray-600); background: rgba(255, 255, 255, 0.025); }
[data-bs-theme="dark"] .disclosure:hover,
[data-bs-theme="dark"] .disclosure[aria-expanded="true"] {
    border-color: rgba(var(--bs-primary-rgb), 0.5);
    background: rgba(var(--bs-primary-rgb), 0.08);
}

/* A disclosure with its content: one panel. The row is the header and what it opens is the body,
   inside the same border with a rule between them - so what opened reads as part of the section,
   and the header as how to close it. The border belongs to the panel, not the row. */
.disclosure-panel {
    border: 1.5px solid var(--bs-border-color);
    border-radius: 10px;
    background: var(--bs-body-bg);
    overflow: hidden;
    transition: border-color 0.2s ease-out;
}
.disclosure-panel:hover,
.disclosure-panel:has(> .disclosure[aria-expanded="true"]) {
    border-color: rgba(var(--bs-primary-rgb), 0.4);
}
.disclosure-panel > .disclosure { border: 0; border-radius: 0; }
.disclosure-panel > .disclosure[aria-expanded="true"] {
    border-bottom: 1px solid rgba(var(--bs-primary-rgb), 0.2);
}
/* Inside the panel's clipped edge, the focus ring has to sit inward to be seen. */
.disclosure-panel > .disclosure:focus-visible { outline-offset: -3px; }
.disclosure-body { padding: 12px 14px 14px; }

/* Show / Hide beside the chevron: says in words that the header opens and closes the panel. */
.disclosure-action {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    flex-shrink: 0;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--bs-primary);
}
.disclosure-action .disclosure-caret { color: inherit; }
.disclosure-when-open { display: none; }
.disclosure[aria-expanded="true"] .disclosure-when-open { display: inline; }
.disclosure[aria-expanded="true"] .disclosure-when-shut { display: none; }

[data-bs-theme="dark"] .disclosure-panel { border-color: var(--bs-gray-600); background: rgba(255, 255, 255, 0.025); }
[data-bs-theme="dark"] .disclosure-panel:hover,
[data-bs-theme="dark"] .disclosure-panel:has(> .disclosure[aria-expanded="true"]) {
    border-color: rgba(var(--bs-primary-rgb), 0.5);
}
[data-bs-theme="dark"] .disclosure-panel > .disclosure:not(:hover):not([aria-expanded="true"]) { background: transparent; }
@media (prefers-reduced-motion: reduce) {
    .disclosure, .disclosure-icon, .disclosure-caret, .disclosure-panel { transition: none; }
}

/* ── Upload wizard: what the step is still waiting for ───
   A disabled Next button states that the step is incomplete without saying which
   field is, and on a four-field step that is the only question being asked. This
   names one blocker at a time and rings the field it belongs to.

   Primary, not danger: nothing is wrong: the field is simply not filled in yet, and
   red would read as a mistake the user has already made. */
/* Sentence in the hint colour, arrow in brand blue. Primary blue as TEXT measures 3.2:1 on
   the footer's gray-50 and fails AA; as an icon it only owes 3:1 and passes. So the accent
   is carried by the arrow and by the ring on the field, and the words stay legible. */
.step-need {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
}
.step-need > i { font-size: 0.95rem; line-height: 1; color: var(--bs-primary); }
/* The footer's left end: Back, and the hint that says what the step is still waiting for.
   A group rather than two loose children, because the me-auto that splits the footer has to
   survive either one being hidden - and on most steps both are. Matches .modal-footer's own
   12px gap so the spacing reads as one row. */
.step-footer-lead {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* Back is a real way through the wizard, not a disabled-looking grey box: a light primary
   tint marks it as a step control, quieter than the solid Next it sits opposite. */
#btnStepBack {
    background-color: var(--bs-primary-bg-subtle);
    border-color: var(--bs-primary-border-subtle);
    color: var(--bs-primary-text-emphasis);
}
#btnStepBack:hover,
#btnStepBack:focus-visible {
    background-color: rgba(var(--bs-primary-rgb), 0.16);
    border-color: var(--bs-primary);
    color: var(--bs-primary);
}


/* The same 3px ring the focus state uses, so being pointed at and being focused read
   as one language rather than two. Sits on the input, the input-group or the select.

   Radius and alpha are the MODAL control's, not the page's: .modal .form-control rounds to
   10px and focuses at 0.12, and this class is only ever applied inside a modal. At the page
   values the ring cut inside the input's own corners, and it out-glowed the focus ring it
   was meant to echo — so focusing the field it pointed at made the glow weaker. */
.needs-input {
    border-radius: 10px;
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.12);
}
.needs-input.form-control,
.needs-input.form-select,
.needs-input .form-control,
.needs-input .form-select,
.needs-input .input-group-text {
    border-color: var(--bs-primary);
}

/* ── Upload Panel (Google Drive style) ──────────────────── */

/* Minimised: docked to the bottom edge, square where it meets it. */
.upload-panel--minimized {
    bottom: 0;
    border-end-start-radius: 0;
    border-end-end-radius: 0;
    border-bottom: 0;
}

/* Status strip under the panel header: time remaining on the left, cancel-all on the
   right. Muted, because it is context rather than an action bar - the one button in it
   is destructive and should be the only thing that draws the eye. */
.upload-panel-status {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 16px;
    border-bottom: 1px solid var(--bs-border-color);
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
}

.upload-cancel-all {
    border: 0;
    background: none;
    padding: 0;
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--bs-primary);
    cursor: pointer;
}

.upload-cancel-all:hover { text-decoration: underline; }
.upload-panel {
    position: fixed;
    bottom: 24px;
    inset-inline-end: 24px;
    width: 360px;
    background: var(--card-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 12px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.14);
    z-index: 1060;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 120px);
}
.upload-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 14px;
    background: var(--bs-gray-50);
    border-bottom: 1px solid var(--bs-border-color);
    cursor: pointer;
    user-select: none;
    flex-shrink: 0;
}
.upload-panel-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--bs-body-color);
}
.upload-panel-title i {
    font-size: 1rem;
    color: var(--bs-primary);
}
.upload-panel-btns {
    display: flex;
    gap: 2px;
}
.upload-panel-btn {
    width: 28px;
    height: 28px;
    border: none;
    background: transparent;
    border-radius: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: var(--bs-secondary-color);
    font-size: 1rem;
    transition: background 0.15s, color 0.15s;
}
.upload-panel-btn:hover {
    background: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
}
.upload-panel-body {
    overflow-y: auto;
    max-height: 320px;
    padding: 4px 0;
}

/* Individual upload row */
.upload-row {
    padding: 8px 14px;
    border-bottom: 1px solid var(--bs-gray-100);
    transition: background 0.15s;
}
.upload-row:last-child { border-bottom: none; }
.upload-row:hover { background: var(--bs-gray-50); }

.upload-row-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 4px;
}
.upload-row-info {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    flex: 1;
}
.upload-row-info i {
    font-size: 1rem;
    color: var(--bs-secondary-color);
    flex-shrink: 0;
}
.upload-row-name {
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--bs-body-color);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.upload-row-actions {
    display: flex;
    align-items: center;
    gap: 2px;
    flex-shrink: 0;
}
.upload-row-btn {
    width: 24px;
    height: 24px;
    border: none;
    background: transparent;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
    transition: background 0.15s, color 0.15s;
    padding: 0;
}
.upload-row-btn:hover { background: var(--bs-tertiary-bg); color: var(--bs-body-color); }
.upload-row-btn--cancel:hover { color: var(--bs-danger); }

.upload-row-bottom {
    display: flex;
    align-items: center;
    gap: 8px;
}
.upload-row-bar {
    flex: 1;
    height: 3px;
    background: var(--bs-gray-200);
    border-radius: 999px;
    overflow: hidden;
}
.upload-row-fill {
    height: 100%;
    background: var(--bs-primary);
    border-radius: 999px;
    transition: width 0.3s ease;
}
.upload-row-fill--error { background: var(--bs-danger); }
.upload-row-pct {
    font-size: 0.6875rem;
    font-weight: 600;
    color: var(--bs-secondary-color);
    min-width: 36px;
    text-align: end;
    white-space: nowrap;
}

/* Completed row */
.upload-row--done .upload-row-name { color: var(--bs-success); }
.upload-row--done .upload-row-fill { background: var(--bs-success); }
.upload-row-check { color: var(--bs-success); font-size: 1rem; }

/* Failed row */
.upload-row--failed .upload-row-name { color: var(--bs-danger); }
.upload-row--failed .upload-row-pct { color: var(--bs-danger); }

/* Waiting for a slot. Same muted treatment as cancelled - neither is an error, and the
   row should recede until it is actually doing something. */
.upload-row--queued .upload-row-name { color: var(--bs-secondary-color); }
.upload-row--queued .upload-row-pct  { color: var(--bs-secondary-color); }
.upload-row--queued .upload-row-fill { background: transparent; }

/* Cancelled by the user. Muted rather than red - this was a deliberate choice, not a
   fault, and colouring it like an error implies something went wrong. */
.upload-row--cancelled .upload-row-name { color: var(--bs-secondary-color); }
.upload-row--cancelled .upload-row-pct  { color: var(--bs-secondary-color); }
.upload-row--cancelled .upload-row-info i { color: var(--bs-secondary-color); }

/* Waiting for the user to click resume. Deliberately NOT --failed: nothing has gone
   wrong, the bytes are still in S3 and the upload carries on where it stopped. Painting
   it red taught people that a pause had lost their work. */
.upload-row--paused .upload-row-name { color: var(--bs-warning-text-emphasis); }
.upload-row--paused .upload-row-pct  { color: var(--bs-warning-text-emphasis); }
.upload-row--paused .upload-row-fill { background: var(--bs-warning); }

/* Dark mode */
[data-bs-theme="dark"] .upload-panel {
    background: var(--card-bg);
    border-color: var(--sidebar-border);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
}
[data-bs-theme="dark"] .upload-panel-header {
    background: var(--bs-gray-100);
    border-bottom-color: var(--sidebar-border);
}
[data-bs-theme="dark"] .upload-row { border-bottom-color: var(--sidebar-border); }
[data-bs-theme="dark"] .upload-row:hover { background: var(--bs-gray-200); }

.social-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: 9999px;
    font-size: 0.875rem;
    font-weight: 500;
    background: var(--bs-gray-100);
    color: var(--bs-gray-600);
    border: 1px solid var(--bs-border-color);
}

.social-badge.google  { background: rgba(234, 67, 53, 0.08); color: #EA4335; border-color: rgba(234, 67, 53, 0.2); }
.social-badge.github  { background: rgba(36, 41, 46, 0.08); color: #24292e; border-color: rgba(36, 41, 46, 0.2); }
.social-badge.facebook { background: rgba(24, 119, 242, 0.08); color: #1877F2; border-color: rgba(24, 119, 242, 0.2); }
.social-badge.apple   { background: rgba(0, 0, 0, 0.06); color: #000; border-color: rgba(0, 0, 0, 0.15); }

.danger-zone {
    border: 1px solid #fecaca;
    border-radius: 10px;
    padding: 1rem;
    background: #fef2f2;
}

.danger-zone-title {
    font-size: 0.875rem;
    font-weight: 700;
    color: #991b1b;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 0.75rem;
}

/* Invite modal — photo upload circle */
.invite-photo-upload {
    width: 100px;
    height: 100px;
    border: 2px dashed var(--bs-gray-300);
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: border-color 0.2s, background 0.2s;
}
.invite-photo-upload:hover {
    border-color: var(--bs-primary);
    background: rgba(var(--bs-primary-rgb), 0.04);
}
.invite-photo-upload i {
    font-size: 32px;
    color: var(--bs-gray-400);
}
.invite-photo-preview {
    width: 100px;
    height: 100px;
    border-radius: 50%;
    object-fit: cover;
    border: 2px solid var(--bs-border-color);
    cursor: pointer;
}

/* Project permission rows in invite modal */
.project-permission-row {
    background: var(--bs-gray-50);
    border: 1px solid var(--bs-gray-100);
    transition: background 0.2s ease;
}
.project-permission-row:hover {
    background: var(--bs-gray-100) !important;
}
.project-permission-row .remove-project-btn {
    width: 28px;
    height: 28px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
}
.project-permission-row .remove-project-btn:hover {
    background: #fef2f2;
}

/* (Select2 removed — using native Bootstrap selects + search-select + multi-select) */
/* ── Invite modal — selected project rows dark mode ───── */
[data-bs-theme="dark"] #selectedProjectsList .bg-light {
    background-color: var(--bs-gray-200) !important;
    border-color: var(--bs-gray-300) !important;
    color: var(--bs-gray-900);
}

/* Flatpickr dark mode overrides */
[data-bs-theme="dark"] .flatpickr-calendar {
    background: var(--bs-body-bg);
    border-color: var(--bs-border-color);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
}
[data-bs-theme="dark"] .flatpickr-months .flatpickr-month,
[data-bs-theme="dark"] .flatpickr-current-month .flatpickr-monthDropdown-months {
    background: var(--bs-body-bg);
    color: var(--bs-body-color);
}
[data-bs-theme="dark"] .flatpickr-current-month input.cur-year {
    color: var(--bs-body-color);
}
[data-bs-theme="dark"] span.flatpickr-weekday {
    color: var(--bs-secondary-color);
    background: var(--bs-body-bg);
}
[data-bs-theme="dark"] .flatpickr-day {
    color: var(--bs-body-color);
}
[data-bs-theme="dark"] .flatpickr-day:hover {
    background: var(--bs-tertiary-bg);
    border-color: var(--bs-tertiary-bg);
}
[data-bs-theme="dark"] .flatpickr-day.prevMonthDay,
[data-bs-theme="dark"] .flatpickr-day.nextMonthDay {
    color: var(--bs-secondary-color);
}
[data-bs-theme="dark"] .flatpickr-months .flatpickr-prev-month,
[data-bs-theme="dark"] .flatpickr-months .flatpickr-next-month {
    color: var(--bs-body-color);
    fill: var(--bs-body-color);
}
[data-bs-theme="dark"] .flatpickr-months .flatpickr-prev-month:hover svg,
[data-bs-theme="dark"] .flatpickr-months .flatpickr-next-month:hover svg {
    fill: var(--bs-primary);
}

/* ─────────────────────────────────────────────────────────
   Section 19b: Users Page — Redesigned
   ───────────────────────────────────────────────────────── */

/* Invite User button */
/* .btn-invite removed — now uses shared .btn-action */

.tab-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 22px;
    padding: 0 6px;
    border-radius: 9999px;
    font-size: 0.8125rem;
    font-weight: 600;
    background: var(--bs-gray-100);
    color: var(--bs-secondary-color);
    margin-inline-start: 6px;
}

.nav-tabs .nav-link.active .tab-count {
    background: rgba(var(--bs-primary-rgb), 0.1);
    color: var(--bs-primary);
}

.tab-count--warn {
    background: #fef3c7;
    color: #d97706;
}

/* Panel wrapper */
.users-panel {
    border: 1px solid var(--bs-gray-100);
    border-radius: 16px;
    background: var(--card-bg);
    overflow: visible;
}

/* Search & filter toolbar */
.users-toolbar {
    padding: 1rem;
    border-bottom: 1px solid var(--bs-gray-100);
    border-radius: 16px 16px 0 0;
}

.users-search {
    position: relative;
}

.search-icon {
    position: absolute;
    inset-inline-start: 14px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--bs-gray-400);
    font-size: 1.1rem;
    pointer-events: none;
}

.search-input {
    padding-inline-start: 40px !important;
    border: 1px solid var(--bs-border-color);
    border-radius: 10px;
    font-size: 0.9375rem;
    height: 42px;
    background: var(--card-bg);
}

.search-input::placeholder {
    color: var(--bs-gray-400);
}

.search-input:focus {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.1);
}

.filter-select {
    width: auto;
    min-width: 140px;
    border: 1px solid var(--bs-border-color);
    border-radius: 10px;
    font-size: 0.9375rem;
    height: 42px;
    color: var(--bs-body-color);
    font-weight: 500;
}

.filter-select:focus {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.1);
}

/* Table — clean rows */
.users-table {
    margin-bottom: 0;
}

.users-table thead th {
    background: transparent !important;
    border-top: none !important;
    border-bottom: 1px solid var(--bs-gray-100) !important;
    border-inline-end: none;
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
    font-weight: 600;
    padding: 0.75rem 1rem;
    white-space: nowrap;
    text-transform: capitalize;
}

/* Clean rows */
.users-table tbody tr.user-row {
    background: var(--card-bg);
    transition: background-color 0.15s ease;
}

.users-table tbody tr.user-row:hover {
    background: var(--bs-gray-50);
}

.users-table tbody tr.user-row td {
    border: none !important;
    border-bottom: 1px solid var(--bs-gray-100) !important;
    padding: 1rem;
    vertical-align: middle;
    background: transparent !important;
    box-shadow: none !important;
    color: var(--bs-body-color);
}

/* Avatar */
.user-avatar {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-weight: 700;
    font-size: 0.875rem;
    flex-shrink: 0;
}

.user-avatar-img {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    object-fit: cover;
}

/* User cell text */
.user-name {
    font-weight: 600;
    color: var(--bs-body-color);
    font-size: 0.9375rem;
    line-height: 1.3;
}

.user-email {
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
    line-height: 1.3;
}

/* Role badge — colored by type */
.role-badge {
    display: inline-block;
    padding: 4px 14px;
    border-radius: 9999px;
    font-size: 0.8125rem;
    font-weight: 600;
    border: 1px solid;
}

.role-badge--admin {
    color: var(--bs-primary);
    border-color: rgba(var(--bs-primary-rgb), 0.3);
    background: rgba(var(--bs-primary-rgb), 0.06);
}

.role-badge--user {
    color: var(--bs-primary);
    border-color: rgba(var(--bs-primary-rgb), 0.3);
    background: rgba(var(--bs-primary-rgb), 0.06);
}

/* Project count */
.project-count {
    display: inline-flex;
    align-items: center;
    font-size: 0.85rem;
    color: var(--bs-gray-600);
    cursor: default;
}
.project-count i {
    font-size: 0.9rem;
    color: var(--bs-gray-400);
}

/* Status badge — pill style */
.status-badge {
    display: inline-block;
    padding: 4px 14px;
    border-radius: 9999px;
    font-size: 0.8125rem;
    font-weight: 600;
    border: 1px solid;
}

.status-badge--active {
    color: #16a34a;
    border-color: rgba(22, 163, 74, 0.3);
    background: rgba(22, 163, 74, 0.06);
}

.status-badge--inactive {
    color: var(--bs-gray-500);
    border-color: var(--bs-border-color);
    background: var(--bs-gray-50);
}
.status-badge--pending {
    color: #d97706;
    border-color: rgba(217, 119, 6, 0.3);
    background: rgba(217, 119, 6, 0.06);
}

/* Storage Usage cell */
.storage-cell {
    min-width: 120px;
}

.storage-text {
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--bs-body-color);
    margin-bottom: 4px;
}

.storage-total {
    color: var(--bs-secondary-color);
    margin-inline-start: 8px;
}

.storage-track {
    width: 100%;
    height: 5px;
    background: var(--bs-gray-100);
    border-radius: 9999px;
    overflow: hidden;
}

.storage-track .storage-bar {
    height: 100%;
    background: var(--bs-primary);
    border-radius: 9999px;
    min-width: 2px;
    transition: width 0.4s ease;
}

/* Last Active */
.last-active {
    font-size: 0.875rem;
    color: var(--bs-body-color);
    font-weight: 500;
}

/* DataTable controls within panel */
.users-panel .dataTables_length,
.users-panel .dataTables_filter {
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
    font-weight: 500;
}

.users-panel .dataTables_filter input {
    border: 1px solid var(--bs-border-color);
    border-radius: 6px;
    padding: 4px 10px;
    font-size: 0.875rem;
    color: var(--bs-gray-700);
    margin-inline-start: 6px;
}

.users-panel .dataTables_filter input:focus {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 2px rgba(var(--bs-primary-rgb), 0.15);
    outline: none;
}

/* Bottom bar */
.users-dt-bottom {
    font-size: 0.875rem;
    color: var(--bs-gray-500);
    padding: 0 1rem 0.75rem;
}

.users-dt-bottom .dataTables_length select {
    margin: 0 6px;
    padding-block: 4px;
    padding-inline: 10px 24px;
    border-radius: 6px;
    border: 1px solid var(--bs-border-color);
    background-color: var(--bs-body-bg);
    color: var(--bs-gray-700);
    font-size: 0.875rem;
    min-width: 60px;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M2.5 4.5L6 8l3.5-3.5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 6px center;
    background-size: 12px;
}
html[dir="rtl"] .users-dt-bottom .dataTables_length select { background-position: left 6px center; }

/* Override DataTable stripe shadow for card rows */
.users-table.table > tbody > tr > * {
    box-shadow: none !important;
}

/* Responsive toolbar */
@media (max-width: 768px) {
    .users-toolbar { flex-wrap: wrap; }
    .users-toolbar .users-search {
        max-width: 100% !important;
        flex-basis: 100%;
    }
    .filter-select {
        min-width: 100px;
        flex: 1;
    }

    /* Tabs responsive */
    .nav-tabs {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    .nav-tabs .nav-link {
        white-space: nowrap;
        font-size: 0.8125rem;
        padding: 0.5rem 0.75rem;
    }
    .org-form-header {
        flex-direction: column;
        gap: 10px;
        align-items: flex-start;
    }
    .member-row {
        flex-wrap: wrap;
        gap: 8px;
    }
    .member-meta {
        margin-inline-start: 50px;
    }
}

/* ─────────────────────────────────────────────────────────
   Section 20: Project Member Rows
   ───────────────────────────────────────────────────────── */
.project-member-row {
    transition: background 0.2s ease;
    border-radius: 10px;
    background: var(--bs-gray-50);
    border: 1px solid var(--bs-gray-100);
}
.project-member-row:hover {
    background: var(--bs-gray-100) !important;
}
.project-member-row .remove-btn {
    opacity: 0;
    transition: opacity 0.2s ease;
}
.project-member-row:hover .remove-btn {
    opacity: 1;
}
.project-member-row .perm-select {
    border-color: var(--bs-border-color);
    background-color: var(--bs-body-bg);
    transition: border-color 0.2s ease;
}
.project-member-row .perm-select:focus {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 2px rgba(var(--bs-primary-rgb), 0.15);
}

/* Members datatable header — separators & color */
#tblMembers thead th {
    border-inline-end: 1px solid var(--bs-border-color);
    color: var(--bs-gray-500);
    font-weight: 500;
    transition: color 0.2s ease;
}
#tblMembers thead th:last-child {
    border-inline-end: none;
}
#tblMembers thead th:hover {
    color: var(--bs-gray-700);
}

/* ─────────────────────────────────────────────────────────
   Section 21: Project Detail Page
   ───────────────────────────────────────────────────────── */

/* Breadcrumb */
.breadcrumb-item a {
    color: var(--bs-primary);
    text-decoration: none;
}
.breadcrumb-item a:hover {
    color: var(--primary-hover);
    text-decoration: underline;
}
.breadcrumb-item.active {
    color: var(--bs-gray-500);
}

/* Tab styling for project detail tabs — inherits pill-outline from .nav-tabs */

/* Stat cards hover in overview */
#overview-panel .detail-card {
    transition: box-shadow 0.2s ease;
}
#overview-panel .detail-card:hover {
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}

/* Edit field button in detail cards */
.edit-field-btn {
    opacity: 0;
    transition: opacity 0.2s ease;
    text-decoration: none !important;
}
.detail-card:hover .edit-field-btn,
#overviewName:hover ~ .edit-field-btn,
.edit-field-btn.edit-name-btn {
    opacity: 1;
}
.edit-field-btn:hover {
    color: var(--bs-primary) !important;
}

/* ═══════════════════════════════════════════════════════════════════════════
   §22b — Shared Context Menu (ctx-menu)
   Consistent dropdown menu pattern across the entire platform.
   Apply .ctx-menu to any .dropdown-menu for the branded look.
   ═══════════════════════════════════════════════════════════════════════════ */
.ctx-menu {
    padding: 6px; border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
    border: 1px solid var(--bs-border-color);
    min-width: 160px;
}
.ctx-menu .dropdown-item {
    display: flex !important; align-items: center; gap: 8px;
    font-size: 0.8125rem; font-weight: 500;
    color: var(--bs-body-color) !important;
    padding: 8px 12px; border-radius: 6px;
    margin: 1px 0;
    transition: background 120ms cubic-bezier(0.4, 0, 0.2, 1),
                color 120ms cubic-bezier(0.4, 0, 0.2, 1);
}
.ctx-menu .dropdown-item i { font-size: 1rem; width: 18px; text-align: center; color: var(--bs-body-color) !important; }
.ctx-menu .dropdown-item:hover,
.ctx-menu .dropdown-item:focus {
    background: var(--bs-primary) !important; color: #fff !important;
}
.ctx-menu .dropdown-item:hover i,
.ctx-menu .dropdown-item:focus i { color: #fff !important; }
.ctx-menu .dropdown-item:active { transform: scale(0.97); }
/* Primary action variant — add .ctx-primary to the first dropdown-item for a permanent blue CTA */
.ctx-menu .dropdown-item.ctx-primary {
    background: var(--bs-primary) !important; color: #fff !important;
    font-weight: 600;
}
.ctx-menu .dropdown-item.ctx-primary i { color: #fff !important; }
.ctx-menu .dropdown-item.ctx-primary:hover {
    background: var(--primary-hover, #1E5CF5) !important;
}
/* Danger item */
.ctx-menu .dropdown-item.text-danger { color: var(--danger, #dc2626) !important; }
.ctx-menu .dropdown-item.text-danger i { color: var(--danger, #dc2626) !important; }
.ctx-menu .dropdown-item.text-danger:hover,
.ctx-menu .dropdown-item.text-danger:focus {
    background: var(--danger, #dc2626) !important; color: #fff !important;
}
.ctx-menu .dropdown-item.text-danger:hover i,
.ctx-menu .dropdown-item.text-danger:focus i { color: #fff !important; }
.ctx-menu .dropdown-divider { margin: 4px 0; opacity: 0.12; }
[data-bs-theme="dark"] .ctx-menu {
    background: var(--bs-gray-800); border-color: var(--bs-gray-700);
    box-shadow: 0 8px 24px rgba(0,0,0,0.4);
}
[data-bs-theme="dark"] .ctx-menu .dropdown-item { color: var(--bs-gray-200) !important; }
[data-bs-theme="dark"] .ctx-menu .dropdown-item i { color: var(--bs-gray-200) !important; }
[data-bs-theme="dark"] .ctx-menu .dropdown-item:hover {
    background: var(--bs-primary) !important; color: #fff !important;
}
[data-bs-theme="dark"] .ctx-menu .dropdown-item.text-danger:hover {
    background: var(--danger, #dc2626) !important; color: #fff !important;
}

/* ═══════════════════════════════════════════════════════════════════════════
   §23 — Project Hub (Home page)
   ═══════════════════════════════════════════════════════════════════════════ */

/* Project Hub page */

/* ── Header right controls ──────────────────────────── */
.ph-header-right {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
}

/* Search */
.ph-search-wrap {
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    padding: 0 16px;
    height: 44px;
    width: 240px;
    transition: border-color 0.2s, box-shadow 0.2s;
}
.ph-search-wrap:focus-within {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.08);
}
.ph-search-icon {
    color: var(--bs-secondary-color);
    font-size: 15px;
    flex-shrink: 0;
}
.ph-search-input {
    border: none;
    outline: none;
    background: transparent;
    font-size: 13.5px;
    color: var(--bs-body-color);
    width: 100%;
}
.ph-search-input::placeholder { color: var(--bs-secondary-color); }

/* View toggle */
.ph-view-toggle {
    display: flex;
    align-items: stretch;
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 8px;
    overflow: hidden;
    height: 44px;
}
.ph-view-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    padding: 0 13px;
    cursor: pointer;
    color: var(--bs-secondary-color);
    font-size: 16px;
    line-height: 1;
    transition: background 0.15s, color 0.15s;
}
.ph-view-btn:hover  { background: var(--bs-tertiary-bg); color: var(--bs-body-color); }
.ph-view-btn.active { background: #EFF2FF; color: var(--bs-primary); }


/* ── Grid ───────────────────────────────────────────── */
.ph-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
}
@media (max-width: 1200px) { .ph-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .ph-grid { grid-template-columns: 1fr; } }

/* ── Card ───────────────────────────────────────────── */
.ph-card {
    background: var(--bs-body-bg);
    border-radius: 16px;
    /* Clip content to the rounded border so meta/badges never spill outside the card.
       The kebab menu is portalled to <body>, so it isn't affected by this. */
    overflow: hidden;
    box-shadow: 0 1px 3px rgba(0,0,0,0.07), 0 1px 2px rgba(0,0,0,0.05);
    transition: box-shadow 0.2s, transform 0.2s;
    cursor: pointer;
    min-width: 0;
    display: flex;
    flex-direction: column;
}
.ph-card:hover {
    box-shadow: 0 6px 20px rgba(0,0,0,0.10);
    transform: translateY(-2px);
}

/* Hero area */
.ph-card-hero {
    position: relative;
    height: 160px;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    border-radius: 16px 16px 0 0;
}
/* Bottom layer — solid per-project colour at full opacity (inline background-color) */
.ph-hero-thumb {
    position: absolute;
    inset: 0;
    user-select: none;
}
/* Middle layer — uploaded preview fills the hero, kept faint so the solid colour shows through */
.ph-hero-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    z-index: 0;
    opacity: 0.35;
}
/* Top layer — project initial, painted over the photo and legible on any image */
.ph-hero-letter {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 4rem;
    font-weight: 700;
    color: #fff;
    letter-spacing: -0.02em;
    user-select: none;
    pointer-events: none;
    z-index: 1;
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
    /* Low-opacity wash over the hero, tinted per-project inline (see phHeroThumb) so the
       uploaded image keeps the card's colour identity while staying visible behind it */
    background: transparent;
}
.ph-hero-letter-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* Hero top row (status + visibility left, count right) */
.ph-hero-left {
    position: absolute;
    top: 12px;
    inset-inline-start: 12px;
    display: flex;
    align-items: center;
    gap: 6px;
    z-index: 1;
}

/* Status badge */
.ph-status-badge {
    border-radius: 999px;
    padding: 3px 11px;
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: 0.01em;
}
.ph-s-active     { background: #DBEAFE; color: #1D4ED8; }
.ph-s-completed  { background: #D1FAE5; color: #059669; }
.ph-s-processing { background: #FEF3C7; color: #D97706; }
.ph-s-archived   { background: var(--bs-tertiary-bg); color: var(--bs-secondary-color); }

/* Visibility badge (Public / Private) */
.ph-vis-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    border-radius: 999px;
    padding: 3px 10px;
    font-size: 11.5px;
    font-weight: 600;
    border: none;
}
.ph-vis-badge i { font-size: 12px; }
.ph-vis-public {
    color: #16a34a;
    background: #f0fdf4;
}
.ph-vis-private {
    color: #dc2626;
    background: #fef2f2;
}
/* Coordinate system, shown beside the project title. Same pill as the visibility badge because
   it states the same kind of thing: a fixed property of the project, not an action. Neutral
   rather than green/red — it is a fact, not a warning. Long grid names are common
   ("NAD83(HARN) / Virginia North (ftUS)"), so it truncates instead of pushing the title. */
.ph-vis-crs {
    color: var(--bs-secondary-color);
    background: var(--bs-gray-100);
    max-width: 320px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display: inline-flex;
}
.ph-vis-crs .ph-vis-crs-name { overflow: hidden; text-overflow: ellipsis; }

/* Count badge (top-right of hero) */
.ph-count-badge {
    position: absolute;
    top: 12px;
    inset-inline-end: 12px;
    display: flex;
    align-items: center;
    gap: 5px;
    background: var(--bs-body-bg);
    border-radius: 999px;
    padding: 3px 10px;
    font-size: 12px;
    font-weight: 600;
    color: var(--bs-primary);
    box-shadow: 0 1px 4px rgba(0,0,0,0.10);
    z-index: 1;
}
.ph-count-badge i { font-size: 13px; }

.ph-storage-badge {
    position: absolute;
    bottom: 10px;
    inset-inline-end: 12px;
    display: flex;
    align-items: center;
    gap: 4px;
    background: rgba(0,0,0,0.45);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    border-radius: 999px;
    padding: 3px 9px;
    font-size: 11px;
    font-weight: 600;
    color: #fff;
    z-index: 1;
    letter-spacing: 0.01em;
}
.ph-storage-badge i { font-size: 12px; opacity: 0.85; }

/* Card body */
.ph-card-body { padding: 15px 16px 16px; min-width: 0; overflow: visible; flex: 1; display: flex; flex-direction: column; }

/* Title row */
.ph-card-title-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 6px;
    gap: 8px;
}
.ph-card-title {
    font-size: 14.5px;
    font-weight: 700;
    color: var(--bs-body-color);
    margin: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1;
    min-width: 0;
}

/* Three-dot menu */
.ph-menu-wrap {
    position: relative;
    flex-shrink: 0;
}
.ph-menu-btn {
    background: transparent;
    border: none;
    color: var(--bs-secondary-color);
    font-size: 16px;
    padding: 2px 4px;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
    line-height: 1;
}
.ph-menu-btn:hover { background: var(--bs-tertiary-bg); color: var(--bs-body-color); }

/* Dropdown */
.ph-dropdown {
    display: none;
    position: absolute;
    top: calc(100% + 4px);
    inset-inline-end: 0;
    background: var(--bs-body-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 10px;
    box-shadow: 0 4px 16px rgba(0,0,0,0.10);
    min-width: 160px;
    z-index: 1100;
}
.ph-dropdown.open { display: block; }
.ph-dropdown .ph-dd-item,
.ph-dropdown .ph-dd-item i {
    color: var(--bs-body-color) !important;
}
.ph-dd-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 14px;
    font-size: 13px;
    text-decoration: none;
    transition: background 0.15s, color 0.15s;
    border-radius: 6px;
    margin: 2px 4px;
}
.ph-dd-item:hover { background: var(--bs-primary); color: #fff !important; }
.ph-dd-item:hover i { color: #fff !important; }
.ph-dropdown .ph-dd-item.ph-dd-danger,
.ph-dropdown .ph-dd-item.ph-dd-danger i { color: var(--bs-danger) !important; }
.ph-dd-item.ph-dd-danger:hover { background: var(--bs-danger); color: #fff !important; }
.ph-dd-item.ph-dd-danger:hover i { color: #fff !important; }
.ph-dd-item i { font-size: 15px; }

/* Description */
.ph-card-desc {
    font-size: 12.5px;
    color: var(--bs-secondary-color);
    line-height: 1.55;
    margin: 0 0 12px;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    word-break: break-word;
    overflow-wrap: break-word;
}

/* Meta footer */
.ph-card-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-top: 1px solid var(--bs-border-color);
    padding-top: 10px;
    font-size: 12px;
    color: var(--bs-secondary-color);
    gap: 8px;
    margin-top: auto;
    flex-wrap: wrap;
}
.ph-meta-left {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
    flex-shrink: 1;
}
.ph-meta-left span {
    display: flex;
    align-items: center;
    gap: 5px;
    white-space: nowrap;
}
.ph-card-meta i { font-size: 13px; }

/* Data type badge (footer right) */
.ph-type-badge {
    font-size: 11.5px;
    font-weight: 600;
    padding: 2px 10px;
    border-radius: 999px;
    border: 1px solid;
    white-space: nowrap;
}
.ph-t-lidar          { color: #2563EB; border-color: #BFDBFE; background: #EFF6FF; }
.ph-t-photogrammetry { color: #DC2626; border-color: #FECACA; background: #FEF2F2; }
.ph-t-pointcloud     { color: #7C3AED; border-color: #DDD6FE; background: #F5F3FF; }
.ph-t-elevation      { color: #059669; border-color: #A7F3D0; background: #ECFDF5; }
.ph-t-thermal        { color: #D97706; border-color: #FDE68A; background: #FFFBEB; }

/* Category badge (footer right) */
.ph-cat-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11.5px;
    font-weight: 600;
    padding: 2px 10px;
    border-radius: 999px;
    white-space: nowrap;
    color: #2563EB;
    border: 1px solid #BFDBFE;
    background: #EFF6FF;
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    flex-shrink: 1;
}
.ph-cat-badge i { font-size: 12px; }

/* ── Locked project card ──────────────────────────────── */
.ph-card-locked {
    position: relative;
    background: var(--bs-tertiary-bg);
    border: 1.5px dashed var(--bs-border-color);
    box-shadow: none;
    pointer-events: none;
    user-select: none;
    cursor: default !important;
    opacity: 0.65;
}
.ph-card-locked .ph-hero-thumb {
    background: var(--bs-gray-300) !important;
    color: var(--bs-gray-500);
}
.ph-card-locked .ph-card-hero::after {
    content: '';
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.06);
    border-radius: 16px 16px 0 0;
    pointer-events: none;
}
.ph-card-locked .ph-card-hero::before {
    content: '\eecc';
    font-family: 'remixicon';
    position: absolute;
    z-index: 2;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.5);
    color: #fff;
    font-size: 1.25rem;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}
.ph-card-locked:hover {
    transform: none !important;
    box-shadow: none !important;
}
.ph-card-locked .ph-card-title,
.ph-card-locked .ph-card-title a {
    color: var(--bs-gray-500) !important;
    pointer-events: none;
    text-decoration: none !important;
}
.ph-card-locked .ph-card-desc,
.ph-card-locked .ph-card-meta {
    color: var(--bs-gray-500) !important;
}
.ph-card-locked .ph-vis-badge {
    background: var(--bs-gray-200) !important;
    color: var(--bs-gray-500) !important;
}
.ph-card-locked .ph-status-badge {
    background: var(--bs-gray-200) !important;
    color: var(--bs-gray-500) !important;
}
.ph-card-locked .ph-count-badge {
    opacity: 0.4;
}
.ph-card-locked .ph-cat-badge {
    color: var(--bs-gray-500) !important;
    border-color: var(--bs-gray-300) !important;
}
.ph-card-locked .ph-card-menu {
    pointer-events: none;
    opacity: 0.3;
}

/* Dark mode locked cards */
[data-bs-theme="dark"] .ph-card-locked {
    background: var(--bs-gray-900);
    border-color: var(--bs-gray-700);
}
[data-bs-theme="dark"] .ph-card-locked .ph-hero-thumb {
    background: var(--bs-gray-700) !important;
    color: var(--bs-gray-500);
}
[data-bs-theme="dark"] .ph-card-locked .ph-card-hero::after {
    background: rgba(0, 0, 0, 0.15);
}
[data-bs-theme="dark"] .ph-card-locked .ph-card-hero::before {
    background: rgba(0, 0, 0, 0.6);
}
[data-bs-theme="dark"] .ph-card-locked .ph-vis-badge,
[data-bs-theme="dark"] .ph-card-locked .ph-status-badge {
    background: var(--bs-gray-800) !important;
    color: var(--bs-gray-500) !important;
}
[data-bs-theme="dark"] .ph-card-locked .ph-cat-badge {
    border-color: var(--bs-gray-700) !important;
}
.ph-lock-badge {
    font-size: 11.5px;
    font-weight: 600;
    padding: 3px 10px;
    border-radius: 999px;
    background: #fefce8;
    color: #ca8a04;
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.ph-lock-badge i { font-size: 12px; }

/* Inline visibility badge: hidden in grid view, shown in list view */
.ph-vis-inline { display: none; }

/* ── List view ───────────────────────────────────────── */
.ph-grid.ph-list { grid-template-columns: 1fr; gap: 12px; }
.ph-grid.ph-list .ph-card { display: flex; flex-direction: row; }
.ph-grid.ph-list .ph-card-hero {
    width: 160px;
    height: auto;
    min-height: 120px;
    flex-shrink: 0;
    border-radius: 0;
}
/* Hide hero visibility badge in list view, show inline one instead */
.ph-grid.ph-list .ph-hero-left .ph-vis-badge { display: none; }
.ph-grid.ph-list .ph-vis-inline { display: inline-flex; flex-shrink: 0; margin-inline-start: auto; }
/* Hide hero count-badge in list view — member count is already shown in the body
   meta row, and the narrow 160px hero can't fit both hero-left badges and the
   top-right count-badge without overlap. Keeps the hero clean. */
.ph-grid.ph-list .ph-count-badge { display: none; }
/* Card body: flex column so meta sticks to bottom */
.ph-grid.ph-list .ph-card-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    padding: 16px 20px;
}
.ph-grid.ph-list .ph-card-title-row {
    justify-content: flex-start;
}
.ph-grid.ph-list .ph-card-desc {
    margin-bottom: 0;
}
.ph-grid.ph-list .ph-card-meta {
    margin-top: auto;
}
/* Align type badge right edge with visibility badge above */
.ph-grid.ph-list .ph-type-badge {
    margin-inline-start: auto;
}

/* ── Empty state ─────────────────────────────────────── */
.ph-empty-state {
    grid-column: 1 / -1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 60px 20px 50px;
}

/* Drone scene container */
.ph-empty-scene {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-bottom: 24px;
}

/* Drone float animation */
.ph-drone {
    animation: ph-drone-float 3s ease-in-out infinite;
}
@keyframes ph-drone-float {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-10px); }
}

/* Propeller spin */
.ph-prop {
    transform-origin: center;
    animation: ph-prop-spin 0.15s linear infinite;
}
.ph-prop-r {
    animation-direction: reverse;
}
@keyframes ph-prop-spin {
    0% { rx: 22; ry: 4; }
    25% { rx: 6; ry: 2; }
    50% { rx: 22; ry: 4; }
    75% { rx: 6; ry: 2; }
}

/* LED blink */
.ph-led {
    animation: ph-led-blink 1.5s ease-in-out infinite;
}
@keyframes ph-led-blink {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.2; }
}

/* Ground shadow — scales with drone float */
.ph-drone-shadow {
    width: 80px;
    height: 10px;
    border-radius: 50%;
    background: radial-gradient(ellipse, rgba(0,0,0,0.1) 0%, transparent 70%);
    margin-top: 4px;
    animation: ph-shadow-pulse 3s ease-in-out infinite;
}
@keyframes ph-shadow-pulse {
    0%, 100% { transform: scaleX(1); opacity: 0.6; }
    50% { transform: scaleX(0.7); opacity: 0.3; }
}

.ph-empty-title {
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--bs-gray-800);
    margin-bottom: 8px;
}
.ph-empty-subtitle {
    font-size: 0.875rem;
    color: var(--bs-gray-500);
    line-height: 1.6;
    margin-bottom: 24px;
}
.ph-empty-hint {
    font-size: 0.8125rem;
    color: var(--bs-primary);
    opacity: 0.7;
}
.ph-empty-hint i {
    font-size: 0.875rem;
    margin-inline-end: 2px;
}

/* ── Project Hub Pagination ──────────────────────────── */
.ph-pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 0;
    margin-top: 8px;
    font-size: 13px;
    color: var(--bs-secondary-color);
}
.ph-pagination-info {
    font-weight: 500;
    white-space: nowrap;
}
.ph-pagination-pages {
    display: flex;
    align-items: center;
    gap: 4px;
}
.ph-page-btn {
    min-width: 30px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
    font-size: 13px;
    font-weight: 500;
    color: var(--bs-secondary-color);
    border: 1px solid var(--bs-border-color);
    background: var(--bs-body-bg);
    cursor: pointer;
    transition: all 0.15s;
}
.ph-page-btn:hover:not(.disabled):not(.active) {
    background: var(--bs-gray-100);
    color: var(--bs-body-color);
    border-color: var(--bs-gray-300);
}
.ph-page-btn.active {
    background: var(--bs-primary);
    color: #fff;
    border-color: var(--bs-primary);
    font-weight: 600;
}
.ph-page-btn.disabled {
    opacity: 0.35;
    cursor: default;
    pointer-events: none;
}
.ph-pagination-limit {
    display: flex;
    align-items: center;
    gap: 8px;
}
.ph-pagination-limit label {
    margin: 0;
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
}
.ph-limit-select {
    padding-block: 4px;
    padding-inline: 10px 28px;
    border-radius: 6px;
    border: 1px solid var(--bs-border-color);
    background-color: var(--bs-body-bg);
    font-size: 13px;
    min-width: 52px;
}
[data-bs-theme="dark"] .ph-page-btn {
    background: var(--card-bg);
    border-color: var(--sidebar-border);
    color: var(--bs-secondary-color);
}
[data-bs-theme="dark"] .ph-page-btn:hover:not(.disabled):not(.active) {
    background: var(--bs-gray-700);
    color: var(--bs-body-color);
}
[data-bs-theme="dark"] .ph-limit-select {
    background-color: var(--card-bg);
    border-color: var(--sidebar-border);
    color: var(--bs-body-color);
}
@media (max-width: 768px) {
    .ph-pagination {
        flex-direction: column;
        gap: 12px;
        align-items: center;
    }
}

/* ── Mobile header wrap ──────────────────────────────── */
@media (max-width: 768px) {
    .ph-header-right { width: 100%; flex-wrap: wrap; }
    .ph-search-wrap { flex: 1; min-width: 160px; }
    .ph-header-right .btn-action { width: 100%; justify-content: center; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   §24 — Projects Table View
   ═══════════════════════════════════════════════════════════════════════════ */

/* Page wrapper — white bg, consistent with sidebar */
.pj-page {
    background: var(--bs-body-bg);
    min-height: 100%;
    margin: -24px -32px -24px -32px;
    padding: 32px 36px;
    box-sizing: border-box;
}
.pj-page .container-fluid { padding: 0 !important; }


/* ── Search input width override for Projects page ── */
.pj-page .proj-search { max-width: 280px; }

/* ── Table wrapper ────────────────────────────────── */
.pj-table-wrap {
    background: var(--bs-body-bg);
    border-radius: 16px;
    border: 1px solid var(--bs-border-color);
    box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
    overflow: visible;
}

/* ── Table ────────────────────────────────────────── */
.pj-table {
    width: 100%;
    border-collapse: collapse;
}

/* Header row */
.pj-table thead tr {
    border-bottom: 1px solid var(--bs-border-color);
}
.pj-table thead th {
    padding: 13px 18px;
    font-size: 11px;
    font-weight: 700;
    color: var(--bs-secondary-color);
    text-transform: uppercase;
    letter-spacing: 0.07em;
    white-space: nowrap;
    background: var(--bs-body-bg);
}
.pj-th-actions { text-align: end; }

/* Body rows */
.pj-table tbody tr {
    border-bottom: 1px solid var(--bs-border-color);
    transition: background 0.15s;
    cursor: default;
}
.pj-table tbody tr:last-child { border-bottom: none; }
.pj-table tbody tr:hover      { background: var(--bs-tertiary-bg); }

/* Cells */
.pj-table td {
    padding: 15px 18px;
    vertical-align: middle;
}

/* PROJECT cell */
.pj-proj-name {
    font-size: 14.5px;
    font-weight: 800;
    color: var(--bs-body-color);
    margin: 0 0 3px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 300px;
}
.pj-proj-desc {
    font-size: 12px;
    color: var(--bs-secondary-color);
    margin: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 300px;
}

.pj-proj-data {
    font-size: 11px;
    color: var(--bs-secondary-color);
    margin-top: 2px;
    display: flex;
    align-items: center;
    gap: 4px;
    opacity: 0.7;
}
.pj-proj-data i { font-size: 12px; }

/* PROJECT link (blue clickable name) */
.pj-proj-link {
    font-size: 14.5px;
    font-weight: 700;
    color: var(--bs-primary);
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: block;
    max-width: 300px;
    transition: color 0.15s;
}
.pj-proj-link:hover {
    color: var(--bs-primary);
    text-decoration: underline;
}

/* Generic text cell */
.pj-col-text {
    font-size: 13px;
    color: var(--bs-body-color);
    white-space: nowrap;
}

/* Category chips in data table */
.pj-cat-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}
.pj-cat-chip {
    font-size: 0.75rem;
    font-weight: 500;
    padding: 2px 8px;
    border-radius: 4px;
    background: var(--bs-tertiary-bg);
    color: var(--bs-body-color);
    white-space: nowrap;
}
.data-table-row-locked .pj-cat-chip {
    color: var(--bs-gray-500) !important;
}

/* Processing state */
.pj-processing {
    font-size: 13px;
    color: var(--bs-secondary-color);
    font-style: italic;
}

/* ── Member avatar group ──────────────────────────── */
.pj-avatar-group {
    display: flex;
    align-items: center;
    justify-content: center;
    /* Stack avatars left-to-right with later ones on top */
    direction: ltr;
}
/* Each avatar circle */
.pj-avatar {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    /* Ring separator — adapts to page background in dark mode */
    border: 2px solid var(--bs-body-bg);
    margin-inline-start: -7px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    text-transform: uppercase;
    position: relative;
    z-index: 1;
}
.pj-avatar:first-child { margin-inline-start: 0; }
/* Each subsequent avatar stacks above the previous */
.pj-avatar:nth-child(2) { z-index: 2; }
.pj-avatar:nth-child(3) { z-index: 3; }
/* +N overflow badge — same size and border as avatars for visual consistency */
.pj-avatar-more {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 2px solid var(--bs-body-bg);
    margin-inline-start: -7px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 9px;
    font-weight: 700;
    color: var(--bs-secondary-color);
    background: var(--bs-tertiary-bg);
    flex-shrink: 0;
    z-index: 4;
    position: relative;
}
.pj-no-members {
    color: var(--bs-secondary-color);
    font-size: 14px;
}

/* ── Action buttons ───────────────────────────────── */
.pj-actions {
    display: flex;
    align-items: center;
    gap: 3px;
    justify-content: flex-end;
}
.pj-action-btn {
    width: 30px;
    height: 30px;
    border-radius: 7px;
    border: none;
    background: transparent;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: var(--bs-secondary-color);
    font-size: 15px;
    transition: background 0.15s, color 0.15s;
    padding: 0;
    flex-shrink: 0;
}
.pj-action-btn:hover              { background: var(--bs-tertiary-bg); color: var(--bs-body-color); }
.pj-action-btn.pj-action-delete   { color: #FDA4A4; }
.pj-action-btn.pj-action-delete:hover { background: #FEE2E2; color: #DC2626; }
/* Disabled state — mock rows: all icons visible but dimmed, non-interactive */
.pj-action-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* ── Responsive ───────────────────────────────────── */
@media (max-width: 1100px) {
    .pj-proj-name, .pj-proj-desc { max-width: 220px; }
}
@media (max-width: 900px) {
    /* Table scrolls horizontally on medium screens */
    .pj-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
    .pj-table { min-width: 700px; }
    .pj-proj-name, .pj-proj-desc { max-width: 160px; }
    /* Hide less critical columns on tablet */
    .pj-table thead th:nth-child(3),
    .pj-table tbody td:nth-child(3) { display: none; } /* SIZE */
}
@media (max-width: 768px) {
    .pj-page { padding: 20px 16px; margin: -16px; }
    .pj-page .container-fluid { padding: 0 !important; }
    .pj-page .proj-header { flex-direction: column; align-items: flex-start; gap: 12px; }
    .pj-page .proj-header-right { width: 100%; flex-wrap: wrap; gap: 8px; }
    .pj-page .proj-search { flex: 1; min-width: 140px; max-width: 100%; }
    /* Hide DATA TYPE on mobile */
    .pj-table thead th:nth-child(2),
    .pj-table tbody td:nth-child(2) { display: none; }
    /* Hide PROCESSED DATA on mobile */
    .pj-table thead th:nth-child(4),
    .pj-table tbody td:nth-child(4) { display: none; }
}

/* ═══════════════════════════════════════════════════════
   Section 22 · Unified DataTable Card System (data-table-*)
   Reusable card + table + pagination pattern for all
   DataTable pages.
   ═══════════════════════════════════════════════════════ */

/* ── Card Container ─────────────────────────────────── */
.data-table-card {
    background: var(--card-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: 16px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
    overflow: visible;
}

/* ── Card Header ────────────────────────────────────── */
.data-table-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 20px 24px;
    border-bottom: 1px solid var(--bs-gray-100);
    border-radius: 16px 16px 0 0;
}
.data-table-header-left {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
}
.data-table-header-icon {
    width: 42px;
    height: 42px;
    border-radius: 10px;
    background: rgba(var(--bs-primary-rgb), 0.1);
    color: var(--bs-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.25rem;
    flex-shrink: 0;
}
.data-table-header-right {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-shrink: 0;
}

/* ── Toolbar (search + filters) ─────────────────────── */
.data-table-toolbar {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 24px;
    border-bottom: 1px solid var(--bs-gray-100);
}
.data-table-search {
    position: relative;
    flex: 1;
    max-width: 340px;
}
.data-table-search-icon {
    position: absolute;
    inset-inline-start: 14px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--bs-gray-400);
    font-size: 1.1rem;
    pointer-events: none;
}
.data-table-search-input {
    width: 100%;
    padding-block: 8px;
    padding-inline: 40px 14px;
    border: 1px solid var(--bs-border-color);
    border-radius: 10px;
    font-size: 0.875rem;
    color: var(--bs-body-color);
    background: var(--card-bg);
    height: 40px;
    font-family: var(--bs-body-font-family);
    transition: border-color 0.2s, box-shadow 0.2s;
}
.data-table-search-input::placeholder { color: var(--bs-gray-400); }
.data-table-search-input:focus {
    outline: none;
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.1);
}
.data-table-filter-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 16px;
    border: 1px solid var(--bs-border-color);
    border-radius: 10px;
    background: var(--card-bg);
    color: var(--bs-body-color);
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
    height: 40px;
    transition: all 0.15s;
}
.data-table-filter-btn:hover {
    border-color: var(--bs-gray-300);
    background: var(--bs-gray-50);
}

/* ── Toolbar title + right group ──────────────────────── */
.data-table-toolbar-title {
    font-size: 1rem;
    font-weight: 700;
    color: var(--bs-emphasis-color);
    margin: 0;
    white-space: nowrap;
}
.data-table-toolbar-right {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-inline-start: auto;
}

/* ── Bulk delete button ──────────────────────────────── */
.data-table-bulk-delete {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 16px;
    border: 1px solid #FECACA;
    border-radius: 9999px;
    background: #FEE2E2;
    color: #DC2626;
    font-size: 0.8125rem;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition: all 0.15s;
}
.data-table-bulk-delete:hover {
    background: #FECACA;
    border-color: #FCA5A5;
}
.data-table-bulk-delete i {
    font-size: 1rem;
}

/* ── Custom checkbox ─────────────────────────────────── */
/* appearance:none is load-bearing. Without it the browser still paints its own
   control inside this border and accent-color styles that native box, so the
   result is a checkbox drawn inside a checkbox. Every table using .data-table-check
   was affected, not just one screen. */
.data-table-check {
    appearance: none;
    -webkit-appearance: none;
    position: relative;
    width: 16px;
    height: 16px;
    margin: 0;
    vertical-align: middle;
    border-radius: 4px;
    border: 1.5px solid var(--bs-gray-300);
    background: var(--card-bg);
    cursor: pointer;
}
.data-table-check:checked,
.data-table-check:indeterminate {
    background: var(--bs-primary);
    border-color: var(--bs-primary);
}
.data-table-check:checked::after {
    content: '';
    position: absolute;
    left: 4.5px;
    top: 1px;
    width: 4px;
    height: 9px;
    border: solid #fff;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}
.data-table-check:indeterminate::after {
    content: '';
    position: absolute;
    left: 3px;
    top: 6px;
    width: 8px;
    height: 2px;
    background: #fff;
    border-radius: 1px;
}
.data-table-check:focus-visible {
    outline: 2px solid var(--bs-primary);
    outline-offset: 2px;
}

/* ── Filter dropdown (icon + select) ─────────────────── */
.data-table-filter-wrap {
    position: relative;
    display: inline-flex;
    align-items: center;
}
.data-table-filter-icon {
    position: absolute;
    inset-inline-start: 12px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--bs-gray-400);
    font-size: 0.9rem;
    pointer-events: none;
    z-index: 10;
}
.data-table-filter-select {
    padding-block: 8px;
    padding-inline: 34px 32px;
    border: 1px solid var(--bs-border-color);
    border-radius: 10px;
    background: var(--card-bg);
    color: var(--bs-body-color);
    font-size: 0.875rem;
    font-weight: 500;
    height: 40px;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M2.5 4.5L6 8l3.5-3.5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 12px;
    transition: border-color 0.15s;
}
html[dir="rtl"] .data-table-filter-select { background-position: left 10px center; }
.data-table-filter-select:focus {
    outline: none;
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.1);
}


/* ── Table ───────────────────────────────────────────── */
.data-table-table {
    width: 100% !important;
    margin-bottom: 0;
    border-collapse: collapse;
    table-layout: fixed;
}
.data-table-table thead th {
    background: var(--bs-gray-50) !important;
    border-top: none !important;
    border-bottom: 1px solid var(--bs-border-color) !important;
    border-inline-end: none;
    color: var(--bs-secondary-color);
    font-size: 11.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 13px 24px;
    white-space: nowrap;
    vertical-align: middle;
}
/* Allow long / multi-word column headers to wrap onto two lines cleanly.
   Keeps alignment with single-line headers via vertical-align: middle above. */
.data-table-table thead th.data-table-th-wrap {
    white-space: normal;
    line-height: 1.25;
}
/* Sort cursor for DataTable columns */
.data-table-table thead th.sorting,
.data-table-table thead th.sorting_asc,
.data-table-table thead th.sorting_desc {
    cursor: pointer;
}
/* DataTables' own stylesheet is left-to-right only: headers align left and the sort arrows sit
   in a 26px gutter on the right. In Arabic both move to the other side. */
html[dir="rtl"] table.dataTable thead th,
html[dir="rtl"] table.dataTable thead td,
html[dir="rtl"] table.dataTable tfoot th,
html[dir="rtl"] table.dataTable tfoot td {
    text-align: right;
}
html[dir="rtl"] table.dataTable thead > tr > th.sorting,
html[dir="rtl"] table.dataTable thead > tr > th.sorting_asc,
html[dir="rtl"] table.dataTable thead > tr > th.sorting_desc {
    padding-right: 24px;
    padding-left: 26px;
}
html[dir="rtl"] table.dataTable thead > tr > th.sorting:before,
html[dir="rtl"] table.dataTable thead > tr > th.sorting:after,
html[dir="rtl"] table.dataTable thead > tr > th.sorting_asc:before,
html[dir="rtl"] table.dataTable thead > tr > th.sorting_asc:after,
html[dir="rtl"] table.dataTable thead > tr > th.sorting_desc:before,
html[dir="rtl"] table.dataTable thead > tr > th.sorting_desc:after {
    right: auto;
    left: 10px;
}
.data-table-table tbody tr {
    background: var(--card-bg);
    transition: background-color 0.15s ease;
}
.data-table-table tbody tr:hover {
    background: var(--bs-gray-50);
}
.data-table-table tbody td {
    border: none !important;
    border-bottom: 1px solid var(--bs-gray-100) !important;
    padding: 14px 24px;
    vertical-align: middle;
    background: transparent !important;
    box-shadow: none !important;
    color: var(--bs-body-color);
    font-size: 0.875rem;
    overflow: hidden;
    text-overflow: ellipsis;
}
.data-table-table tbody td.dt-vis-cell {
    overflow: visible;
    text-overflow: clip;
    white-space: nowrap;
}
.data-table-table tbody tr:last-child td {
    border-bottom: none !important;
}
.data-table-table.table > tbody > tr > * {
    box-shadow: none !important;
}


/* ── Locked row styling for DataTable ───────────────── */
.data-table-row-locked {
    pointer-events: none;
    user-select: none;
}
.data-table-row-locked td {
    background: var(--bs-tertiary-bg) !important;
    color: var(--bs-gray-500) !important;
    opacity: 0.65;
}
.data-table-row-locked:hover td {
    background: var(--bs-tertiary-bg) !important;
}
.data-table-row-locked .pj-proj-link {
    color: var(--bs-gray-500) !important;
    pointer-events: none;
    text-decoration: none !important;
}
.data-table-row-locked .pj-col-text {
    color: var(--bs-gray-500) !important;
}
.data-table-row-locked .ph-vis-badge {
    background: var(--bs-gray-200) !important;
    color: var(--bs-gray-500) !important;
}
.data-table-row-locked .ph-lock-badge {
    opacity: 0.8;
}
.data-table-row-locked .data-table-check {
    pointer-events: none;
    opacity: 0.3;
}
.data-table-row-locked .action-icon {
    opacity: 0.3;
    pointer-events: none;
    cursor: default;
}

/* ── Pagination Footer (3-column) ────────────────────── */
/* Only the table scrolls horizontally when narrow — the footer/pager below stays full-width.
   A fixed-layout table at width:100% always fits, but Chrome rounds each column to whole pixels
   and the sum can land 1px past the box, which drew a scroll bar under every table on desktop.
   So nothing scrolls by default; tables given a minimum width (phones, below; the dataset
   explorer) switch scrolling back on. */
.data-table-scroll { overflow-x: clip; width: 100%; }
@media (max-width: 767.98px) {
    .data-table-scroll { overflow-x: auto; }   /* the tables' 620px minimum above */
}

.data-table-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 9px 20px;
    border-top: 1px solid var(--bs-border-color);
    font-size: 12px;
    color: var(--bs-secondary-color);
    background: var(--bs-gray-50);
    /* The count and the page numbers both change under the user. Proportional digits
       re-measure every time and shift the whole row sideways as they do. */
    font-variant-numeric: tabular-nums;
}

/* Left: total records — "Total Projects: 300" */
.data-table-footer-total {
    font-weight: 500;
    white-space: nowrap;
    flex: 0 0 auto;
}
.data-table-footer-total strong {
    color: var(--bs-body-color);
    font-weight: 700;
}

/* Center: page numbers — < 1 [2] 3 4 5 > */
.data-table-footer-pages {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1;
}
/* One segmented control, not six loose boxes.
   The border and the radius belong to the strip; the buttons inside carry
   only a hairline divider between them. Detached boxes read as six separate decisions
   and made the footer look unfinished — a pager is one control, and it should look like
   one. DataTables wraps the numbers in a <span>, so that has to become a flex row too or
   the dividers land on the wrapper instead of on each page. */
.data-table-footer-pages .dataTables_paginate {
    margin: 0 !important;
    padding: 0 !important;
    display: flex;
    align-items: stretch;
    border: 1px solid var(--bs-border-color);
    border-radius: 6px;
    background: var(--bs-body-bg);
    overflow: hidden;
}
.data-table-footer-pages .dataTables_paginate > span,
.data-table-footer-pages .dataTables_paginate > .pagination {
    display: flex;
    align-items: stretch;
    margin: 0;
    padding: 0;
    gap: 0;
}
/* The app's tables use the Bootstrap 5 build of DataTables, which renders each page as
   li.paginate_button > a.page-link rather than a bare button. The segment styling below lands on
   the li; the link inside must add nothing of Bootstrap's own — no border, fill, radius or
   padding — or every page shows as a loose box with its own edge (the admin screens, which render
   bare buttons, never had this). */
.data-table-footer-pages .page-item .page-link {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    margin: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    border-radius: 0 !important;
    background: transparent !important;
    color: inherit !important;
    font: inherit;
    box-shadow: none !important;
    text-decoration: none;
}
/* `transition: all` is avoided deliberately — it animates layout properties too, and
   every one of these redraws on each page change. */
.data-table-footer-pages .paginate_button {
    min-width: 28px;
    height: 28px;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    border: 0 !important;
    border-inline-start: 1px solid var(--bs-border-color) !important;
    border-radius: 0 !important;
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--bs-secondary-color) !important;
    background: transparent !important;
    margin: 0 !important;
    padding: 0 6px !important;
    transition: background var(--ease-fast), color var(--ease-fast) !important;
    line-height: 1 !important;
    cursor: pointer;
    touch-action: manipulation;
}
/* The strip draws its own outer edge; the first segment must not double it. */
.data-table-footer-pages .paginate_button.previous {
    border-inline-start: 0 !important;
}
/* Prev / Next — same segment, bigger glyph, and wider than a digit because an arrow is
   the target people go for without reading. */
.data-table-footer-pages .paginate_button.previous,
.data-table-footer-pages .paginate_button.next {
    font-size: 14px !important;
    min-width: 30px;
    color: var(--bs-gray-500) !important;
}
/* Hover — every enabled segment, arrows included. */
.data-table-footer-pages .paginate_button:hover:not(.disabled):not(.current):not(.active) {
    background: var(--bs-gray-100) !important;
    color: var(--bs-body-color) !important;
}
/* DataTables strips its own focus styling, so without this a keyboard user paging
   through a table has no idea where they are. Inset, because the strip clips its
   overflow and an outer ring would be cut off. */
.data-table-footer-pages .paginate_button:focus-visible {
    outline: 2px solid var(--bs-primary) !important;
    outline-offset: -2px;
}
/* Active page — filled, and it keeps the divider colour off its own edges so the fill
   reads as one solid block rather than a tile with seams. */
/* .active is the Bootstrap 5 build's name for the same state. */
.data-table-footer-pages .paginate_button.current,
.data-table-footer-pages .paginate_button.current:hover,
.data-table-footer-pages .paginate_button.active,
.data-table-footer-pages .paginate_button.active:hover {
    background: var(--bs-primary) !important;
    color: var(--on-primary) !important;
    border-inline-start-color: var(--bs-primary) !important;
    font-weight: 600 !important;
}
.data-table-footer-pages .paginate_button.current + .paginate_button,
.data-table-footer-pages .paginate_button.active + .paginate_button {
    border-inline-start-color: var(--bs-primary) !important;
}
/* Disabled arrows stay in place — a pager that loses a segment at the ends changes
   width as you page, and the row shifts under the pointer. */
.data-table-footer-pages .paginate_button.disabled {
    opacity: 0.4;
    cursor: default;
    pointer-events: none;
}

/* Right: rows per page — "Show per Page: [5 v]" */
.data-table-footer-length {
    display: flex;
    align-items: center;
    gap: 8px;
    justify-content: flex-end;
    flex: 0 0 auto;
    white-space: nowrap;
    margin-inline-start: auto;
}
.data-table-footer-length label {
    margin: 0;
    font-weight: 500;
    color: var(--bs-secondary-color);
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
}
.data-table-footer-length select {
    padding-block: 3px;
    padding-inline: 8px 24px;
    height: 28px;                  /* matches the page buttons beside it */
    border-radius: 6px;
    border: 1px solid var(--bs-border-color);
    background-color: var(--bs-body-bg);
    color: var(--bs-gray-700);
    font-size: 12px;
    min-width: 50px;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b7280' d='M2.5 4.5L6 8l3.5-3.5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 7px center;
    background-size: 10px;
}
html[dir="rtl"] .data-table-footer-length select { background-position: left 7px center; }

/* A finger is not a mouse pointer: 34px is a comfortable target to click and a poor
   one to tap. Widened only where the pointer is actually coarse, rather than inflating
   a desktop footer to phone proportions everywhere. */
@media (pointer: coarse) {
    .data-table-footer-pages .paginate_button {
        min-width: 44px;
        height: 44px;
    }
    .data-table-footer-pages .paginate_button.previous,
    .data-table-footer-pages .paginate_button.next {
        min-width: 48px;
    }
    .data-table-footer-length select { height: 44px; }
}

/* ── Responsive ──────────────────────────────────────── */
@media (max-width: 768px) {
    .data-table-header {
        flex-direction: column;
        align-items: flex-start;
        gap: 12px;
        padding: 16px 18px;
    }
    .data-table-header-right {
        width: 100%;
    }
    .data-table-header-right .btn-action {
        width: 100%;
        justify-content: center;
    }
    .data-table-toolbar {
        flex-wrap: wrap;
        padding: 12px 18px;
    }
    .data-table-search {
        max-width: 100%;
        flex-basis: 100%;
    }
    .data-table-toolbar-right {
        flex-wrap: wrap;
        width: 100%;
    }
    .data-table-filter-wrap {
        flex: 1;
    }
    .data-table-filter-select {
        width: 100%;
    }
    .data-table-table thead th,
    .data-table-table tbody td {
        padding-inline-start: 16px;
        padding-inline-end: 16px;
    }
    .data-table-footer {
        flex-direction: column;
        gap: 12px;
        align-items: center;
        padding: 14px 18px;
    }
    .data-table-footer-total,
    .data-table-footer-pages,
    .data-table-footer-length {
        justify-content: center;
        flex: unset;
    }
}

/* Hide less-critical columns on smaller screens (Projects) */
@media (max-width: 1100px) {
    .data-table-table .pj-proj-name,
    .data-table-table .pj-proj-desc { max-width: 220px; }
    .data-table-table .pj-proj-link { max-width: 220px; }
}
@media (max-width: 900px) {
    .data-table-card { overflow-x: auto; }
    .data-table-table .pj-proj-name,
    .data-table-table .pj-proj-desc { max-width: 160px; }
    .data-table-table .pj-proj-link { max-width: 160px; }
    /* Hide checkbox column + bulk delete on small screens */
    .data-table-table thead th:first-child,
    .data-table-table tbody td:first-child { display: none; }
    .data-table-bulk-delete { display: none !important; }
}

/* ── Dataset Library table: allow header wrapping ───── */
#tblDatasets thead th {
    white-space: normal;
    line-height: 1.4;
    vertical-align: middle;
}

/* ── Responsive: stat cards stack on mobile ─────────── */
@media (max-width: 768px) {
    #statCards { flex-direction: column; }
}

/* ======================================
   Section: Page-Load Entrance Animations
   CSS keyframes with fill-mode:both apply the "from"
   state before first paint — zero flicker on server-
   rendered pages (unlike JS-based gsap.from).
   ====================================== */

@keyframes fadeUp {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes fadeIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}
@keyframes slideLeft {
    from { opacity: 0; transform: translateX(-10px); }
    to   { opacity: 1; transform: translateX(0); }
}
@keyframes slideRight {
    from { opacity: 0; transform: translateX(10px); }
    to   { opacity: 1; transform: translateX(0); }
}
@keyframes spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

/* ── Header: quick fade ────────────────── */
.header {
    animation: fadeIn 0.35s ease-out both;
}

/* ── Sidebar: slide from left ──────────── */
.sidebar {
    animation: slideLeft 0.3s ease-out both;
}

/* ── Sidebar nav items: staggered slide ── */
.sidebar-nav-item {
    animation: slideLeft 0.3s ease-out both;
}
/* RTL: the sidebar sits on the right, so it and its items slide in from the right. */
html[dir="rtl"] .sidebar,
html[dir="rtl"] .sidebar-nav-item {
    animation-name: slideRight;
}
.sidebar-nav-item:nth-child(1)  { animation-delay: 0.04s; }
.sidebar-nav-item:nth-child(2)  { animation-delay: 0.08s; }
.sidebar-nav-item:nth-child(3)  { animation-delay: 0.12s; }
.sidebar-nav-item:nth-child(4)  { animation-delay: 0.16s; }
.sidebar-nav-item:nth-child(5)  { animation-delay: 0.20s; }
.sidebar-nav-item:nth-child(6)  { animation-delay: 0.24s; }
.sidebar-nav-item:nth-child(7)  { animation-delay: 0.28s; }
.sidebar-nav-item:nth-child(8)  { animation-delay: 0.32s; }
.sidebar-nav-item:nth-child(9)  { animation-delay: 0.36s; }
.sidebar-nav-item:nth-child(10) { animation-delay: 0.40s; }

/* ── Sidebar storage widget: fade up ───── */
.sidebar-storage {
    animation: fadeUp 0.35s ease-out 0.25s both;
}

/* ── NOTE: .content is NOT animated ───── */
/* Animating .content creates a CSS stacking context
   (opacity in fill-mode:both) which traps Bootstrap
   modal z-index inside .content — backdrop renders
   above modal, page goes black. Cards are safe because
   modals are NOT children of cards. */

/* ── Cards: staggered fade up ──────────── */
.data-table-card,
.ph-card,
.org-hero,
.org-form-card,
.detail-card {
    animation: fadeUp 0.35s ease-out both;
}
.data-table-card:nth-child(1),    .ph-card:nth-child(1),
.org-hero:nth-child(1), .org-form-card:nth-child(1),
.detail-card:nth-child(1) { animation-delay: 0.08s; }
.data-table-card:nth-child(2),    .ph-card:nth-child(2),
.org-hero:nth-child(2), .org-form-card:nth-child(2),
.detail-card:nth-child(2) { animation-delay: 0.14s; }
.data-table-card:nth-child(3),    .ph-card:nth-child(3),
.org-hero:nth-child(3), .org-form-card:nth-child(3),
.detail-card:nth-child(3) { animation-delay: 0.20s; }
.data-table-card:nth-child(4),    .ph-card:nth-child(4),
.org-hero:nth-child(4), .org-form-card:nth-child(4),
.detail-card:nth-child(4) { animation-delay: 0.26s; }

/* ── Accessibility: kill animations for reduced-motion */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-delay: 0ms !important;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   §26 — Dark Mode: Project Hub (ph-*), Projects Table (pj-*), Alerts, Badges
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Project Hub (ph-*) dark overrides ─────────────────────────── */
[data-bs-theme="dark"] .ph-search-wrap {
    background: var(--card-bg);
    border-color: var(--sidebar-border);
}
[data-bs-theme="dark"] .ph-search-icon { color: var(--bs-gray-500); }
[data-bs-theme="dark"] .ph-search-input { color: var(--bs-body-color); }
[data-bs-theme="dark"] .ph-search-input::placeholder { color: var(--bs-gray-600); }
[data-bs-theme="dark"] .ph-view-toggle {
    background: var(--card-bg);
    border-color: var(--sidebar-border);
}
[data-bs-theme="dark"] .ph-view-btn { color: var(--bs-gray-500); }
[data-bs-theme="dark"] .ph-view-btn:hover {
    background: var(--bs-gray-800);
    color: var(--bs-body-color);
}
[data-bs-theme="dark"] .ph-view-btn.active {
    background: rgba(var(--bs-primary-rgb), 0.15);
    color: var(--bs-primary);
}
[data-bs-theme="dark"] .ph-card {
    background: var(--card-bg);
    border-color: var(--sidebar-border);
    box-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
[data-bs-theme="dark"] .ph-card:hover {
    box-shadow: 0 4px 12px rgba(0,0,0,0.4);
}
[data-bs-theme="dark"] .ph-card-title { color: var(--bs-body-color); }
[data-bs-theme="dark"] .ph-card-desc { color: var(--bs-gray-500); }
[data-bs-theme="dark"] .ph-card-meta {
    border-color: var(--sidebar-border);
    color: var(--bs-gray-500);
}
[data-bs-theme="dark"] .ph-menu-btn { color: var(--bs-gray-500); }
[data-bs-theme="dark"] .ph-menu-btn:hover {
    background: var(--bs-gray-800);
    color: var(--bs-body-color);
}
[data-bs-theme="dark"] .ph-dropdown {
    background: var(--card-bg);
    border-color: var(--sidebar-border);
    box-shadow: 0 4px 12px rgba(0,0,0,0.4);
}
[data-bs-theme="dark"] .ph-dd-item { color: var(--bs-body-color); }
[data-bs-theme="dark"] .ph-dd-item.ph-dd-danger { color: var(--bs-danger); }
[data-bs-theme="dark"] .ph-dd-item.ph-dd-danger:hover {
    background: rgba(var(--bs-danger-rgb), 0.1);
    color: var(--bs-danger);
}
/* Visibility badges keep their light-mode backgrounds in dark mode too */
[data-bs-theme="dark"] .ph-count-badge {
    background: var(--card-bg);
    box-shadow: 0 1px 3px rgba(0,0,0,0.3);
}

/* Status badges keep their light-mode backgrounds in dark mode too (archived stays neutral) */
[data-bs-theme="dark"] .ph-s-archived {
    background: var(--bs-gray-800);
    color: var(--bs-gray-500);
}

/* Type badges (dark) */
[data-bs-theme="dark"] .ph-t-lidar {
    background: rgba(37,99,235,0.15);
    color: #60a5fa;
    border-color: rgba(37,99,235,0.3);
}
[data-bs-theme="dark"] .ph-t-photogrammetry {
    background: rgba(var(--bs-danger-rgb),0.15);
    color: #fca5a5;
    border-color: rgba(var(--bs-danger-rgb),0.3);
}
[data-bs-theme="dark"] .ph-t-pointcloud {
    background: rgba(124,58,237,0.15);
    color: #c4b5fd;
    border-color: rgba(124,58,237,0.3);
}
[data-bs-theme="dark"] .ph-t-elevation {
    background: rgba(var(--bs-success-rgb),0.15);
    color: #6ee7b7;
    border-color: rgba(var(--bs-success-rgb),0.3);
}
[data-bs-theme="dark"] .ph-t-thermal {
    background: rgba(var(--bs-warning-rgb),0.15);
    color: #fcd34d;
    border-color: rgba(var(--bs-warning-rgb),0.3);
}

/* ── Projects Table (pj-*) dark overrides ──────────────────────── */
[data-bs-theme="dark"] .pj-page { background: var(--bs-body-bg); }
[data-bs-theme="dark"] .pj-table-wrap {
    background: var(--card-bg);
    border-color: var(--sidebar-border);
    box-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
[data-bs-theme="dark"] .pj-table thead tr { border-color: var(--sidebar-border); }
[data-bs-theme="dark"] .pj-table thead th {
    color: var(--bs-gray-500);
    background: var(--card-bg);
}
[data-bs-theme="dark"] .pj-table tbody tr { border-color: var(--sidebar-border); }
[data-bs-theme="dark"] .pj-proj-name { color: var(--bs-body-color); }
[data-bs-theme="dark"] .pj-proj-desc { color: var(--bs-gray-500); }
[data-bs-theme="dark"] .pj-proj-data { color: var(--bs-gray-500); }
[data-bs-theme="dark"] .pj-col-text { color: var(--bs-body-color); }
[data-bs-theme="dark"] .pj-processing { color: var(--bs-gray-500); }
[data-bs-theme="dark"] .pj-avatar { border-color: var(--card-bg); }
[data-bs-theme="dark"] .pj-avatar-more {
    background: var(--bs-gray-700);
    color: var(--bs-gray-300);
    border-color: var(--card-bg);
}
[data-bs-theme="dark"] .pj-no-members { color: var(--bs-gray-600); }
[data-bs-theme="dark"] .pj-action-btn { color: var(--bs-gray-500); }
[data-bs-theme="dark"] .pj-action-btn:hover {
    color: var(--bs-body-color);
    background: var(--bs-gray-800);
}

/* ── Alerts dark overrides ─────────────────────────────────────── */
[data-bs-theme="dark"] .alert-danger {
    background: rgba(var(--bs-danger-rgb), 0.1);
    border-color: rgba(var(--bs-danger-rgb), 0.25);
    color: #fca5a5;
}
[data-bs-theme="dark"] .alert-success {
    background: rgba(var(--bs-success-rgb), 0.1);
    border-color: rgba(var(--bs-success-rgb), 0.25);
    color: #6ee7b7;
}
[data-bs-theme="dark"] .alert-warning {
    background: rgba(var(--bs-warning-rgb), 0.1);
    border-color: rgba(var(--bs-warning-rgb), 0.25);
    color: #fcd34d;
}
[data-bs-theme="dark"] .alert-info {
    background: rgba(var(--bs-info-rgb), 0.1);
    border-color: rgba(var(--bs-info-rgb), 0.25);
    color: #93c5fd;
}

/* ── Universal Animated Action Modal System ───────────── */
.action-dialog-popup {
    max-width: 360px !important;
    padding: 32px 28px 28px !important;
    border-radius: 16px !important;
    border: none !important;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15) !important;
}
.action-dialog-loading { text-align: center; }
.action-dialog-icon-wrap {
    width: 64px;
    height: 64px;
    margin: 0 auto 16px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    /* GSAP handles animation via animations.js §4 */
}
.action-dialog-icon {
    font-size: 28px;
    /* GSAP handles animation via animations.js §4 */
}
.action-dialog-title {
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--bs-body-color);
    margin-bottom: 4px;
}
.action-dialog-subtitle {
    font-size: 0.8125rem;
    color: var(--bs-secondary-color);
    margin-bottom: 20px;
}
.action-dialog-bar {
    height: 4px;
    background: var(--bs-gray-200);
    border-radius: 999px;
    overflow: hidden;
}
.action-dialog-bar-fill {
    height: 100%;
    width: 30%;
    border-radius: 999px;
    /* GSAP handles animation via animations.js §4 */
}

/* ── Action Themes (color per action type) ────────── */

/* Delete — Red */
.action-dialog--delete .action-dialog-icon-wrap { background: linear-gradient(135deg, #fee2e2, #fecaca); }
.action-dialog--delete .action-dialog-icon { color: #dc2626; }
.action-dialog--delete .action-dialog-bar-fill { background: linear-gradient(90deg, #dc2626, #ef4444, #dc2626); background-size: 200% 100%; }

/* Save — Green */
.action-dialog--save .action-dialog-icon-wrap { background: linear-gradient(135deg, #dcfce7, #bbf7d0); }
.action-dialog--save .action-dialog-icon { color: #16a34a; }
.action-dialog--save .action-dialog-bar-fill { background: linear-gradient(90deg, #16a34a, #22c55e, #16a34a); background-size: 200% 100%; }

/* Send — Blue */
.action-dialog--send .action-dialog-icon-wrap { background: linear-gradient(135deg, #dbeafe, #bfdbfe); }
.action-dialog--send .action-dialog-icon { color: #2563eb; }
.action-dialog--send .action-dialog-bar-fill { background: linear-gradient(90deg, #2563eb, #3b82f6, #2563eb); background-size: 200% 100%; }

/* Process — Purple */
.action-dialog--process .action-dialog-icon-wrap { background: linear-gradient(135deg, #f3e8ff, #e9d5ff); }
.action-dialog--process .action-dialog-icon { color: #9333ea; }
.action-dialog--process .action-dialog-bar-fill { background: linear-gradient(90deg, #9333ea, #a855f7, #9333ea); background-size: 200% 100%; }

/* Load — Sky */
.action-dialog--load .action-dialog-icon-wrap { background: linear-gradient(135deg, #e0f2fe, #bae6fd); }
.action-dialog--load .action-dialog-icon { color: #0284c7; }
.action-dialog--load .action-dialog-bar-fill { background: linear-gradient(90deg, #0284c7, #0ea5e9, #0284c7); background-size: 200% 100%; }

/* Warn — Amber */
.action-dialog--warn .action-dialog-icon-wrap { background: linear-gradient(135deg, #fef3c7, #fde68a); }
.action-dialog--warn .action-dialog-icon { color: #d97706; }
.action-dialog--warn .action-dialog-bar-fill { background: linear-gradient(90deg, #d97706, #f59e0b, #d97706); background-size: 200% 100%; }

/* ── Keyframes — migrated to GSAP (animations.js §4) ─ */
/* action-dialog-pulse, action-dialog-wobble, action-dialog-progress,
   action-dialog-spin, action-dialog-bounce — all handled by GSAP
   with runtime control (pause/reverse on modal close). */

/* ── Dark Theme ────────────────────────────────────── */
[data-bs-theme="dark"] .action-dialog--delete .action-dialog-icon-wrap { background: linear-gradient(135deg, rgba(220,38,38,0.2), rgba(239,68,68,0.15)); }
[data-bs-theme="dark"] .action-dialog--save .action-dialog-icon-wrap { background: linear-gradient(135deg, rgba(22,163,74,0.2), rgba(34,197,94,0.15)); }
[data-bs-theme="dark"] .action-dialog--send .action-dialog-icon-wrap { background: linear-gradient(135deg, rgba(37,99,235,0.2), rgba(59,130,246,0.15)); }
[data-bs-theme="dark"] .action-dialog--process .action-dialog-icon-wrap { background: linear-gradient(135deg, rgba(147,51,234,0.2), rgba(168,85,247,0.15)); }
[data-bs-theme="dark"] .action-dialog--load .action-dialog-icon-wrap { background: linear-gradient(135deg, rgba(2,132,199,0.2), rgba(14,165,233,0.15)); }
[data-bs-theme="dark"] .action-dialog--warn .action-dialog-icon-wrap { background: linear-gradient(135deg, rgba(217,119,6,0.2), rgba(245,158,11,0.15)); }
[data-bs-theme="dark"] .action-dialog-popup { box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4) !important; }

/* Legacy bulk-delete aliases removed — now uses showActionLoading({ type: 'delete' }) */


/* ======================================
   Enterprise Contact Modal — Two-column
   ====================================== */

.ent-dialog {
    max-width: 960px;
    width: 100%;
}
.ent-modal {
    border: none;
    border-radius: 16px;
    overflow: hidden;
    box-shadow: 0 28px 72px rgba(0, 0, 0, 0.2);
}
.ent-close {
    position: absolute;
    top: 14px;
    inset-inline-end: 14px;
    z-index: 10;
    opacity: 0.65;
}
.ent-close:hover { opacity: 1; }

/* Two-column wrapper */
.ent-layout {
    display: flex;
    min-height: 520px;
}

/* ── Left panel ── */
.ent-left {
    width: 320px;
    flex-shrink: 0;
    background: linear-gradient(160deg, #0f172a 0%, #1e1b4b 60%, #0f172a 100%);
    padding: 36px 28px;
    display: flex;
    flex-direction: column;
}
.ent-left-inner {
    display: flex;
    flex-direction: column;
    height: 100%;
}
.ent-icon-wrap {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    background: rgba(251, 191, 36, 0.12);
    border: 1px solid rgba(251, 191, 36, 0.28);
    border-radius: 12px;
    font-size: 22px;
    color: #fbbf24;
    margin-bottom: 14px;
}
.ent-badge {
    display: inline-block;
    width: fit-content;
    background: rgba(251, 191, 36, 0.12);
    border: 1px solid rgba(251, 191, 36, 0.28);
    color: #fbbf24;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.1em;
    padding: 3px 10px;
    border-radius: 999px;
    margin-bottom: 12px;
}
.ent-title {
    margin: 0 0 8px;
    color: #f1f5f9;
    font-size: 1.2rem;
    font-weight: 700;
    line-height: 1.3;
}
.ent-subtitle {
    margin: 0 0 24px;
    color: #94a3b8;
    font-size: 0.8rem;
    line-height: 1.55;
}
.ent-features {
    list-style: none;
    padding: 0;
    margin: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.ent-features li {
    display: flex;
    align-items: center;
    gap: 10px;
    color: #cbd5e1;
    font-size: 0.8rem;
    line-height: 1.4;
}
.ent-features li i {
    font-size: 15px;
    color: #7dd3fc;
    flex-shrink: 0;
    width: 16px;
    text-align: center;
}
.ent-response-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 24px;
    background: rgba(255,255,255,0.06);
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 8px;
    padding: 8px 12px;
    color: #94a3b8;
    font-size: 0.75rem;
}
.ent-response-badge i { color: #7dd3fc; font-size: 13px; }

/* ── Right panel ── */
.ent-right {
    flex: 1;
    padding: 32px 28px 28px;
    background: var(--bs-body-bg);
    display: flex;
    flex-direction: column;
    justify-content: center;
}
.ent-form-heading {
    font-size: 0.95rem;
    font-weight: 700;
    margin-bottom: 16px;
    color: var(--bs-body-color);
}
.form-label {
    font-size: 0.78rem;
    font-weight: 500;
    margin-bottom: 4px;
}
.ent-opt {
    font-weight: 400;
    color: var(--bs-secondary-color);
    font-size: 0.72rem;
}
.ent-submit-row {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}
.ent-submit {
    min-width: 140px;
    font-weight: 600;
    font-size: 0.85rem;
}
.ent-privacy {
    color: var(--bs-secondary-color);
    font-size: 0.75rem;
}

/* Success state */
.ent-success {
    text-align: center;
    padding: 24px 0;
}
.ent-success-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 60px;
    height: 60px;
    background: rgba(22, 163, 74, 0.1);
    border-radius: 50%;
    font-size: 30px;
    color: #16a34a;
    margin: 0 auto;
}

/* Dark mode */
[data-bs-theme="dark"] .ent-modal {
    box-shadow: 0 28px 72px rgba(0, 0, 0, 0.5);
}
[data-bs-theme="dark"] .ent-left {
    background: linear-gradient(160deg, #020617 0%, #0f0c29 60%, #020617 100%);
}
[data-bs-theme="dark"] .ent-right {
    background: var(--bs-body-bg);
}

/* Mobile: stack columns */
@media (max-width: 640px) {
    .ent-dialog { max-width: 100%; margin: 0.5rem; }
    .ent-layout { flex-direction: column; min-height: unset; }
    .ent-left {
        width: 100%;
        padding: 24px 20px 20px;
    }
    .ent-features { display: none; } /* hide features list on mobile — too long */
    .ent-right { padding: 20px; }
}

/* Enterprise modal — icon animation support */
.ent-icon-wrap {
    position: relative;
    overflow: visible !important;
}
.ent-particles {
    position: absolute;
    inset: 0;
    pointer-events: none;
    overflow: visible;
}
.ent-particle {
    position: absolute;
    bottom: 50%;
    left: 50%;
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: #fbbf24;
    opacity: 0;
    transform: translateX(-50%);
}
.ent-particle:nth-child(2) { background: #fde68a; width: 3px; height: 3px; }
.ent-particle:nth-child(3) { background: #f59e0b; width: 5px; height: 5px; }
.ent-particle:nth-child(4) { background: #fef3c7; width: 3px; height: 3px; }
.ent-particle:nth-child(5) { background: #fbbf24; width: 4px; height: 4px; }

/* ── Clerk branding suppression ── */
.cl-internal-12b32jh { display: none !important; }

/* ── Clerk UserButton popover — dark navy in dark mode only ── */
[data-bs-theme="dark"] .cl-userButtonPopoverCard,
[data-bs-theme="dark"] .cl-userButtonPopoverMain,
[data-bs-theme="dark"] .cl-userButtonPopoverFooter,
[data-bs-theme="dark"] .cl-cardBox,
[data-bs-theme="dark"] .cl-popoverBox,
[data-bs-theme="dark"] .cl-card {
    background-color: #1e293b !important;
    border-color: #334155 !important;
    box-shadow: none !important;
}
[data-bs-theme="dark"] .cl-userPreviewMainIdentifier,
[data-bs-theme="dark"] .cl-userButtonPopoverActionButton,
[data-bs-theme="dark"] .cl-userButtonPopoverActionButton *,
[data-bs-theme="dark"] .cl-userButtonPopoverActionButton__text {
    color: #ffffff !important;
}
[data-bs-theme="dark"] .cl-userPreviewSecondaryIdentifier,
[data-bs-theme="dark"] .cl-userButtonPopoverActionButtonIcon,
[data-bs-theme="dark"] .cl-userButtonPopoverActionButton__iconBox {
    color: #cbd5e1 !important;
}
[data-bs-theme="dark"] .cl-userButtonPopoverActionButton:hover {
    background-color: #334155 !important;
}
[data-bs-theme="dark"] .cl-userButtonPopoverFooter {
    border-top-color: #334155 !important;
}

/* ── Trial expired — sidebar badge + banner ── */
#sidebar-plan-badge.badge-trial-expired { color: var(--warning) !important; }
.trial-banner { border-inline-start-color: var(--warning); }
.trial-banner .overquota-icon { background: rgba(217,119,6,.10); color: var(--warning); }
.trial-banner .overquota-title { color: var(--warning); }
[data-bs-theme="dark"] .trial-banner .overquota-icon { background: rgba(217,119,6,.18); }

