        @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');

        .text-base-20 { font-size: 20px; line-height: 1.6; }

        /* PDF Canvas Constraints & Updated Typography from image_1568f7.png */
        .pdf-print-container {
            width: 794px;
            height: 1123px;
            padding: 70px 55px;
            box-sizing: border-box;
            background: #ffffff;
            position: relative;
            font-family: 'Mabry Pro', 'Inter', sans-serif;
            font-variant-numeric: tabular-nums;
            font-feature-settings: "tnum" 1;
            color: #1e293b;
        }
        /* No flexbox for vertical layout — html2canvas mis-handles flex-grow and
           margin:auto in fixed-height columns, which left a big gap at the top of
           the PDF. Instead: main content flows from the top normally, and the
           footer is absolutely pinned to the bottom padding box. */
        .pdf-print-main { display: block; }
        .pdf-print-spacer { display: none; }
        .pdf-print-footer {
            position: absolute;
            left: 55px;
            right: 55px;
            bottom: 70px;
        }

        /* Logo sizing — max-width is set inline from layout.logoScale so the
           Design editor's size slider can override this default. */
        .pdf-logo-wrapper img {
            max-width: 140px;
            height: auto !important;
        }

        .stable-dropdown-cell {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            height: 38px;
            box-sizing: border-box;
        }
        
        .custom-scrollbar::-webkit-scrollbar {
            height: 6px;
            width: 6px;
        }
        .custom-scrollbar::-webkit-scrollbar-track {
            background: transparent;
        }
        .custom-scrollbar::-webkit-scrollbar-thumb {
            background: rgba(100, 116, 139, 0.2);
            border-radius: 4px;
        }
        .custom-scrollbar::-webkit-scrollbar-thumb:hover {
            background: rgba(100, 116, 139, 0.35);
        }
        /* ── Liquid-glass nav indicator ──
           A glass capsule slides between tabs and refracts the page content behind
           it via a runtime SVG displacement filter (#nav-liquid-filter), built for
           the pill's size. On Chromium/Opera that yields true Apple-style glass; the
           frosted blur below is the base look and the fallback elsewhere. */
        .nav-liquid { gap: 3px; padding: 5px; }

        .nav-tabs { position: relative; z-index: 0; display: flex; gap: 3px; }
        .nav-tab {
            appearance: none; border: 0; background: transparent; cursor: pointer;
            padding: 8px 18px; height: 38px; border-radius: 19px;
            display: inline-flex; align-items: center; line-height: 1; white-space: nowrap;
            transition: color .4s ease, font-weight .3s ease;
            outline: none;  /* kill browser default focus ring (looks like a black halo on dark theme) */
        }
        /* Keep a subtle focus indicator for keyboard users only */
        .nav-tab:focus-visible { box-shadow: 0 0 0 2px rgba(99,102,241,.35); }

        .nav-glass {
            position: absolute; top: 50%; left: 0; width: 0; transform: translateY(-50%);
            height: 38px; border-radius: 19px; z-index: 1; pointer-events: none;
            isolation: isolate;
            border: 1px solid rgba(255,255,255,.35);
            /* Inset glow REMOVED — was reading as a top-of-pill reflection,
               especially against dark backgrounds. The refraction effect on
               ::before still gives it the glassy feel without the highlight. */
            transition: opacity .3s ease, border-color .6s ease;
            will-change: left, width;
        }
        /* Refraction layer — its own element BEHIND the glass content (z-index -1),
           which is what backdrop-filter requires to distort what's behind it. Base
           is a frosted blur; the displacement filter replaces it once generated. */
        .nav-glass::before {
            content: ''; position: absolute; inset: 0; z-index: -1; border-radius: inherit;
            backdrop-filter: blur(7px) saturate(1.5) brightness(1.05);
            -webkit-backdrop-filter: blur(7px) saturate(1.5) brightness(1.05);
            background: rgba(255,255,255,.10);
            isolation: isolate;
        }
        .nav-glass.lg-ready::before {
            backdrop-filter: url(#nav-liquid-filter);
            -webkit-backdrop-filter: url(#nav-liquid-filter);
            background: rgba(255,255,255,.06);
            transition: filter .8s cubic-bezier(.4,0,.2,1);
        }
        /* extra glow/brightness on the refraction layer while travelling */
        .nav-glass.is-moving::before { filter: brightness(1.08) saturate(1.12); }
        /* Top specular streak — REMOVED per user feedback. The white blob at
           the top of the pill reads as oddly placed reflection, particularly
           on dark theme. Refraction effect itself stays via ::before. */
        .nav-glass::after { display: none; }
        .nav-glass.is-moving::after { display: none; }
        .nav-glass.is-moving {
            border-color: rgba(255,255,255,.55);
        }

        /* Smooth expand/collapse for editor panels (premium graphics, sections).
           grid-template-rows 0fr->1fr animates variable-height content cleanly. */
        .collapsible {
            display: grid; grid-template-rows: 0fr;
            transition: grid-template-rows .35s cubic-bezier(.4,0,.2,1), opacity .3s ease;
            opacity: 0;
        }
        .collapsible.open { grid-template-rows: 1fr; opacity: 1; }
        .collapsible > .collapsible-inner { overflow: hidden; min-height: 0; }

        /* Invoice card actions: Share stays visible (ghost style); the secondary
           icons are always visible but subdued at rest, brightening on hover so
           there's no discoverability trap on trackpad-only laptops. */
        .inv-actions { display:flex; align-items:center; gap:2px; }
        .inv-secondary {
            display:flex; align-items:center; gap:2px;
            opacity:0.45;
            transition: opacity .18s ease;
        }
        .group:hover .inv-secondary,
        .inv-card:hover .inv-secondary,
        .inv-secondary:focus-within { opacity:1; }
        @media (hover:none) {            /* touch devices: always fully visible */
            .inv-secondary { opacity:1; }
        }

        /* Invoice-card variant: hidden at rest, slow graceful fade-in on hover.
           Used on the invoice archive cards where a calm resting state is
           preferred and the actions reveal only when the user engages. */
        .inv-secondary--fade {
            opacity:0;
            transition: opacity .45s cubic-bezier(.4,0,.2,1);
            pointer-events:none;
        }
        .group:hover .inv-secondary--fade,
        .inv-card:hover .inv-secondary--fade,
        .inv-secondary--fade:focus-within {
            opacity:1;
            pointer-events:auto;
        }
        @media (hover:none) {
            .inv-secondary--fade { opacity:1; pointer-events:auto; }
        }

        /* Section edit panel reveal — fade + slight slide down on open */
        @keyframes panelReveal { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: translateY(0); } }
        .panel-reveal { animation: panelReveal .3s cubic-bezier(.4,0,.2,1) both; }
        @media (prefers-reduced-motion: reduce) { .panel-reveal { animation: none; } }

        /* Mobile: scale the big rolling counters down so long values (e.g. $115.650,00)
           don't overflow the stat cards and push the labels off-screen. Transform
           scaling preserves the internal px-based digit-roll geometry. */
        @media (max-width: 767px) {
            /* Stack each stat card vertically: label on top, big number below.
               This removes the side-by-side crowding that pushed labels off-card. */
            .stat-card {
                flex-direction: column !important;
                justify-content: flex-start !important;
                gap: 8px !important;
                min-height: 0 !important;
                padding: 18px !important;
                overflow: hidden;
            }
            .stat-card > .self-start { align-self: flex-start !important; order: 0; }
            .stat-card > .self-end { align-self: flex-start !important; order: 1; }
            /* Total Projects card: its metadata block is right-aligned for desktop;
               on mobile flip it to left-aligned so it lines up under the label and
               doesn't leave the number stranded with empty space beside it. */
            .stat-card > .self-start.flex-col { align-items: flex-start !important; text-align: left !important; }
            .stat-card > .self-start.flex-col .justify-end { justify-content: flex-start !important; }
            .stat-label { letter-spacing: 0.04em !important; white-space: normal; }
            .rolling-counter { transform: scale(0.72); transform-origin: left center; }
            /* shrink the decorative right-edge gradient so it doesn't overlay the number */
            .stat-card > .absolute { width: 40% !important; }
            /* never allow horizontal scroll / edge-clipping on phones */
            html, body { overflow-x: hidden; max-width: 100vw; }
        }

        /* Tablet (768–1023px): stat cards are 3-across but narrower than desktop, so
           scale the big rolling numbers down a touch so long values fit cleanly. */
        @media (min-width: 768px) and (max-width: 1023px) {
            .rolling-counter { transform: scale(0.82); transform-origin: left center; }
            .stat-card { padding: 20px !important; }
        }

        /* Smooth, momentum scrolling inside scroll panels (client list, holds, etc.)
           These panels opt out of the global Lenis smooth scroller (data-lenis-prevent),
           so we add native smooth + touch momentum here for a fluid feel. */
        .custom-scrollbar {
            scroll-behavior: smooth;
            -webkit-overflow-scrolling: touch;
            scrollbar-width: thin;
            scrollbar-color: rgba(100, 116, 139, 0.25) transparent;
        }

        /* Rolling Animation Rules */
        .rolling-number-window {
            display: inline-flex;
            overflow: hidden;
        }
        .rolling-digit-container {
            display: flex;
            flex-direction: column;
            transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
        }
        .rolling-digit-item {
            text-align: center;
        }

        /* Financial privacy blur — applied to money values on PAID and OUTSTANDING
           cards when the user has toggled the eye icon closed. Hover over the parent
           card (.stat-card) unblurs so the owner can peek without toggling. */
        .fin-blur {
            filter: blur(8px);
            transition: filter 0.18s cubic-bezier(0.4, 0, 0.2, 1);
        }
        .stat-card:hover .fin-blur {
            filter: blur(0);
        }

        /* Smooth Accordion Collapse/Expand Transitions */
        .accordion-body {
            display: grid;
            grid-template-rows: 0fr;
            transition: grid-template-rows 0.35s cubic-bezier(0.4, 0, 0.2, 1);
        }
        .accordion-body.is-open {
            grid-template-rows: 1fr;
        }
        .accordion-body > .accordion-inner {
            overflow: hidden;
        }
        /* Card-style body: white BG, matching border, rounded-b + shadow — but
           only when the parent accordion is .is-open. Opacity syncs to the same
           duration/easing as the height animation so nothing snaps. When collapsed,
           the border/bg/shadow are transparent, meaning no hairline shows under
           the closed year row (the "divider leftover" bug). */
        .accordion-card-body {
            background: transparent;
            border: 1px solid transparent;
            border-top: none;
            border-radius: 0 0 0.75rem 0.75rem;
            overflow: hidden;
            box-shadow: none;
            transition: background 0.35s cubic-bezier(0.4, 0, 0.2, 1),
                        border-color 0.35s cubic-bezier(0.4, 0, 0.2, 1),
                        box-shadow 0.35s cubic-bezier(0.4, 0, 0.2, 1);
        }
        .accordion-body.is-open > .accordion-card-body {
            background: #ffffff;
            border-color: rgb(241 245 249);  /* slate-100 */
            box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
        }
        .dark .accordion-body.is-open > .accordion-card-body {
            background: #232731;
            border-color: #2a2f3b;
        }
        .accordion-chevron {
            transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);
            display: inline-flex;
            align-items: center;
            justify-content: center;
            color: #94a3b8;
        }
        .accordion-chevron.is-open {
            transform: rotate(90deg);
        }

        /* Hide all scrollbars globally */
        * {
            scrollbar-width: none !important;
            -ms-overflow-style: none !important;
        }
        *::-webkit-scrollbar {
            display: none !important;
            width: 0 !important;
            height: 0 !important;
        }

        /* Force calendar pickers for uniform dark-mode UI styling */
        .dark input[type="date"]::-webkit-calendar-picker-indicator {
            filter: invert(56%) sepia(51%) saturate(476%) hue-rotate(104deg) brightness(91%) contrast(88%);
            cursor: pointer;
        }
        
        /* Fallback styling context variables for Light Mode native pickers */
        html:not(.dark) input[type="date"]::-webkit-calendar-picker-indicator {
            filter: none;
            cursor: pointer;
        }

        /* Smooth page/view fade — each top-level view fades + drifts up gently on
           switch. Slower than the default so the transition is clearly visible. */
        @keyframes viewFadeIn {
            from { opacity: 0; }
            to   { opacity: 1; }
        }
        .view-fade { animation: viewFadeIn .35s cubic-bezier(.22,1,.36,1) both; }
        @media (prefers-reduced-motion: reduce) {
            .view-fade { animation: none; }
        }
        /* Soft fade for the invoice preview + archive when content changes.
           Pure opacity (no movement) so it's kept even under reduced-motion —
           the user explicitly wants this fade visible. */
        @keyframes fadeSoftIn {
            from { opacity: 0; }
            to   { opacity: 1; }
        }
        .fade-soft { animation: fadeSoftIn .3s ease both; }

        /* Brief flash focus when navigating to a hold from the dashboard chip */
        @keyframes holdFlashAnim {
            0%, 100% { background-color: transparent; }
            30%, 70% { background-color: rgba(20, 184, 166, 0.22); }
        }
        .hold-flash { animation: holdFlashAnim 0.85s ease-in-out 3; border-radius: 10px; }

        /* Project-archive stripe: base 4px wide, expands horizontally to ~10px
           when the user hovers anywhere on the project row (not just the stripe
           itself, which is too thin to target reliably). The .group class on the
           parent tr lets us target group hover via :hover on that ancestor.
           Flash highlight on the destination task row in the Tasks tab when
           jumped to via this stripe mirrors the .hold-flash pattern above. */
        .task-stripe { width: 4px; transition: width 0.18s ease; }
        tr.group:hover .task-stripe { width: 10px; }
        @keyframes taskFlashAnim {
            0%, 100% { background-color: transparent; }
            30%, 70% { background-color: rgba(59, 91, 232, 0.18); }
        }
        .task-flash > td { animation: taskFlashAnim 0.85s ease-in-out 3; }

        /* Task badges (priority / status pills in the Tasks tab) — Bonsai style:
           soft tinted background using the badge's own color at 15% opacity,
           lightly rounded rectangle (not a full pill), no border, small dot to
           the left. The 250ms transition makes the hover-darken feel smooth. */
        .task-badge {
            display: inline-flex; align-items: center; gap: 8px;
            padding: 4px 10px; border-radius: 6px;
            font-size: 12px; font-weight: 600;
            border: 0; cursor: pointer;
            transition: filter 0.25s ease, transform 0.25s ease;
        }
        .task-badge:hover { filter: brightness(0.92) saturate(1.15); }
        .task-badge-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; }

        /* Avatar circle for the Assignee column in the task grid.
           Background color set inline (deterministic per email), letter is
           the email's first character uppercased. White text, semibold,
           sized to read clearly at the table's row density. */
        .assignee-avatar {
            display: inline-flex; align-items: center; justify-content: center;
            width: 26px; height: 26px;
            border-radius: 50%;
            color: #fff; font-weight: 600; font-size: 12px;
            line-height: 1; cursor: default;
            transition: transform 0.18s ease;
        }
        .assignee-avatar:hover { transform: scale(1.08); }

        /* Stacked assignees (multi-assignee task). Avatars overlap by 8px so
           a row of two reads as ~44px wide rather than 60px. Each avatar gets
           a thin white outline so the overlap stays visually crisp. */
        .assignee-stack { display: inline-flex; align-items: center; }
        .assignee-stack .assignee-avatar { margin-left: -8px; box-shadow: 0 0 0 2px #fff; }
        html.dark .assignee-stack .assignee-avatar { box-shadow: 0 0 0 2px #232731; }
        .assignee-stack .assignee-avatar:first-child { margin-left: 0; }
        .assignee-stack .assignee-more { font-size: 10px; }

        /* Shared tab badge + flash animation — appears for invitees when they
           have new task assignments they haven't viewed yet. Two parts: a small
           red badge with the count, and a gentle pulsing border around the tab
           itself. Stops when the user clicks through to the Shared view. */
        .shared-badge {
            display: inline-flex; align-items: center; justify-content: center;
            min-width: 18px; height: 18px; padding: 0 5px;
            background: #ef4444; color: #fff;
            border-radius: 9px;
            font-size: 10px; font-weight: 700;
            margin-left: 4px;
        }
        @keyframes sharedFlashAnim {
            0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
            50%      { box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.28); }
        }
        .shared-flash { animation: sharedFlashAnim 1.6s ease-in-out infinite; border-radius: 8px; }

        /* ── DATE PICKER ───────────────────────────────────────────
           Custom calendar popover used everywhere a date is entered.
           Replaces native <input type="date"> for a consistent look
           on every browser. Three view modes: day grid / month grid /
           year grid. Popover is position:fixed so it escapes any
           overflow:hidden ancestor (table cells, modals). */
        .dp-wrap { position: relative; }
        .dp-trigger {
            display: inline-flex; align-items: center; justify-content: space-between;
            gap: 8px; width: 100%; min-width: 0;
            padding: 6px 10px; border-radius: 4px;
            background: #ffffff; color: #1e293b;
            border: 1px solid #e2e8f0;
            font-family: inherit; cursor: pointer;
            text-align: left;
            box-shadow: 0 1px 2px rgba(0,0,0,0.02);
            transition: border-color 0.15s ease, background 0.15s ease;
        }
        .dp-trigger:hover { border-color: #cbd5e1; }
        /* No colored outline ring on focus — matches the calmer style of the
           cell-control inputs elsewhere. */
        .dp-trigger:focus-visible { outline: none; border-color: #94a3b8; }
        html.dark .dp-trigger { background: #1e222b; color: #e5e7eb; border-color: #2a2f3b; }
        html.dark .dp-trigger:hover { border-color: #3a3f4b; }
        .dp-val { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: ui-monospace, 'SF Mono', Menlo, monospace; }
        .dp-placeholder { color: #94a3b8; font-family: inherit; }
        html.dark .dp-placeholder { color: #697284; }
        .dp-icon { flex-shrink: 0; opacity: 0.5; }
        /* Bare trigger — no calendar icon, centered value, brand font (used by the
           Projects "project dates" + "paid date" cells). */
        .dp-trigger.dp-bare { justify-content: center; }
        .dp-bare .dp-val { flex: 0 1 auto; text-align: center; font-family: inherit; }

        /* Popover. Rendered with position:fixed via inline style; this rule
           only handles non-positional styling. */
        .dp-pop {
            min-width: 280px; max-width: 320px;
            background: #ffffff; color: #1e293b;
            border: 1px solid #e2e8f0; border-radius: 10px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.12), 0 2px 6px rgba(0,0,0,0.06);
            padding: 12px;
            animation: dpFadeIn 0.16s cubic-bezier(0.16, 1, 0.3, 1);
            transform-origin: top left;
            /* Stack above sibling table rows + general page content. Matches the
               inline zIndex DatePicker sets via JS; ensures ProjectCalendarSelector
               (which doesn't set zIndex inline) gets it too. */
            z-index: 1000;
        }
        html.dark .dp-pop {
            background: #1a1d24; color: #e5e7eb;
            border-color: #2a2f3b;
            box-shadow: 0 10px 30px rgba(0,0,0,0.45), 0 2px 6px rgba(0,0,0,0.25);
        }
        @keyframes dpFadeIn {
            from { opacity: 0; transform: translateY(-4px) scale(0.98); }
            to   { opacity: 1; transform: translateY(0) scale(1); }
        }

        /* ── CLIENT PICKER (custom select with logo + company + contact) ────── */
        .cp-trigger {
            display: inline-flex; align-items: center; justify-content: space-between;
            gap: 8px; width: 100%; min-width: 0;
            padding: 6px 12px; border-radius: 6px;
            background: #f8fafc; color: #0f172a;
            border: 1px solid #f1f5f9;
            font-family: inherit; cursor: pointer; text-align: left;
            transition: border-color .15s ease, background .15s ease;
        }
        .cp-trigger:hover { border-color: #cbd5e1; }
        .cp-trigger:focus-visible { outline: none; border-color: #94a3b8; }
        html.dark .cp-trigger { background: #1e222b; color: #e5e7eb; border-color: #2d3342; }
        html.dark .cp-trigger:hover { border-color: #3a3f4b; }
        .cp-trigger-logo { width: 22px; height: 22px; object-fit: contain; flex-shrink: 0; border-radius: 9999px; background: #fff; padding: 1px; }
        html.dark .cp-trigger-logo { background: #2a2f3b; }
        .cp-icon { flex-shrink: 0; opacity: .5; }
        .cp-placeholder { color: #94a3b8; }
        html.dark .cp-placeholder { color: #697284; }

        .cp-pop {
            background: #ffffff; color: #0f172a;
            border: 1px solid #e2e8f0; border-radius: 10px;
            box-shadow: 0 12px 40px rgba(0,0,0,.16), 0 2px 6px rgba(0,0,0,.06);
            overflow: hidden; z-index: 1000;
            animation: dpFadeIn .16s cubic-bezier(.16,1,.3,1);
            transform-origin: top left;
        }
        html.dark .cp-pop { background: #1a1d24; color: #e5e7eb; border-color: #2a2f3b; box-shadow: 0 12px 40px rgba(0,0,0,.5); }
        .cp-search {
            width: 100%; padding: 8px 10px; border-radius: 6px;
            background: #f8fafc; color: #0f172a; border: 1px solid #e2e8f0;
            font-family: inherit; outline: none;
        }
        html.dark .cp-search { background: #1e222b; color: #e5e7eb; border-color: #2d3342; }
        .cp-opt {
            display: grid; align-items: center; gap: 10px; width: 100%;
            padding: 8px 10px; text-align: left; background: transparent;
            border: 0; cursor: pointer; font-family: inherit;
            transition: background .12s ease;
        }
        .cp-opt:hover { background: #f1f5f9; }
        html.dark .cp-opt:hover { background: #1e222b; }
        .cp-opt[data-sel="1"] { background: rgba(0,0,0,.05); }
        html.dark .cp-opt[data-sel="1"] { background: rgba(255,255,255,.06); }
        .cp-opt-logo { display: flex; align-items: center; justify-content: center; height: 20px; }
        .cp-opt-logo img { width: 20px; height: 20px; object-fit: contain; border-radius: 9999px; background: #fff; padding: 1px; }
        html.dark .cp-opt-logo img { background: #2a2f3b; }
        .cp-opt-name { font-weight: 600; color: #1e293b; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        html.dark .cp-opt-name { color: #e5e7eb; }
        .cp-opt-contact { color: #64748b; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        html.dark .cp-opt-contact { color: #8b94a7; }
        .cp-empty { padding: 14px; text-align: center; color: #94a3b8; }
        .cp-add { display: flex; align-items: center; gap: 8px; width: 100%; padding: 10px 12px; text-align: left; cursor: pointer; font-family: inherit; border: 0; border-top: 1px solid #e2e8f0; background: transparent; font-weight: 600; transition: background .12s ease; }
        .cp-add:hover { background: #f1f5f9; }
        html.dark .cp-add { border-top-color: #2a2f3b; }
        html.dark .cp-add:hover { background: #1e222b; }

        /* ── STATUS PICKER (rounded, coloured, staggered reveal) ────────────── */
        .sp-trigger { display: inline-flex; align-items: center; gap: 7px; width: 100%; padding: 5px 10px; border-radius: 8px; border: 1px solid transparent; cursor: pointer; font-family: inherit; transition: filter .15s ease; }
        .sp-trigger:hover { filter: brightness(0.96); }
        .sp-trigger:disabled { opacity: .55; cursor: not-allowed; }
        .sp-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
        .sp-icon { opacity: .6; flex: none; }
        .sp-pop { padding: 5px; }
        .sp-opt { display: flex; align-items: center; gap: 8px; width: 100%; padding: 7px 10px; border: 0; background: transparent; border-radius: 7px; cursor: pointer; font-family: inherit; text-align: left; opacity: 0; transform: translateY(-4px); animation: spReveal .26s cubic-bezier(.16,1,.3,1) forwards; }
        .sp-opt:hover { background: rgba(0,0,0,.05); }
        html.dark .sp-opt:hover { background: rgba(255,255,255,.07); }
        .sp-opt[data-sel="1"] { background: rgba(0,0,0,.045); }
        html.dark .sp-opt[data-sel="1"] { background: rgba(255,255,255,.05); }
        @keyframes spReveal { to { opacity: 1; transform: none; } }
        @media (prefers-reduced-motion: reduce) { .sp-opt { animation: none; opacity: 1; transform: none; } }

        /* ── DROPDOWN (generic custom select) ──────────────────────────────── */
        .dd-trigger { display: inline-flex; align-items: center; gap: 8px; width: 100%; padding: 6px 12px; border-radius: 8px; background: #f8fafc; color: #0f172a; border: 1px solid #f1f5f9; cursor: pointer; font-family: inherit; text-align: left; transition: border-color .15s ease; }
        .dd-trigger:hover { border-color: #cbd5e1; }
        .dd-trigger:disabled { opacity: .55; cursor: not-allowed; }
        html.dark .dd-trigger { background: #1e222b; color: #e5e7eb; border-color: #2d3342; }
        .dd-val { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .dd-icon { flex: none; opacity: .5; }
        .dd-placeholder { color: #94a3b8; }
        .dd-pop { padding: 5px; }
        .dd-opt { display: flex; align-items: baseline; gap: 8px; width: 100%; padding: 8px 10px; border: 0; background: transparent; border-radius: 7px; cursor: pointer; font-family: inherit; text-align: left; }
        .dd-opt:hover { background: #f1f5f9; }
        html.dark .dd-opt:hover { background: #1e222b; }
        .dd-opt[data-sel="1"] { background: rgba(0,0,0,.045); }
        html.dark .dd-opt[data-sel="1"] { background: rgba(255,255,255,.05); }
        .dd-opt-label { font-weight: 600; color: #1e293b; }
        html.dark .dd-opt-label { color: #e5e7eb; }
        .dd-note { font-weight: 400; color: #94a3b8; font-size: .9em; }
        .dd-trigger.dd-center { justify-content: center; }
        .dd-center .dd-val { flex: 0 1 auto; text-align: center; }

        /* ── CUSTOM CHECKBOX (.ms-check) ───────────────────────────────────── */
        .ms-check-input { position: absolute; opacity: 0; width: 0; height: 0; }
        .ms-check { width: 15px; height: 15px; border-radius: 4px; border: 1.5px solid #cbd5e1; display: inline-flex; align-items: center; justify-content: center; transition: background .15s, border-color .15s; flex: none; color: #fff; }
        html.dark .ms-check { border-color: #3a4150; }
        .ms-check svg { opacity: 0; transform: scale(.5); transition: opacity .15s, transform .15s; }
        .ms-check-input:checked + .ms-check { background: var(--ms-accent, #3b5be8); border-color: var(--ms-accent, #3b5be8); }
        .ms-check-input:checked + .ms-check svg { opacity: 1; transform: scale(1); }
        .ms-check-input:focus-visible + .ms-check { box-shadow: 0 0 0 3px rgba(59,91,232,.25); }

        /* ── TOOLTIP (.ms-tip — a "?" that reveals help text on hover) ──────── */
        .ms-tip { position: relative; display: inline-flex; align-items: center; color: #94a3b8; cursor: help; opacity: .8; }
        .ms-tip:hover { opacity: 1; }
        .ms-tip:hover::after, .ms-tip:focus-visible::after { content: attr(data-tip); position: absolute; left: 50%; bottom: calc(100% + 9px); transform: translateX(-50%); background: #1e293b; color: #fff; padding: 7px 11px; border-radius: 9px; font-size: 11px; font-weight: 500; line-height: 1.4; white-space: normal; width: max-content; max-width: 230px; text-transform: none; letter-spacing: normal; box-shadow: 0 8px 24px rgba(0,0,0,.28); z-index: 3000; }
        .ms-tip:hover::before, .ms-tip:focus-visible::before { content: ''; position: absolute; left: 50%; bottom: calc(100% + 4px); transform: translateX(-50%); border: 5px solid transparent; border-top-color: #1e293b; z-index: 3000; }

        /* Rename hint — reveals slowly (opacity only) when the field is hovered or
           focused. Its space is always reserved (in-flow) so it never overlaps the
           field below and never shifts anything when it fades in. */
        .rename-hint { opacity: 0; margin-top: 5px; margin-bottom: 2px; transition: opacity .6s ease; }
        .rename-wrap:hover .rename-hint, .rename-wrap:focus-within .rename-hint { opacity: 1; }

        /* Logos fade in from transparent once their pixels actually load (no pop-in).
           JS adds .is-loaded on the <img> onLoad event. */
        .logo-fade { opacity: 0; transition: opacity .35s ease; }
        .logo-fade.is-loaded { opacity: 1; }
        @media (prefers-reduced-motion: reduce) { .logo-fade { transition: none; } }

        /* Circle mask so every logo reads as a consistent round badge. */
        .logo-circle { border-radius: 9999px; background: #fff; object-fit: contain; padding: 2px; }
        html.dark .logo-circle { background: #2a2f3b; }

        /* Small inline spinner (e.g. "Finding contact details…"). */
        .ms-spin { animation: msSpin .7s linear infinite; transform-origin: center; }
        @keyframes msSpin { to { transform: rotate(360deg); } }
        @media (prefers-reduced-motion: reduce) { .ms-spin { animation: none; } }

        /* Header (month name + year + arrows). Month and year are clickable;
           clicking them switches the popover into month-picker or year-picker mode. */
        .dp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
        .dp-title-group { display: flex; gap: 4px; }
        .dp-title-btn {
            border: 0; background: transparent;
            font: inherit; font-weight: 700; font-size: 13px;
            color: #1e293b; cursor: pointer;
            padding: 4px 8px; border-radius: 5px;
            transition: background 0.15s ease;
            text-transform: uppercase; letter-spacing: 0.04em;
        }
        .dp-title-btn:hover { background: #f1f5f9; }
        html.dark .dp-title-btn { color: #f1f5f9; }
        html.dark .dp-title-btn:hover { background: #2a2f3b; }
        .dp-title-static {
            font-weight: 700; font-size: 13px;
            text-transform: uppercase; letter-spacing: 0.04em;
        }
        .dp-nav {
            border: 0; background: transparent;
            width: 26px; height: 26px;
            border-radius: 6px;
            display: flex; align-items: center; justify-content: center;
            font-size: 17px; line-height: 1; cursor: pointer;
            color: #64748b;
            transition: background 0.15s ease;
        }
        .dp-nav:hover { background: #f1f5f9; color: #1e293b; }
        html.dark .dp-nav { color: #94a3b8; }
        html.dark .dp-nav:hover { background: #2a2f3b; color: #f1f5f9; }

        /* Day-of-week strip */
        .dp-dow {
            display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px;
            margin-bottom: 4px;
        }
        .dp-dow-cell {
            text-align: center; font-size: 10px;
            text-transform: uppercase; letter-spacing: 0.05em;
            color: #94a3b8; padding: 4px 0;
            font-weight: 600;
        }
        .dp-dow-weekend { color: #cbd5e1; }
        html.dark .dp-dow-cell { color: #7c8496; }
        html.dark .dp-dow-weekend { color: #4b5363; }

        /* Day grid (default view) */
        .dp-grid {
            display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px;
        }
        .dp-day {
            aspect-ratio: 1 / 1;
            display: flex; align-items: center; justify-content: center;
            border: 0; background: transparent;
            color: #334155; font-size: 12px; font-weight: 600;
            font-family: ui-monospace, 'SF Mono', Menlo, monospace;
            border-radius: 5px;
            cursor: pointer;
            transition: background 0.12s ease, color 0.12s ease;
        }
        .dp-day:hover:not(.dp-day-sel):not(.dp-day-disabled) {
            background: #f1f5f9;
        }
        .dp-day-out { color: #cbd5e1; }
        .dp-day-today:not(.dp-day-sel) {
            color: #3b5be8; position: relative;
        }
        .dp-day-today:not(.dp-day-sel)::after {
            content: ''; position: absolute;
            bottom: 3px; left: 50%; transform: translateX(-50%);
            width: 3px; height: 3px; border-radius: 50%;
            background: currentColor;
        }
        .dp-day-disabled { color: #e2e8f0; cursor: not-allowed; }
        .dp-day-disabled:hover { background: transparent; }
        html.dark .dp-day { color: #cbd5e1; }
        html.dark .dp-day:hover:not(.dp-day-sel):not(.dp-day-disabled) { background: #2a2f3b; }
        html.dark .dp-day-out { color: #4b5363; }
        html.dark .dp-day-today:not(.dp-day-sel) { color: #6884ed; }
        html.dark .dp-day-disabled { color: #3a3f4b; }

        /* Month-grid + year-grid (the two alternate views). 3 columns × 4 rows. */
        .dp-mgrid {
            display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px;
            margin-top: 4px;
        }
        .dp-mcell {
            padding: 12px 6px;
            border: 0; background: transparent;
            color: #334155; font-size: 12px; font-weight: 600;
            font-family: inherit;
            border-radius: 5px;
            cursor: pointer;
            transition: background 0.12s ease, color 0.12s ease;
        }
        .dp-mcell:hover:not(.dp-mcell-sel) { background: #f1f5f9; }
        html.dark .dp-mcell { color: #cbd5e1; }
        html.dark .dp-mcell:hover:not(.dp-mcell-sel) { background: #2a2f3b; }

        /* Footer */
        .dp-foot {
            display: flex; gap: 4px; margin-top: 10px;
            padding-top: 10px; border-top: 1px solid #f1f5f9;
        }
        html.dark .dp-foot { border-top-color: #2a2f3b; }
        .dp-foot-btn {
            border: 0; background: transparent;
            padding: 6px 10px; border-radius: 5px;
            font-size: 12px; font-weight: 600;
            color: #475569; cursor: pointer;
            font-family: inherit;
            transition: background 0.15s ease, color 0.15s ease;
        }
        .dp-foot-btn:hover { background: #f1f5f9; color: #1e293b; }
        .dp-foot-clear { color: #ef4444; }
        .dp-foot-clear:hover { background: #fef2f2; color: #dc2626; }
        .dp-foot-close { margin-left: auto; }
        html.dark .dp-foot-btn { color: #94a3b8; }
        html.dark .dp-foot-btn:hover { background: #2a2f3b; color: #f1f5f9; }
        html.dark .dp-foot-clear { color: #f87171; }
        html.dark .dp-foot-clear:hover { background: rgba(239,68,68,0.12); color: #fca5a5; }

        /* Suppress the browser's default black focus outline on all form
           controls. Keep :focus-visible with a subtle accent shadow for
           keyboard-nav accessibility. Alex flagged this as an ugly black
           halo, especially on dark theme. */
        input:focus, textarea:focus, select:focus, button:focus,
        [contenteditable]:focus {
            outline: none;
        }
        input:focus-visible, textarea:focus-visible, select:focus-visible,
        [contenteditable]:focus-visible {
            box-shadow: 0 0 0 2px rgba(99,102,241,.25);
            border-radius: 4px;
        }

        /* ImageBrowser wall tile — fully reset browser button defaults so
           there's NO hover/focus styling. The user explicitly doesn't want
           hover-state distractions or unexpected scaling/lightening. */
        .dp-wall-tile {
            background: transparent !important;
            border: 0;
            outline: none;
            appearance: none;
            -webkit-appearance: none;
            /* No transitions of any kind — even subtle ones look like
               flicker when the canvas pans behind them. */
            transition: none !important;
            transform: none !important;
        }
        .dp-wall-tile:hover, .dp-wall-tile:focus, .dp-wall-tile:active {
            background: transparent !important;
            filter: none !important;
            transform: none !important;
        }
        /* Inner img — explicit overrides so nothing inherits any hover state */
        .dp-wall-tile img,
        .dp-wall-tile:hover img,
        .dp-wall-tile:focus img,
        .dp-wall-tile:active img {
            filter: none !important;
            opacity: 1 !important;
            transition: none !important;
            transform: none !important;
        }

        /* Hover lift for the inline button-row buttons in the image browser
           (zoom in/out, reset, theme toggle, ?, close). Color comes from
           inline style; we just bump background slightly on hover. */
        .dp-ib-btn { transition: filter 0.15s ease; }
        .dp-ib-btn:hover { filter: brightness(1.4); }

        /* Task badge popover menu (status / priority dropdowns).
           Sized to content: just wide enough for the longest label, never the
           full-width fixed min-width that was leaving a big empty area on the
           right. Fade + slight downward slide on open ("statuses show slowly
           when user hovers" → animate in on appearance). */
        .task-menu {
            min-width: max-content;
            max-width: 280px;
            transform-origin: top left;
            animation: taskMenuIn 0.22s cubic-bezier(0.16, 1, 0.3, 1);
        }
        @keyframes taskMenuIn {
            from { opacity: 0; transform: translateY(-4px) scaleY(0.96); }
            to   { opacity: 1; transform: translateY(0)    scaleY(1);    }
        }

        /* History carousel: hover brings unfocused cards into focus */
        .hist-card { transition: opacity 0.25s ease, transform 0.3s cubic-bezier(0.22, 1, 0.36, 1) !important; }
        .hist-card:hover { opacity: 1 !important; z-index: 8 !important; }
        .hist-card:hover .hist-card-inner { box-shadow: 0 6px 20px rgba(0,0,0,0.14); border-color: #94a3b8; }

        /* Analytics chart tooltip — light/dark mode variables */
        :root {
            --chart-tooltip-bg: #ffffff;
            --chart-tooltip-border: #e2e8f0;
            --chart-tooltip-text: #64748b;
            --chart-tooltip-month: #475569;
        }
        .dark {
            --chart-tooltip-bg: #1a1d24;
            --chart-tooltip-border: #2d3342;
            --chart-tooltip-text: #a0a5b5;
            --chart-tooltip-month: #697284;
        }

        /* Light theme default page background */
        body.light-mode-override { background-color: var(--studio-bg, #e3e3e3) !important; }

        /* Smooth scrolling site-wide */
        html, body { scroll-behavior: smooth; }
        .custom-scrollbar { scroll-behavior: smooth; }

        /* Smoother, eased button hovers app-wide. !important overrides Tailwind's
           .transition utility (150ms linear) which would otherwise win. */
        button:not([data-no-ease]), .btn, a[role="button"] {
            transition-property: transform, box-shadow, background-color, border-color, filter, color !important;
            transition-duration: .32s !important;
            transition-timing-function: cubic-bezier(.34, 1.4, .42, 1) !important;
        }
        button:not(:disabled):hover, .btn:hover, a[role="button"]:hover {
            filter: brightness(1.08) !important;
        }
        button:not(:disabled):active { transform: translateY(1px) scale(.99); }

        /* Login window button — smooth premium hover */
        .login-btn { transition: transform .3s cubic-bezier(.34,1.4,.42,1), box-shadow .3s ease, filter .25s ease !important; will-change: transform; }
        .login-btn:hover:not(:disabled) { transform: translateY(-2px); filter: brightness(1.07); box-shadow: 0 8px 24px rgba(59,91,232,.45), inset 0 1px 0 rgba(255,255,255,.3) !important; }
        .login-btn:active:not(:disabled) { transform: translateY(0); }
        .login-field:focus { box-shadow: 0 0 0 3px rgba(59,91,232,.12); }

        /* Continue-with-Google button — smooth hover */
        .google-btn { transition: background-color .25s ease, border-color .25s ease, transform .25s cubic-bezier(.34,1.4,.42,1), box-shadow .25s ease !important; }
        .google-btn:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0,0,0,.08) !important; }

        /* Maintenance indicator banner — gentle attention pulse */
        .maint-banner { box-shadow: 0 2px 12px rgba(217,119,6,.4); transition: filter .2s ease; animation: maintPulse 2.6s ease-in-out infinite; }
        .maint-banner:hover { filter: brightness(1.06); animation: none; }
        @keyframes maintPulse { 0%,100% { box-shadow: 0 2px 12px rgba(217,119,6,.4); } 50% { box-shadow: 0 2px 20px rgba(217,119,6,.7); } }
        @media (prefers-reduced-motion: reduce) { .maint-banner { animation: none; } }

        /* ── Unified project-row controls ──
           One height + font for every interactive cell control (date inputs,
           selects, status, payment button, calendar triggers) so the row reads
           as a consistent set instead of random sizes. */
        .cell-control {
            height: 32px;
            line-height: 1;
            font-family: 'Mabry Pro', ui-sans-serif, system-ui, sans-serif;
            display: inline-flex;
            align-items: center;
            box-sizing: border-box;
            vertical-align: middle;
        }
        /* Native date inputs: normalize their internal layout to match */
        .cell-control[type="date"] { padding-top: 0; padding-bottom: 0; }
        .cell-control[type="date"]::-webkit-calendar-picker-indicator { opacity: .55; cursor: pointer; }
        /* font-mono fields keep mono numerals but same box */
        .cell-control.font-mono { font-family: 'JetBrains Mono', ui-monospace, monospace; }

        /* ── Brand numerals (invoice form + archive) ──
           In the New/Edit invoice tab and the invoice archive, numbers and IDs
           should use the brand font (Mabry Pro), not the monospace stack. We keep
           tabular figures so amounts still align in columns. This overrides any
           font-mono inside these containers without touching analytics/settings. */
        .brand-numerals .font-mono,
        .brand-numerals [class*="font-mono"] {
            font-family: 'Mabry Pro', ui-sans-serif, system-ui, sans-serif !important;
            font-variant-numeric: tabular-nums;
            font-feature-settings: "tnum" 1;
        }

        /* ── Focus mode (Pro) ──
           Row dimming is handled in JS (components.js) via inline opacity for
           reliability. This CSS only dims the SURROUNDING CHROME (projects header
           bar + other year groups) while the cursor is over the table, driven by
           :has(tbody.focus-mode:hover) which stays true across rows (no flicker).
           Header metric cards live OUTSIDE .focus-on, so they stay bright. */
        .focus-on > * {
            transition: opacity .6s cubic-bezier(0.4, 0, 0.2, 1);
        }
        .focus-on:has(tbody.focus-mode:hover) > *:not(:has(tbody.focus-mode:hover)) {
            opacity: .4;
        }
        @media (prefers-reduced-motion: reduce) {
            .focus-on > * { transition: opacity .6s ease; }
        }

        /* ── Invoice live canvas (Studio-style live preview) ──
           The InvoiceSheet is always 794px wide (A4). We scale it down
           to fill whatever the viewport container gives us. The outer
           .invoice-canvas-viewport clips and sizes the visible area;
           the inner .invoice-canvas-scaler applies a CSS scale transform
           and adjusts the host element's visible footprint so the parent
           layout collapses correctly around the scaled-down content.       */
        .invoice-canvas-viewport {
            width: 100%;
            max-width: 100%;
            overflow: hidden;
            background: #ffffff;
        }
        .invoice-canvas-scaler {
            /* 794px is the canonical A4 canvas width */
            width: 794px;
            transform-origin: top left;
            /* Default scale — overridden by JS-injected style */
            transform: scale(var(--canvas-scale, 0.62));
            /* Collapse the height to the scaled value so the container
               does not leave a giant blank gap below the canvas. */
            height: calc(1123px * var(--canvas-scale, 0.62));
        }

        /* ── Section hover-highlight (Design editor → preview) ──
           When a section row is hovered in the editor, the matching
           [data-section] in the canvas gets a soft accent outline that
           fades in/out. data-hl is set on the scaler to the hovered key. */
        .invoice-canvas-scaler [data-section] {
            outline: 2px solid transparent;
            outline-offset: 3px;
            border-radius: 2px;
            transition: outline-color .18s ease, background-color .18s ease;
        }
        .invoice-canvas-scaler[data-hl="billTo"]    [data-section="billTo"],
        .invoice-canvas-scaler[data-hl="lineItems"] [data-section="lineItems"],
        .invoice-canvas-scaler[data-hl="totals"]    [data-section="totals"],
        .invoice-canvas-scaler[data-hl="notes"]     [data-section="notes"],
        .invoice-canvas-scaler[data-hl="bank"]      [data-section="bank"],
        .invoice-canvas-scaler[data-hl="footer"]    [data-section="footer"],
        .invoice-canvas-scaler[data-hl="header"]    [data-section="header"] {
            outline-color: var(--hl-color, #3b5be8);
            background-color: color-mix(in srgb, var(--hl-color, #3b5be8) 7%, transparent);
        }

        /* ── Settings dropdown: eased open AND close ──
           Always in the DOM; we animate opacity + transform so it glides both
           ways instead of snapping on/off in a single frame. */
        .settings-menu {
            opacity: 0;
            transform: translateY(-8px) scale(0.97);
            transform-origin: top right;
            pointer-events: none;
            visibility: hidden;
            transition: opacity .28s cubic-bezier(0.22, 1, 0.36, 1),
                        transform .28s cubic-bezier(0.22, 1, 0.36, 1),
                        visibility 0s linear .28s;
        }
        .settings-menu.is-open {
            opacity: 1;
            transform: translateY(0) scale(1);
            pointer-events: auto;
            visibility: visible;
            transition: opacity .28s cubic-bezier(0.22, 1, 0.36, 1),
                        transform .28s cubic-bezier(0.22, 1, 0.36, 1),
                        visibility 0s linear 0s;
        }
        @media (prefers-reduced-motion: reduce) {
            .settings-menu { transition: opacity .15s linear, visibility 0s linear .15s; transform: none; }
            .settings-menu.is-open { transition: opacity .15s linear, visibility 0s linear 0s; transform: none; }
        }

/* Rich text content (editor + rendered notes) */
.rich-content { line-height: 1.55; }
.rich-content b, .rich-content strong { font-weight: 700; }
.rich-content i, .rich-content em { font-style: italic; }
.rich-content u { text-decoration: underline; }
.rich-content s, .rich-content strike { text-decoration: line-through; }
.rich-content h1, .rich-content h2, .rich-content h3 { font-weight: 700; margin: 0.4em 0 0.2em; line-height: 1.25; }
.rich-content h1 { font-size: 1.4em; } .rich-content h2 { font-size: 1.2em; } .rich-content h3 { font-size: 1.05em; }
.rich-content ul, .rich-content ol { margin: 0.3em 0; padding-left: 1.4em; }
.rich-content ul { list-style: disc; } .rich-content ol { list-style: decimal; }
.rich-content li { margin: 0.15em 0; }
.rich-content a { color: #3b5be8; text-decoration: underline; }
.rich-content blockquote { border-left: 2px solid currentColor; opacity: .8; margin: 0.4em 0; padding-left: 0.8em; }
.rich-editor .rich-content:empty:before { content: ''; }

/* Open Runde — used by the login gate (and future Acctual-style app surfaces).
   Self-hosted at site root /fonts; app/css -> ../../fonts. */
@font-face { font-family:'Open Runde'; src:url('../../fonts/openrunde-regular.woff2') format('woff2');  font-weight:400; font-display:swap; }
@font-face { font-family:'Open Runde'; src:url('../../fonts/openrunde-medium.woff2') format('woff2');   font-weight:500; font-display:swap; }
@font-face { font-family:'Open Runde'; src:url('../../fonts/openrunde-semibold.woff2') format('woff2'); font-weight:600; font-display:swap; }

/* ── Year rows: staggered reveal / collapse (one by one) — grid-rows so the
   collapse is smooth at ANY content height and never clips an open table. */
.year-reveal { display: grid; grid-template-rows: 1fr;
    transition: grid-template-rows .5s cubic-bezier(.4,0,.2,1), opacity .4s ease, margin .5s cubic-bezier(.4,0,.2,1); }
.year-reveal > .year-reveal-inner { overflow: hidden; min-height: 0; }
.year-reveal.is-hidden { grid-template-rows: 0fr; opacity: 0; margin-top: 0 !important; pointer-events: none; }
/* Year tab: no press-scale (overrides the global button:active); use a subtle
   background change for hover/click feedback instead. */
.year-tab button:active { transform: none !important; }


/* Hide number-input spinners so centred RATE / QTY values sit truly centred
   (the up/down arrows reserved space on the right, shifting text off-centre). */
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; appearance: none; margin: 0; }
input[type=number] { -moz-appearance: textfield; appearance: textfield; }

