/* ============================================================================
   Sorted — professional design system
   Spacing 4/8 rhythm · restrained type weights · semantic tokens · responsive
   ============================================================================ */

:root {
    /* ==========================================================
       Design tokens — canonical set. Legacy variable names below
       (--bg, --surface, --s1..--s8, --accent, etc.) are kept as
       aliases so existing CSS/templates across the app keep working;
       new component code should reach for the --color-*/--space-*/
       --radius-*/--font-*/--shadow-* names directly.
       ========================================================== */

    /* Brand — Gaffiero Digital brand manual, Edition 01. Sorted is
       Gaffiero's own product family: same typeface (Jost) and spacing as
       the Gaffiero wordmark, but its own lead colors - the manual is
       explicit that "Sorted leads with Noir and Ivory; the studio leads
       with Midnight and Mist." Midnight/Slate/Mist are supporting tones
       inside Sorted's own Noir/Ivory system, not a second identity.
       --accent is still the per-account customizable color (set inline in
       base.html from settings.theme_color) - only the FALLBACK before a
       tenant picks their own changes from the old generic orange.
       Slate, not Midnight: a solid-fill button needs to read against
       BOTH a Noir and an Ivory background since this one hex has to work
       in both themes, and Midnight-on-Noir contrast is only 1.21 (the
       button all but disappears in dark mode) against Slate's 3.58 - the
       manual's own restrained palette simply has no separate "pop" accent
       hue, so the mid-tone neutral is the one that actually works as a
       CTA in both modes. --color-primary always mirrors it. */
    --accent: #626E7D;
    --color-primary: var(--accent);
    --color-primary-hover: #56606D;
    --color-primary-subtle: color-mix(in srgb, var(--color-primary) 10%, transparent);
    --color-primary-border: color-mix(in srgb, var(--color-primary) 25%, transparent);

    /* Neutrals — dark mode first, and Sorted's default per the manual.
       Noir background; surfaces are Noir blended toward Slate for
       restrained-but-visible elevation (contrast 1.14/1.27/1.48 vs bg -
       "let one colour fill the space" is a deliberately quiet system, not
       flat to the point cards disappear). Text is Ivory; muted/subtle are
       Slate lightened for legibility on a near-black background (raw
       Slate reads as low-contrast on Noir - contrast-checked, not
       eyeballed: muted is 6.06:1 against bg). */
    --color-bg: #121314;
    --color-surface: #1D2023;
    --color-surface-2: #25292D;
    --color-surface-3: #2F343A;
    --color-border: rgba(247, 245, 240, 0.12);
    --color-border-strong: rgba(247, 245, 240, 0.18);

    /* Text */
    --color-text: #F7F5F0;
    --color-text-muted: #8C949D;
    --color-text-subtle: #697583;

    /* Semantic — nudged off the stock Tailwind palette (#10B981/#F59E0B/
       #EF4444/#3B82F6, instantly recognizable as unmodified defaults) into
       the same considered family, without changing what each color means. */
    --color-success: #2DA96F;
    --color-success-subtle: rgba(45, 169, 111, 0.12);
    --color-warning: #EC9E18;
    --color-warning-subtle: rgba(236, 158, 24, 0.12);
    --color-danger: #DB434A;
    --color-danger-subtle: rgba(219, 67, 74, 0.12);
    --color-info: #3E7CE0;
    --color-info-subtle: rgba(62, 124, 224, 0.12);

    /* Spacing scale */
    --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
    --space-5: 20px; --space-6: 24px; --space-8: 32px; --space-10: 40px; --space-12: 48px;

    /* Radii — --radius-lg matches the brand manual's own --gd-radius-card
       (18px) exactly. */
    --radius-sm: 6px;
    --radius-md: 14px;
    --radius-lg: 20px;
    --radius-xl: 24px;
    --radius-full: 9999px;

    /* Typography — Jost per the brand manual ("used for the logo,
       headlines, body text and interfaces"), loaded via Google Fonts in
       base.html with the exact weight list brand-tokens.css specifies
       (300/400/500/600 = Light/Regular/Medium/SemiBold). Sizes are
       unchanged from the previous pass - that scale was bumped up from a
       denser SaaS default for outdoor/over-45 legibility, which has
       nothing to do with typeface and still applies. */
    --font-sans: 'Jost', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --font-accent: 'Cormorant Garamond', Georgia, serif;
    --font-size-xs: 0.8125rem;
    --font-size-sm: 1rem;
    --font-size-base: 1.0625rem;
    --font-size-lg: 1.1875rem;
    --font-size-xl: 1.3125rem;
    --font-size-2xl: 1.5rem;
    --font-size-3xl: 1.875rem;
    --font-size-4xl: 2.25rem;

    /* Shadows — tinted toward the bg hue instead of pure black, so a
       raised card's shadow reads as "this surface's own shadow" rather
       than a generic drop-shadow pasted on top. */
    --shadow-sm: 0 1px 3px rgba(6, 7, 7, 0.3);
    --shadow-md: 0 4px 12px rgba(6, 7, 7, 0.4);
    --shadow-lg: 0 8px 30px rgba(6, 7, 7, 0.5);
    --shadow-primary: 0 4px 20px color-mix(in srgb, var(--color-primary) 25%, transparent);

    /* Sidebar / chrome */
    --sidebar-width: 236px;
    --sidebar-collapsed: 64px;
    --topbar-height: 56px;
    --bottom-nav-height: 60px;

    /* === legacy aliases (existing CSS + inline styles rely on these) === */
    --bg: var(--color-bg);
    --bg-sidebar: #0D0E0E;
    --surface: var(--color-surface);
    --surface-2: var(--color-surface-2);
    --surface-3: var(--color-surface-3);
    --bg-elevated: var(--color-surface-3);
    --border: var(--color-border);
    --border-strong: var(--color-border-strong);

    --text: var(--color-text);
    --text-muted: var(--color-text-muted);
    --text-soft: var(--color-text-subtle);

    --accent-blue: var(--color-info);
    --accent-green: var(--color-success);
    --accent-red: var(--color-danger);
    --accent-yellow: var(--color-warning);
    --success: var(--color-success);
    --warning: var(--color-warning);
    --danger: var(--color-danger);
    --ring-track: rgba(247, 245, 240, 0.08);

    --bg-page: var(--bg);
    --bg-card: var(--surface);
    --bg-input: var(--surface-3);
    --text-primary: var(--text);
    --text-secondary: var(--text-muted);

    --radius-card: var(--radius-lg);
    --radius-btn: var(--radius-md);

    --shadow: var(--shadow-md);

    --s1: var(--space-1); --s2: var(--space-2); --s3: var(--space-3); --s4: var(--space-4);
    --s5: var(--space-5); --s6: var(--space-6); --s7: var(--space-8); --s8: var(--space-12);

    --ease: cubic-bezier(0.2, 0.6, 0.2, 1);
    --container: 1180px;
    color-scheme: dark;
}

/* Light theme (per-account settings.theme_mode) — overrides the canonical
   neutral tokens above, not the legacy aliases. Aliases like --bg/--text
   are themselves `var(--color-*)`, so overriding the canonical names here
   repaints them automatically; overriding only the aliases (as this used
   to work, via an inline <style> block in base.html) left everything that
   reads --color-* directly - body, .card, .badge-neutral, .empty-state,
   and more - stuck on the dark values. --bg-sidebar and --ring-track have
   no canonical backing and stay explicit. */
[data-theme="light"] {
    color-scheme: light;
    /* Ivory is the brand's own "main background" per brand-tokens.css -
       Sorted's light mode isn't a generic light-gray SaaS theme, it's the
       other half of Sorted's own Noir/Ivory pairing. */
    --color-bg: #F7F5F0;
    --color-surface: #FFFFFF;
    --color-surface-2: #E8EBE9;
    --color-surface-3: #E0E5E6;
    --color-border: rgba(18, 19, 20, 0.12);
    --color-border-strong: rgba(18, 19, 20, 0.18);
    --color-text: #121314;
    --color-text-muted: #626E7D;
    --color-text-subtle: #969DA5;
    --bg-sidebar: #FFFFFF;
    --ring-track: rgba(18, 19, 20, 0.08);

    /* The same hex rarely reads well as text on both a near-black and a
       near-white surface, so semantic colors get their own light-mode
       shade here (darker + more saturated) — the -subtle tint backgrounds
       stay the shared dark-mode hue at 12% opacity in both modes, since a
       translucent overlay composites fine against either surface. */
    --color-success: #188150;
    --color-warning: #9D5707;
    --color-danger: #C52028;
    --color-info: #195CC8;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
/* Any element that pairs a `display`-setting class with the native `hidden`
   attribute silently ignores `hidden` — author-origin `display` rules beat
   the browser's own `[hidden]{display:none}` UA rule regardless of
   specificity. Without this, .empty-state (and anything else styled with an
   explicit display) renders even while `hidden` is set. */
[hidden] { display: none !important; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

/* Inline-SVG icons (see the icon() Jinja global + _icon_sprite.html), sized
   in `em` so every existing font-size-based sizing rule (.nav-icon,
   .empty-state-icon, .kpi-icon, etc.) keeps working unchanged - only the
   glyph source changed, not how it's sized. */
.icon {
    width: 1em; height: 1em; display: inline-block; flex-shrink: 0;
    vertical-align: -0.15em;
    stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
    fill: none;
}

body {
    min-height: 100dvh;
    background: var(--color-bg);
    color: var(--color-text);
    font-family: var(--font-sans);
    font-size: var(--font-size-base);
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }

h1, h2, h3, h4 { font-weight: 400; line-height: 1.2; letter-spacing: -0.01em; color: var(--text); }
h1 { font-size: clamp(1.4rem, 1.1rem + 1.4vw, 1.6rem); }
h2 { font-size: clamp(1.2rem, 1rem + 1vw, 1.35rem); }
h3 { font-size: clamp(1.02rem, 0.95rem + 0.4vw, 1.1rem); }
h4 { font-size: 0.98rem; }
strong, b { font-weight: 600; }
:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 3px; border-radius: 6px; }

/* ============================================================================
   Responsive safety net — keep every page adaptable on all devices, forever.
   - media never overflows its container
   - flex/grid children may shrink below content (the #1 cause of side-scroll)
   - long words/emails/URLs wrap instead of forcing horizontal scroll
   ============================================================================ */
img, video, canvas, picture, iframe { max-width: 100%; height: auto; }
svg { max-width: 100%; }
.page-shell, .main-content, .panel, .stat-card, .list-card, .table-wrap,
.content-grid > *, .stats-grid > *, .form-row > *, .stack-panel > *, .kpi-grid > *, .deadline-row > * { min-width: 0; }
p, h1, h2, h3, h4, td, th, .topbar-title, .detail-title {
    overflow-wrap: break-word; word-break: break-word;
}
/* Numbers must never be allowed to break mid-character (e.g. "€1,18" / "0.00")
   — that's illegible, not "responsive". If a number + its label don't fit
   side by side, the label wraps onto its own line above the number instead. */
.stat-value, .list-card strong, .list-card b { white-space: nowrap; }
.list-card { flex-wrap: wrap; row-gap: 4px; }

/* ----------------------------------------------------------------- shell */
.app-shell { display: grid; grid-template-columns: var(--sidebar-width) 1fr; min-height: 100dvh; }

.sidebar {
    background: var(--bg-sidebar);
    border-right: 1px solid var(--border);
    padding: var(--s5) var(--s4) var(--s4);
    position: sticky; top: 0; height: 100dvh;
    display: flex; flex-direction: column; gap: 0;
    z-index: 40;
    overflow-y: auto; scrollbar-width: none;
}
.sidebar::-webkit-scrollbar { display: none; }

.brand {
    display: flex; flex-direction: column; gap: 2px;
    padding: var(--s2) var(--s2) var(--s5); margin-bottom: var(--s2);
    border-bottom: 1px solid var(--border);
}
.brand a { font-size: 1.05rem; font-weight: 500; color: var(--text); }
.brand span {
    color: var(--text-soft); font-size: 0.68rem; font-weight: 500;
    text-transform: uppercase; letter-spacing: 0.14em;
}

.sidebar-search {
    position: relative;
    margin: 0 var(--s2) var(--s3);
}
.sidebar-search .icon {
    position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
    color: var(--text-soft); font-size: 0.9rem; pointer-events: none;
}
.sidebar-search input {
    width: 100%; padding: 8px 10px 8px 30px; font-size: 0.82rem;
    background: var(--bg-input); border: 1px solid var(--border); border-radius: var(--radius-md); color: var(--text);
}

.sidebar-nav { display: flex; flex-direction: column; gap: 1px; padding-top: var(--s3); }

.nav-section-label {
    font-size: 10.5px; font-weight: 700; color: var(--text-soft);
    text-transform: uppercase; letter-spacing: 0.9px;
    padding: 0 var(--s3); margin: var(--s4) 0 var(--s1);
    pointer-events: none;
}

.nav-item {
    display: flex; align-items: center; gap: 10px; min-height: 48px;
    color: var(--text-muted); padding: 9px var(--s4); border-radius: var(--radius-full);
    font-weight: 500; font-size: 1rem; cursor: pointer;
    text-decoration: none;
    transition: background 0.16s var(--ease), color 0.16s var(--ease);
}
.nav-item:hover { background: var(--surface-2); color: var(--text); }
.nav-badge {
    margin-left: auto; background: var(--accent-red); color: #fff;
    font-size: 0.7rem; font-weight: 700; line-height: 1; border-radius: 999px;
    padding: 3px 6px; min-width: 18px; text-align: center;
}
/* Inset bar rather than a real border, so the active item doesn't shift
   layout by its own border-width - same technique already used for the
   low-stock/out-of-stock inventory row accents below. */
.nav-item.active { background: var(--color-primary-subtle); color: var(--color-primary); }
.nav-item.nav-locked { color: var(--text-soft); opacity: 0.45; cursor: not-allowed; pointer-events: none; }
.nav-item.nav-locked:hover { background: none; }
.nav-icon { font-size: 17px; line-height: 1; flex-shrink: 0; width: 18px; text-align: center; }

/* ---- paywall: full-screen blurred prompt shown on Home whenever an
   authenticated account has no access (expired trial, canceled, etc.) ---- */
.paywall-backdrop {
    position: fixed; inset: 0; z-index: 600;
    background: rgba(0,0,0,0.6); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
    display: flex; align-items: center; justify-content: center; padding: var(--s5);
}
.paywall-modal {
    background: var(--surface); border: 1px solid var(--border-strong);
    border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
    width: 100%; max-width: 460px; padding: var(--s7) var(--s6);
    text-align: center;
}
.paywall-kicker { color: var(--accent-red); font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: var(--s2); }
.paywall-modal h2 { font-size: 1.4rem; font-weight: 800; margin-bottom: var(--s2); }
.paywall-lead { color: var(--text-muted); font-size: 0.92rem; line-height: 1.5; margin-bottom: var(--s6); }
.paywall-plans { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--s3); margin-bottom: var(--s5); text-align: left; }
.paywall-plan {
    display: flex; flex-direction: column; gap: 6px; position: relative;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-md);
    padding: var(--s4);
}
.paywall-plan-featured { border-color: var(--accent-green); }
.paywall-plan-name { font-size: 0.8rem; font-weight: 600; color: var(--text-muted); }
.paywall-plan-price { font-size: 1.5rem; font-weight: 800; color: var(--text); }
.paywall-plan-price small { font-size: 0.85rem; font-weight: 500; color: var(--text-muted); }
.paywall-plan-note { font-size: 0.76rem; color: var(--text-soft); margin-bottom: 4px; }
.paywall-plan .btn { margin-top: 6px; width: 100%; }
.paywall-save-badge {
    position: absolute; top: -10px; right: 12px;
    background: var(--accent-green); color: #06301c;
    font-size: 0.68rem; font-weight: 700; padding: 2px 8px; border-radius: var(--radius-full);
}
.paywall-signout { color: var(--text-muted); font-size: 0.86rem; text-decoration: none; }
.paywall-signout:hover { color: var(--text); text-decoration: underline; }
@media (max-width: 480px) {
    .paywall-plans { grid-template-columns: 1fr; }
    .paywall-modal { padding: var(--s6) var(--s4); }
}

/* ---- sidebar bottom: billing + profile ---- */
.sidebar-bottom {
    margin-top: auto; padding-top: var(--s4);
    border-top: 1px solid var(--border);
    display: flex; flex-direction: column; gap: var(--s2);
}
.billing-chip {
    display: inline-flex; justify-content: center; align-items: center; width: 100%;
    padding: 7px var(--s3); border-radius: var(--radius-sm);
    font-size: 0.77rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    color: var(--text-muted); border: 1px solid var(--border);
    background: var(--surface-2); text-decoration: none;
    transition: border-color 0.16s var(--ease), color 0.16s var(--ease);
}
.billing-chip.active-plan { border-color: rgba(45,169,111,0.35); color: var(--accent-green); }
.billing-chip.expired-plan { border-color: rgba(219,67,74,0.35); color: var(--accent-red); }

.sidebar-profile {
    display: flex; align-items: center; gap: var(--s3);
    padding: 10px var(--s3); border-radius: var(--radius-sm);
    cursor: pointer; text-decoration: none;
    transition: background 0.16s var(--ease);
}
.sidebar-profile:hover { background: var(--surface-2); }
.sidebar-profile.active { background: var(--color-primary-subtle); }
.sidebar-avatar {
    width: 32px; height: 32px; border-radius: 50%;
    background: var(--color-primary-subtle); color: var(--accent);
    display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 13px; flex-shrink: 0; text-transform: uppercase;
}
.sidebar-profile-info {
    flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px;
}
.sidebar-profile-name {
    font-size: 0.87rem; font-weight: 600; color: var(--text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sidebar-profile-role { font-size: 0.74rem; color: var(--text-soft); font-weight: 500; }
.sidebar-profile-arrow { color: var(--text-soft); font-size: 14px; flex-shrink: 0; }

.page-shell { min-width: 0; }
.main-content {
    max-width: var(--container); margin: 0 auto;
    padding: var(--s7) var(--s7) var(--s8);
}
/* The floating help button sits fixed over the bottom-right of the viewport
   (see .help-fab) on desktop/tablet - without this, scrolling a long list
   or panel all the way down leaves its last row's price or action sitting
   directly underneath it. Extra bottom padding on the scroll container
   guarantees clear space below the last row instead. */
@media (min-width: 768.02px) {
    .main-content { padding-bottom: calc(var(--s8) + 64px); }
}

/* mobile top bar (hidden on desktop) */
.mobile-topbar { display: none; }
.sidebar-scrim { display: none; }

/* ----------------------------------------------------------------- topbar */
.topbar {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: var(--s4); margin-bottom: var(--s6); flex-wrap: wrap;
}
.topbar-title { font-size: clamp(1.5rem, 3.4vw, 2.4rem); font-weight: 400; letter-spacing: -0.015em; line-height: 1.1; }
.eyebrow { color: var(--text-soft); font-size: 0.74rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; margin-bottom: var(--s1); }
/* .topbar-chip's own recipe now lives in the shared .status/.status-chip
   rule above - this used to be a second, slightly different definition of
   the same pill (different padding/font-size/weight), which would have
   silently won over the consolidated one at equal specificity by coming
   later in the file. */
.page-actions { display: flex; gap: var(--s2); align-items: center; flex-wrap: wrap; }

/* ----------------------------------------------------------------- page header */
.page-header {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: var(--space-6); flex-wrap: wrap; gap: var(--space-3);
}
.page-subtitle { font-size: var(--font-size-sm); color: var(--color-text-muted); margin-top: 2px; }

/* ----------------------------------------------------------------- cards */
.card { background: var(--color-surface); border-radius: var(--radius-lg); padding: 22px 24px; }
.card-sm { padding: var(--space-4); border-radius: var(--radius-md); }
.card-hover:hover { background: var(--color-surface-2); cursor: pointer; }

.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr)); gap: var(--s4); margin-bottom: var(--s6); }
.stat-card, .panel, .list-card, .action-card, .highlight-card {
    background: var(--surface); border-radius: var(--radius-card);
}
.stat-card { padding: 22px 24px; transition: background 0.16s var(--ease), transform 0.16s var(--ease); }
.stat-card:hover { background: var(--surface-2); }
.stat-label { color: var(--text-soft); font-size: 0.78rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: var(--s2); }
.stat-value { font-size: clamp(1.5rem, 3.5vw, 1.875rem); font-weight: 400; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }

.panel { padding: 22px 24px; margin-bottom: var(--s6); }
.panel-header { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--s4); margin-bottom: var(--s5); flex-wrap: wrap; }
.panel-kicker { color: var(--text-soft); font-size: 0.72rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.09em; margin-bottom: var(--s1); }
.panel h3 { font-size: 1.15rem; }
.narrow-panel { max-width: 720px; }
.stack-panel { display: flex; flex-direction: column; gap: var(--s5); }

/* ------------------------------------------------------------- kpi cards */
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--s4); margin-bottom: var(--s6); }
.kpi-card {
    background: var(--surface); border-radius: var(--radius-card);
    padding: 22px 24px; transition: background 0.16s var(--ease);
}
.kpi-card:hover { background: var(--surface-2); }
.kpi-card.clickable { cursor: pointer; }
.kpi-card-top { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: var(--s2); }
.kpi-icon { color: var(--text-soft); font-size: 1.15rem; }
.kpi-change { display: inline-flex; align-items: center; gap: 4px; font-size: 0.82rem; color: var(--text-muted); margin-top: var(--s2); }
.kpi-change.up { color: var(--accent-green); }
.kpi-change.down { color: var(--accent-red); }

/* ------------------------------------------------------------- chart cards */
.chart-card {
    background: var(--surface); border-radius: var(--radius-card);
    padding: 22px 24px;
}
.chart-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4); margin-bottom: var(--s6); }
.donut-legend { display: flex; flex-direction: column; gap: var(--s2); margin-top: var(--s4); }
.donut-legend-item { display: flex; align-items: center; gap: var(--s2); font-size: 0.9rem; }
.donut-legend-item strong { margin-left: auto; margin-right: var(--s2); }
.donut-dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }

/* ------------------------------------------------------------- funnel */
.funnel-stack { display: flex; flex-direction: column; gap: 2px; }
.funnel-row { display: flex; flex-direction: column; gap: 6px; padding: var(--s3) 0; }
.funnel-bar-wrap { width: 100%; background: var(--surface-2); border-radius: var(--radius-sm); overflow: hidden; height: 14px; }
.funnel-bar { height: 100%; border-radius: var(--radius-sm); transition: width 0.3s var(--ease); }
.funnel-meta { display: flex; justify-content: space-between; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.funnel-label { font-weight: 600; font-size: 0.92rem; }
.funnel-figures { color: var(--text-muted); font-size: 0.88rem; font-variant-numeric: tabular-nums; }
.funnel-conversion {
    text-align: center; font-size: 0.8rem; color: var(--text-soft);
    padding: 2px 0 var(--s2);
}
.funnel-conv-pct { font-weight: 700; color: var(--accent); }

/* ------------------------------------------------------------- profit bar */
.profit-bar-wrap { width: 100%; }
.profit-bar {
    display: flex; width: 100%; height: 28px; border-radius: var(--radius-sm);
    overflow: hidden; background: var(--surface-2);
}
.profit-segment { height: 100%; flex: none; transition: width 0.3s var(--ease); }
.profit-segment-green { background: #2DA96F; }
.profit-segment-amber { background: #EC9E18; }
.profit-segment-red { background: #DB434A; }
.profit-segment-neutral { background: var(--text-muted); }
.profit-legend { display: flex; flex-wrap: wrap; gap: var(--s4); margin-top: var(--s4); font-size: 0.86rem; color: var(--text-muted); }
.profit-legend span { display: inline-flex; align-items: center; gap: 6px; }
.profit-legend .donut-dot { border-radius: 50%; }
.profit-summary { margin-top: var(--s4); font-size: 0.95rem; color: var(--text-muted); }
.profit-text-green { color: #2DA96F; font-weight: 600; }
.profit-text-amber { color: #EC9E18; font-weight: 600; }
.profit-text-red { color: #DB434A; font-weight: 600; }
.profit-text-neutral { color: var(--text-muted); font-weight: 600; }

.content-grid { display: grid; grid-template-columns: 1.6fr 1fr; gap: clamp(var(--s3), 3vw, var(--s5)); margin-bottom: var(--s6); }
.two-column-wide { grid-template-columns: 1.3fr 1fr; }

.stack-list, .mini-stats { display: grid; gap: var(--s3); }
.list-card {
    display: flex; justify-content: space-between; align-items: center; gap: var(--s4);
    padding: var(--s4); background: var(--surface-2); border-radius: var(--radius-sm);
}
.list-card.vertical { flex-direction: column; align-items: flex-start; }
.list-card h4 { font-size: 0.96rem; margin-bottom: 2px; }
.list-card p, .detail-subtitle, .insight-copy p { color: var(--text-muted); font-size: 0.9rem; }
.list-card span { color: var(--text-muted); font-size: 0.9rem; }
.list-card strong { font-weight: 600; font-variant-numeric: tabular-nums; }

/* ----------------------------------------------------------------- tables */
/* .table is a name-compatible alias of .data-table — both render identically */
.table-wrap { border-radius: var(--radius-lg); overflow-x: auto; }
.data-table, .table { width: 100%; border-collapse: collapse; min-width: 560px; }
.data-table thead th, .data-table th, .table th {
    text-align: left; padding: var(--space-3) var(--space-4); background: var(--surface);
    color: var(--color-text-muted); font-size: var(--font-size-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em;
    border-bottom: 1px solid var(--border); white-space: nowrap;
}
.data-table tbody td, .table td { padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--border); font-size: var(--font-size-sm); vertical-align: middle; }
.data-table tbody tr:last-child td, .table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr, .table tbody tr { transition: background 0.14s var(--ease); }
.data-table tbody tr.clickable { cursor: pointer; }
.data-table tbody tr.clickable:hover, .table tbody tr:hover td { background: var(--surface-2); }
.data-table td strong, .table td strong { font-weight: 600; }
/* Money cells in editable tables (the invoice/quote line-items grid) must
   never break a number across lines — let the table scroll horizontally
   instead, which is safe now that .table-wrap stays visible on mobile. */
.line-total, .data-table td.num, .table td.num { white-space: nowrap; font-variant-numeric: tabular-nums; }
/* The line-items editor (quote/invoice wizard) has 7 columns with real
   minimum widths — forcing it to 100% of a narrow container squeezes Qty/
   Unit/Price down to slivers. Let it take its natural width instead and
   scroll horizontally (.table-wrap already supports this). */
#itemsTable { width: auto; min-width: 800px; }

/* clickable rows (generic) */
[data-href] { cursor: pointer; }
.data-table tr.low td:first-child { box-shadow: inset 3px 0 0 var(--warning); }
.data-table tr.low { background: color-mix(in srgb, var(--warning) 8%, transparent); }
.data-table tr.out-of-stock td:first-child { box-shadow: inset 3px 0 0 var(--accent-red); }
.data-table tr.out-of-stock { background: color-mix(in srgb, var(--accent-red) 8%, transparent); }

/* ----------------------------------------------------------------- buttons */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
    padding: var(--space-3) var(--space-5); border-radius: var(--radius-full); border: 1px solid transparent;
    font-weight: 600; font-size: var(--font-size-sm); min-height: 48px; white-space: nowrap;
    cursor: pointer; text-decoration: none; text-transform: lowercase; letter-spacing: 0.01em;
    transition: background 0.15s ease, border-color 0.15s ease, transform 0.12s ease, box-shadow 0.15s ease, filter 0.15s ease;
}
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; pointer-events: none; }
.btn-primary { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }
.btn-primary:hover { background: var(--color-primary-hover); border-color: var(--color-primary-hover); transform: translateY(-1px); box-shadow: var(--shadow-primary); }
.btn-secondary { background: var(--color-surface-2); border-color: var(--color-border-strong); color: var(--color-text); }
.btn-secondary:hover { background: var(--color-surface-3); border-color: var(--color-border-strong); }
.btn-ghost { background: transparent; color: var(--color-text-muted); border-color: transparent; }
.btn-ghost:hover { background: var(--color-surface-2); color: var(--color-text); }
.btn-accent { background: var(--color-primary-subtle); color: var(--color-primary); border-color: var(--color-primary-border); }
.btn-accent:hover { background: color-mix(in srgb, var(--color-primary) 20%, transparent); }
.btn-danger { background: var(--color-danger-subtle); border-color: rgba(219, 67, 74, 0.25); color: var(--color-danger); }
.btn-danger:hover { background: var(--color-danger); border-color: var(--color-danger); color: #fff; }
.btn-sm, .btn-small { min-height: 40px; padding: var(--space-2) var(--space-3); font-size: var(--font-size-xs); }
.btn-lg { min-height: 52px; padding: var(--space-3) var(--space-6); font-size: var(--font-size-lg); }
.btn-icon { padding: var(--space-2); width: 44px; height: 44px; min-height: 44px; justify-content: center; }
.text-link {
    color: var(--color-primary); font-weight: 550; cursor: pointer;
    /* Neutralize native <button> chrome so this class looks identical whether
       it's applied to an <a> or a <button> — without this a <button
       class="text-link"> shows the browser's default grey button face. */
    background: none; border: none; padding: 0; font-family: inherit;
}
.text-link:hover { text-decoration: underline; }

/* ----------------------------------------------------------------- forms */
.form-grid { display: grid; gap: var(--s4); }
.form-grid.single-column { grid-template-columns: 1fr; }
.form-row { display: flex; gap: var(--s4); flex-wrap: wrap; }
.form-row > .form-group { flex: 1 1 180px; }
.form-group { display: flex; flex-direction: column; gap: var(--s2); }
.form-group label { font-size: 14px; font-weight: 600; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px; }
.form-label { display: block; font-size: var(--font-size-sm); font-weight: 500; color: var(--color-text-muted); margin-bottom: var(--space-1); }
.form-panel { max-width: 760px; }
.form-actions { display: flex; justify-content: flex-end; gap: var(--s3); flex-wrap: wrap; margin-top: var(--s2); }
.form-actions .btn { min-width: max-content; }

input, select, textarea, .input, .select, .textarea {
    width: 100%; min-height: 48px; padding: 12px var(--s3);
    background: var(--bg-input); color: var(--text-primary);
    font-family: var(--font-sans); font-size: var(--font-size-sm);
    border: 1px solid var(--border-strong); border-radius: var(--radius-sm); outline: none;
    transition: border-color 0.16s var(--ease), box-shadow 0.16s var(--ease);
}
input::placeholder, textarea::placeholder, .input::placeholder, .textarea::placeholder { color: var(--color-text-subtle); }
input:focus, select:focus, textarea:focus, .input:focus, .select:focus, .textarea:focus {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-primary-subtle);
}
textarea, .textarea { min-height: 96px; resize: vertical; }

/* no number spinners */
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
input[type=number] { -moz-appearance: textfield; appearance: textfield; }

input[type=checkbox], input[type=radio] { width: auto; min-height: 0; accent-color: var(--color-primary); }
.check-label { display: flex; align-items: center; gap: var(--s2); cursor: pointer; font-weight: 500; color: var(--text); }
.check-label input { width: auto; }

/* inline affix (currency / unit shown inside the field, greyed, on the right) */
.input-affix { position: relative; display: block; }
.input-affix > input { padding-right: 54px; }
.input-affix.affix-wide > input { padding-right: 68px; }
.input-affix > .affix {
    position: absolute; top: 1px; right: 1px; bottom: 1px; display: flex; align-items: center;
    padding: 0 var(--s3); color: var(--text-soft); font-size: 0.92rem; pointer-events: none;
    background: var(--surface-3); border-left: 1px solid var(--border); border-radius: 0 7px 7px 0;
}

/* toggle switch */
.switch { position: relative; display: inline-flex; align-items: center; gap: var(--s3); cursor: pointer; font-weight: 500; min-height: 48px; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch .track {
    width: 42px; height: 24px; border-radius: 999px; background: var(--surface-3);
    border: 1px solid var(--border-strong); position: relative; transition: background 0.18s var(--ease); flex: none;
}
.switch .track::after {
    content: ""; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%;
    background: #fff; transition: transform 0.18s var(--ease);
}
.switch input:checked + .track { background: var(--color-primary); border-color: var(--color-primary); }
.switch input:checked + .track::after { transform: translateX(18px); }
.switch input:focus-visible + .track { box-shadow: 0 0 0 3px var(--color-primary-subtle); }

/* ----------------------------------------------------------------- filters / search */
.filter-bar { display: flex; gap: var(--s2); align-items: center; flex-wrap: wrap; margin-bottom: var(--s4); }
/* Direct children only - the Inventory page nests a checkbox for its "Low
   stock only" toggle inside a .pipeline-pill label, which this rule used to
   match too (a plain descendant selector doesn't stop at the label). That
   stretched the checkbox itself to a 160-200px flex item, ballooning it
   into a huge oval that squeezed "Low stock only" into a cramped, wrapping
   sliver of text overlapping the Search button next to it. */
.filter-bar > input, .filter-bar > select { min-width: min(200px, 100%); flex: 1 1 160px; }
.filter-bar .btn, .filter-bar a.btn { flex-shrink: 0; }

/* ----------------------------------------------------------------- status / badges
   .status/.status-chip and .topbar-chip used to be two separately-tuned
   recipes for the same "small pill label" component (different font-size,
   different font-weight) - same shared recipe now, so a status pill and the
   topbar's trial-countdown chip read as one family. .badge stays a distinct,
   smaller tier for compact inline annotations (see below) rather than a
   third variant of the same thing. .billing-chip is left alone: it's a
   full-width sidebar block, not an inline label, so it isn't a duplicate of
   this family even though it reads similarly. */
.status, .status-chip, .topbar-chip {
    display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px; border-radius: var(--radius-full);
    font-size: 0.75rem; font-weight: 500; letter-spacing: 0.01em; white-space: nowrap;
    background: var(--surface-3); color: var(--text-muted);
}
/* Every other status pill uses a fixed, pre-tuned brand color, but "active"
   is the account's own customizable accent - which anyone can set to a
   warm/mid-tone color that, at full strength, has poor contrast against a
   dark surface tinted with that very same hue (this is what made "Active"
   read as barely-there muddy text in dark mode for at least one real
   account). Lightening it towards white guarantees legibility on dark
   backgrounds regardless of which color was picked; light mode already has
   good contrast with the accent at full strength, so it's left alone. */
.status-active { background: var(--color-primary-subtle); color: color-mix(in srgb, var(--color-primary) 55%, white); }
[data-theme="light"] .status-active { color: var(--color-primary); }
.status-paid, .status-accepted, .status-completed { background: var(--color-success-subtle); color: var(--color-success); }
.status-quotation, .status-draft, .status-sent, .status-viewed { background: var(--color-info-subtle); color: var(--color-info); border-color: rgba(62, 124, 224, 0.28); }
.status-cancelled, .status-rejected, .status-overdue { background: var(--color-danger-subtle); color: var(--color-danger); border-color: rgba(219, 67, 74, 0.25); }
.status-pending { background: var(--color-warning-subtle); color: var(--color-warning); border-color: rgba(236, 158, 24, 0.28); }

/* Compact inline annotation (e.g. "Today" next to a date) — deliberately a
   size down from the .status/.status-chip/.topbar-chip pill family above,
   not a fourth variant of it. Was font-size-xs (0.8125rem), actually LARGER
   than a full status pill's 0.78rem - backwards for something meant to read
   as a small aside. The border is derived from each modifier's own text
   color so every modifier gets one for free without five separate
   declarations. */
.badge {
    display: inline-flex; align-items: center; gap: 4px; padding: 2px var(--space-2);
    font-size: 0.72rem; font-weight: 600; border-radius: var(--radius-full); white-space: nowrap;
    border: 1px solid color-mix(in srgb, currentColor 28%, transparent);
}
.badge-success { background: var(--color-success-subtle); color: var(--color-success); }
.badge-warning { background: var(--color-warning-subtle); color: var(--color-warning); }
.badge-danger  { background: var(--color-danger-subtle); color: var(--color-danger); }
.badge-info    { background: var(--color-info-subtle); color: var(--color-info); }
.badge-neutral { background: var(--color-surface-3); color: var(--color-text-muted); }

/* ----------------------------------------------------------------- pipeline pills */
.pipeline-pills { display: flex; gap: var(--s2); flex-wrap: wrap; margin-bottom: var(--s4); }
.pipeline-pill {
    padding: 7px 16px; border-radius: var(--radius-full); font-size: 0.82rem; font-weight: 600;
    background: var(--surface-2); color: var(--text-muted); border: 1px solid var(--border);
    cursor: pointer; transition: background 0.15s var(--ease), color 0.15s var(--ease), border-color 0.15s var(--ease);
}
.pipeline-pill:hover { background: var(--surface-3); color: var(--text); }
.pipeline-pill.active { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }
.hidden { display: none !important; }

/* ----------------------------------------------------------------- misc */
.divider { border: none; border-top: 1px solid var(--border); margin: var(--s5) 0; }
.empty-state {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    text-align: center; padding: var(--space-8) var(--space-6); gap: var(--space-3);
    color: var(--color-text-muted);
}
.empty-state p { color: var(--color-text-muted); margin-bottom: var(--space-4); }
.empty-state-icon { display: block; font-size: 1.9rem; color: var(--color-text-subtle); margin: 0 auto; opacity: 0.7; }
.empty-state-title { font-size: var(--font-size-lg); font-weight: 700; color: var(--color-text); }
.empty-state-desc { font-size: var(--font-size-sm); color: var(--color-text-muted); max-width: 320px; margin: 0; }
.detail-hero { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--s4); margin-bottom: var(--s6); flex-wrap: wrap; }
.detail-title { font-size: clamp(1.2rem, 4vw, 1.7rem); font-weight: 400; letter-spacing: -0.015em; }
.detail-subtitle { margin-top: var(--s1); }
.detail-actions { display: flex; gap: var(--s2); align-items: center; flex-wrap: wrap; }
.subsection { padding-top: var(--s2); }

.deadline-row { display: flex; justify-content: space-between; align-items: center; gap: var(--s4); padding: var(--s4); border-radius: var(--radius-sm); background: var(--surface-2); border: 1px solid var(--border); }
.deadline-row.overdue { border-color: color-mix(in srgb, var(--danger) 40%, transparent); }
.deadline-row.soon { border-color: color-mix(in srgb, var(--warning) 38%, transparent); }

.timeframe-toggle { display: inline-flex; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 3px; gap: 2px; }
.timeframe-toggle a { padding: 6px 14px; border-radius: 7px; color: var(--text-muted); font-size: 0.85rem; font-weight: 500; transition: 0.14s var(--ease); }
.timeframe-toggle a:hover { color: var(--text); }
.timeframe-toggle a.active { background: var(--color-primary); color: #fff; }

.chart-box { position: relative; height: clamp(180px, 38vw, 320px); }

/* flash messages */
.flash-messages { display: grid; gap: var(--s2); margin-bottom: var(--s5); }

.demo-banner {
    display: flex; align-items: center; justify-content: space-between; gap: var(--s4);
    flex-wrap: wrap; padding: var(--s3) var(--s5); margin-bottom: var(--s5);
    border-radius: var(--radius-sm); font-size: 0.9rem; font-weight: 500;
    background: color-mix(in srgb, var(--accent) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
    color: var(--text);
}
.demo-banner-invite { background: color-mix(in srgb, var(--accent-green) 12%, transparent); border-color: color-mix(in srgb, var(--accent-green) 28%, transparent); }
.demo-banner span { display: flex; align-items: center; gap: var(--s2); }
.flash { padding: 12px var(--s4); border-radius: var(--radius-sm); font-size: 0.9rem; border: 1px solid var(--border); }
.flash-success { background: color-mix(in srgb, var(--success) 14%, transparent); color: #b7ecd1; border-color: color-mix(in srgb, var(--success) 30%, transparent); }
.flash-error { background: color-mix(in srgb, var(--danger) 14%, transparent); color: #f5b9b9; border-color: color-mix(in srgb, var(--danger) 30%, transparent); }
.flash-info { background: color-mix(in srgb, var(--accent) 14%, transparent); color: color-mix(in srgb, var(--accent) 55%, #fff); border-color: color-mix(in srgb, var(--accent) 30%, transparent); }
.flash-warning { background: color-mix(in srgb, var(--warning) 14%, transparent); color: #ecd29a; border-color: color-mix(in srgb, var(--warning) 30%, transparent); }

/* tabs — clean underline bar, scrolls horizontally on small screens */
.tabs {
    display: flex; gap: var(--s1); margin-bottom: var(--s6);
    border-bottom: 1px solid var(--border);
    overflow-x: auto; scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab-btn {
    background: transparent; border: none; color: var(--text-muted);
    padding: 12px var(--s4); font-weight: 500; font-size: 0.92rem; cursor: pointer;
    border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap; flex: none;
    transition: color 0.16s var(--ease), border-color 0.16s var(--ease);
}
.tab-btn:hover { color: var(--text); }
.tab-btn.active { color: var(--text); border-bottom-color: var(--accent); }
.tab-panel { display: none; }
.tab-panel.active { display: block; animation: fade 0.2s var(--ease); }
@keyframes fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* pricing badges */
.save-badge { position: absolute; top: -11px; right: -8px; background: var(--success); color: #06210f; font-weight: 700; font-size: 0.7rem; letter-spacing: 0.03em; text-transform: uppercase; padding: 5px 11px; border-radius: 999px; box-shadow: var(--shadow); white-space: nowrap; z-index: 2; }
.plan-card { position: relative; }

/* collapsible (native details) */
.collapsible > summary { cursor: pointer; list-style: none; }
.collapsible > summary::-webkit-details-marker { display: none; }

/* calendar */
.calendar { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--s1); }
.cal-head { text-align: center; color: var(--text-soft); font-size: 0.72rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; padding: var(--s2) 0; }
.cal-cell { min-height: 92px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: var(--s2); display: flex; flex-direction: column; gap: 4px; }
.cal-cell.empty { background: transparent; border-color: transparent; }
.cal-cell.today { border-color: var(--accent); }
.cal-date { font-size: 0.78rem; color: var(--text-soft); font-weight: 600; }
.cal-cell.today .cal-date { color: var(--accent); }
.cal-event { font-size: 0.74rem; padding: 3px 6px; border-radius: 6px; background: color-mix(in srgb, var(--accent) 18%, transparent); color: color-mix(in srgb, var(--accent) 55%, #fff); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; }
.cal-event.overdue { background: color-mix(in srgb, var(--danger) 18%, transparent); color: #f3a5a5; }
.cal-event.soon { background: color-mix(in srgb, var(--warning) 18%, transparent); color: #eccd8a; }
.cal-cell.has-jobs { cursor: pointer; }
.cal-cell.has-jobs:hover { border-color: var(--accent); }
.cal-dots { display: flex; gap: 3px; margin-top: 2px; }
.cal-dot { width: 7px; height: 7px; border-radius: 999px; background: var(--accent); }
.cal-dot-start { background: var(--accent); }
.cal-dot-completed { background: var(--success); }
.cal-dot-milestone { background: var(--color-warning); }
.cal-dot-event { background: var(--color-primary); }
.cal-legend { display: flex; gap: var(--s4); margin-bottom: var(--s3); font-size: 0.78rem; color: var(--text-soft); }
.cal-legend span { display: inline-flex; align-items: center; gap: 6px; }
.cal-legend .cal-dot { margin-top: 0; }

/* Compact read-only variant for the dashboard's "This month" widget. */
.mini-calendar .cal-cell { min-height: 40px; padding: 4px; gap: 2px; }
.mini-calendar .cal-date { font-size: 0.7rem; }
.mini-calendar .cal-head { font-size: 0.64rem; padding: var(--s1) 0; }

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

/* ----------------------------------------------------------------- danger zone */
.danger-zone, .page-danger-zone {
    background: color-mix(in srgb, var(--danger) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--danger) 32%, transparent);
    border-radius: var(--radius-md);
    padding: var(--s5) var(--s6);
    margin-bottom: var(--s6);
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--s4);
    flex-wrap: wrap;
}
.danger-label {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--danger);
    margin-bottom: var(--s1);
}
.danger-text {
    color: var(--text-muted);
    font-size: 0.88rem;
    max-width: 520px;
    line-height: 1.5;
}

/* ----------------------------------------------------------------- item cards */
.item-card {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--surface);
    transition: border-color 0.16s var(--ease);
}
.item-card:hover { border-color: var(--border-strong); }
.item-card-top {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--s4);
    padding: var(--s4) var(--s5);
    background: var(--surface-2);
}
.item-card-top h4 { font-size: 0.98rem; margin-bottom: 3px; }
.item-card-top p { color: var(--text-muted); font-size: 0.87rem; }
.item-card > .collapsible { padding: var(--s3) var(--s5) var(--s4); border-top: 1px solid var(--border); }
.item-card > .subsection { padding: var(--s3) var(--s5); border-top: 1px solid var(--border); }
.item-card-footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    padding: var(--s3) var(--s5);
    border-top: 1px solid color-mix(in srgb, var(--danger) 20%, transparent);
    background: color-mix(in srgb, var(--danger) 4%, transparent);
}
.list-meta { display: flex; gap: var(--s2); align-items: center; flex-wrap: wrap; flex-shrink: 0; margin-top: var(--s1); }
.status-chip.strong {
    background: color-mix(in srgb, var(--accent) 14%, transparent);
    color: color-mix(in srgb, var(--accent) 60%, #fff);
    border-color: color-mix(in srgb, var(--accent) 28%, transparent);
    font-weight: 700;
}

/* ----------------------------------------------------------------- compact stat grid */
.compact-grid { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--s3); margin-bottom: var(--s5); }
.compact-grid .stat-value { font-size: 1.15rem; }

/* ----------------------------------------------------------------- project list (cards) */
/* Each project is its own separated, rounded card (a real "bubble") rather
   than a row in a shared flat block - a row's hover used to be a plain
   rectangle sharing the list's own corners, which read as only part of the
   "bubble" lighting up. overflow:hidden clips the accent bar to match the
   card's own rounded corners. */
.project-list { display: flex; flex-direction: column; gap: var(--s3); }
.project-card {
    display: flex;
    align-items: stretch;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background 0.16s var(--ease), border-color 0.16s var(--ease);
    text-decoration: none;
    color: inherit;
    overflow: hidden;
}
.project-card:hover { background: var(--surface-2); border-color: var(--border-strong); }
.project-card-accent { width: 4px; flex-shrink: 0; }
.project-card-accent.status-active { background: var(--accent); }         /* indigo */
.project-card-accent.status-quotation { background: var(--accent-blue); }  /* sky blue */
.project-card-accent.status-completed { background: var(--accent-green); } /* emerald */
.project-card-accent.status-cancelled { background: var(--danger); }       /* red */
/* The colored accent bar needs its own clear margin from the title/meta
   text next to it - it sat flush against the words with no breathing
   room. */
.project-card-inner { display: flex; align-items: center; gap: var(--s4); padding: var(--s4) var(--s5); flex: 1; min-width: 0; }
.project-card-body { flex: 1; min-width: 0; }
.project-card-title { font-weight: 500; font-size: 0.97rem; margin-bottom: 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.project-card-meta { color: var(--text-muted); font-size: 0.83rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.project-card-aside { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; flex-shrink: 0; }
.project-total { font-weight: 600; font-size: 0.93rem; font-variant-numeric: tabular-nums; }
.project-deadline { font-size: 0.81rem; color: var(--text-soft); }
.project-deadline.overdue { color: var(--danger); font-weight: 600; }
.project-deadline.soon { color: var(--warning); font-weight: 600; }

/* ----------------------------------------------------------------- collapsible — button look */
.collapsible > summary { cursor: pointer; list-style: none; }
.collapsible > summary::-webkit-details-marker { display: none; }
details.collapsible > summary {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px var(--s3);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    border: 1px solid var(--border);
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--text-muted);
    transition: background 0.14s var(--ease), color 0.14s var(--ease), border-color 0.14s var(--ease);
}
details.collapsible > summary:hover { background: var(--surface-3); border-color: var(--border-strong); color: var(--text); }
details.collapsible[open] > summary {
    color: var(--text);
    border-color: color-mix(in srgb, var(--accent) 50%, transparent);
    background: color-mix(in srgb, var(--accent) 10%, transparent);
}
details.collapsible > summary::before { content: "▸"; font-size: 0.7rem; transition: transform 0.18s var(--ease); }
details.collapsible[open] > summary::before { transform: rotate(90deg); }

/* ----------------------------------------------------------------- vat note */
.vat-note { font-size: 0.82rem; color: var(--text-soft); margin-top: var(--s1); }

/* ============================================================ responsive */
@media (max-width: 1024px) {
    /* auto-fit handles column count; only collapse two-column layouts */
    .content-grid, .two-column-wide, .chart-grid-2 { grid-template-columns: 1fr; }
    .nav-item { min-height: 44px; display: flex; align-items: center; }
}

/* ---- tablet (768px–1024px): sidebar collapses to an icon-only rail ---- */
@media (min-width: 768.02px) and (max-width: 1024px) {
    .app-shell { grid-template-columns: var(--sidebar-collapsed) 1fr; }
    .sidebar { width: var(--sidebar-collapsed); padding: var(--s4) var(--s2); align-items: center; }
    .brand { align-items: center; padding: var(--s2) 0 var(--s5); }
    .brand span, .nav-section-label, .nav-item span, .sidebar-profile-info,
    .sidebar-profile-arrow, .billing-chip { display: none; }
    .nav-item { justify-content: center; padding: 9px; }
    .sidebar-profile { justify-content: center; padding: 10px; }
    .sidebar-bottom { align-items: center; }
    .sidebar-search { display: none; }
}

@media (max-width: 768px) {
    .app-shell { grid-template-columns: 1fr; }
    .mobile-topbar {
        display: grid; grid-template-columns: 34px 1fr 34px; align-items: center; gap: var(--s2);
        position: sticky; top: 0; z-index: 30;
        padding: var(--s3) var(--s4); background: var(--bg-sidebar); border-bottom: 1px solid var(--border);
        padding-top: calc(var(--s3) + env(safe-area-inset-top));
        padding-left: calc(var(--s4) + env(safe-area-inset-left));
        padding-right: calc(var(--s4) + env(safe-area-inset-right));
    }
    .mobile-topbar .brand-name {
        grid-column: 2; font-weight: 500; font-size: 1.05rem; text-align: center;
        min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .mobile-topbar .notif-bell-wrap { grid-column: 3; justify-self: end; }
    .mobile-topbar .mobile-search-toggle { grid-column: 1; justify-self: start; }
    .mobile-topbar .notif-dropdown { right: -34px; width: min(320px, 90vw); }
    .mobile-search-bar {
        display: none;
        grid-column: 1 / -1;
        margin-top: var(--s3);
    }
    .mobile-topbar.search-open .mobile-search-bar { display: block; }
    .sidebar {
        position: fixed; inset: 0 auto 0 0; width: 280px; max-width: 84vw;
        transform: translateX(-100%); transition: transform 0.24s var(--ease); box-shadow: var(--shadow-lg);
    }
    body.nav-open .sidebar { transform: translateX(0); }
    body.nav-open .sidebar-scrim { display: block; position: fixed; inset: 0; background: rgba(0,0,0,0.55); z-index: 35; }
    .main-content {
        padding: var(--s5) var(--s4) calc(var(--s7) + env(safe-area-inset-bottom));
        padding-left: max(var(--s4), env(safe-area-inset-left));
        padding-right: max(var(--s4), env(safe-area-inset-right));
    }
    /* stack topbar title + actions on mobile */
    .topbar { gap: var(--s3); }
    .page-actions { flex-wrap: wrap; }
    .kpi-grid { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
}

@media (max-width: 560px) {
    body { font-size: 15px; }
    .main-content { padding: var(--s4) var(--s4) var(--s7); }
    .stats-grid { gap: var(--s3); }
    .kpi-grid { gap: var(--s3); }
    .chart-card { padding: var(--s4); }
    .form-row { flex-direction: column; gap: var(--s3); }
    .panel { padding: var(--s4); }
    .page-actions { width: 100%; }
    .cal-cell { min-height: 64px; }
    /* stretch action buttons full-width on small screens */
    .form-actions { justify-content: stretch; }
    .form-actions .btn { flex: 1 1 auto; text-align: center; justify-content: center; }
    /* project card: stack aside below title on narrow screens */
    .project-card-inner { flex-wrap: wrap; gap: var(--s3); }
    .project-card-aside { flex-direction: row; flex-wrap: wrap; width: 100%; align-items: center; gap: var(--s2); }
}

@media (max-width: 420px) {
    /* very small phones: 320px–420px */
    .panel { padding: var(--s3); }
    .topbar { flex-direction: column; align-items: flex-start; }
    .topbar .page-actions { width: 100%; }
    .topbar .page-actions .btn { flex: 1 1 auto; text-align: center; justify-content: center; }
    .detail-hero { flex-direction: column; }
    .detail-actions { width: 100%; justify-content: flex-start; }
    .item-card-top { flex-direction: column; gap: var(--s2); }
    .list-meta { margin-top: 0; }
    .danger-zone, .page-danger-zone { flex-direction: column; align-items: flex-start; }
    .danger-zone .btn, .page-danger-zone .btn { width: 100%; }
    .panel-header { flex-direction: column; gap: var(--s2); }
    .panel-header .btn, .panel-header a.btn { align-self: flex-start; }
    .tabs { gap: 0; }
    .tab-btn { padding: 10px var(--s3); font-size: 0.83rem; }
}

/* ============================================================================
   Ring / donut progress charts — standalone, no card background
   ============================================================================ */
.ring-charts-row {
    display: flex;
    gap: 48px;
    margin-bottom: var(--s7);
    justify-content: center;
    flex-wrap: wrap;
    padding: var(--s5) 0 var(--s4);
    border-bottom: 1px solid var(--border);
}
.ring-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    /* standalone — no card background or border */
}
.ring-wrap {
    position: relative;
    width: 124px;
    height: 124px;
    flex-shrink: 0;
}
.ring-wrap svg {
    width: 124px;
    height: 124px;
    display: block;
    overflow: visible; /* allow glow to bleed outside bounds */
}
.ring-value {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 26px;
    font-weight: 700;
    color: var(--text);
    white-space: nowrap;
    letter-spacing: -0.04em;
    font-variant-numeric: tabular-nums;
}
.ring-sublabel {
    display: block;
    font-size: 11px;
    font-weight: 500;
    color: var(--text-soft);
    text-align: center;
    letter-spacing: 0.2px;
    margin-top: 1px;
}
.ring-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-muted);
    text-align: center;
    letter-spacing: 0.2px;
    line-height: 1.4;
}

/* ============================================================================
   Typography — Bevel hierarchy
   ============================================================================ */
.page-title {
    font-size: clamp(1.5rem, 3.4vw, 2.4rem);
    font-weight: 400;
    letter-spacing: -0.015em;
    line-height: 1.1;
    color: var(--color-text);
}
.section-header {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.caption {
    font-size: 12px;
    color: var(--text-muted);
}

/* ============================================================================
   Bottom navigation bar — mobile only
   ============================================================================ */
.bottom-nav { display: none; }

@media (max-width: 768px) {
    .bottom-nav {
        display: flex;
        position: fixed;
        left: 12px;
        right: 12px;
        bottom: calc(12px + env(safe-area-inset-bottom));
        width: auto;
        background: color-mix(in srgb, var(--surface) 86%, transparent);
        backdrop-filter: blur(20px);
        -webkit-backdrop-filter: blur(20px);
        border: 1px solid var(--border-strong);
        border-radius: 22px;
        box-shadow: var(--shadow-lg);
        z-index: 50;
        padding: 6px;
        gap: 2px;
    }
    .bottom-nav-item {
        position: relative;
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 3px;
        padding: 8px 4px;
        color: var(--color-text-subtle);
        font-size: 10px;
        font-weight: 600;
        text-decoration: none;
        text-transform: uppercase;
        letter-spacing: 0.3px;
        transition: color 0.16s var(--ease), background 0.16s var(--ease), transform 0.1s var(--ease);
        min-height: 52px;
        border-radius: 16px;
        background: none;
        border: none;
        font-family: inherit;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
    }
    .bottom-nav-item.active { color: var(--color-primary); background: var(--color-primary-subtle); }
    .bottom-nav-item:hover { color: var(--text-muted); }
    .bottom-nav-item.active:hover { color: var(--color-primary); }
    .bottom-nav-item:active { transform: scale(0.94); }
    .bottom-nav-item .icon { font-size: 22px; line-height: 1; }
    .bottom-nav-item.active::after {
        content: ""; position: absolute; bottom: 4px; left: 50%; transform: translateX(-50%);
        width: 4px; height: 4px; border-radius: 50%; background: var(--color-primary);
    }
    .bottom-nav-badge {
        position: absolute; top: 2px; right: calc(50% - 20px);
        margin-left: 0; padding: 1px 5px; font-size: 9px;
    }
    /* push content above the floating bottom nav */
    .main-content {
        padding-bottom: calc(92px + env(safe-area-inset-bottom)) !important;
    }
    /* ring charts: scale down on mobile */
    .ring-charts-row { gap: 28px; padding: var(--s4) 0; }
    .ring-wrap { width: 100px; height: 100px; }
    .ring-wrap svg { width: 100px; height: 100px; }
    .ring-value { font-size: 21px; }
    .ring-label { font-size: 12px; }
    /* glance row mobile */
    .glance-row { gap: 20px; }
    .ring-wrap-sm { width: 90px; height: 90px; }
    .ring-wrap-sm svg { width: 90px; height: 90px; }
}

/* ============================================================================
   Glance stats row (ring + key numbers side by side)
   ============================================================================ */
.glance-row {
    display: flex;
    align-items: center;
    gap: 32px;
    margin-bottom: 20px;
    padding: 20px 24px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
}
.ring-wrap-sm {
    width: 110px;
    height: 110px;
    flex-shrink: 0;
}
.ring-wrap-sm svg {
    width: 110px;
    height: 110px;
}
.glance-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 12px 32px;
    flex: 1;
}
.glance-stat {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.glance-stat strong {
    font-size: 18px;
    font-weight: 700;
    color: var(--text);
    letter-spacing: -0.02em;
}

/* ============================================================================
   Receipt thumbnail
   ============================================================================ */
.receipt-thumb {
    width: 44px;
    height: 44px;
    object-fit: cover;
    border-radius: 6px;
    border: 1px solid var(--border);
    vertical-align: middle;
    cursor: pointer;
    transition: opacity 0.15s;
}
.receipt-thumb:hover { opacity: 0.8; }

/* ============================================================================
   Export dropdown
   ============================================================================ */
.export-dropdown {
    position: relative;
}
.export-menu {
    display: none;
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    background: var(--surface-2);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    min-width: 160px;
    z-index: 100;
    overflow: hidden;
    box-shadow: var(--shadow);
}
.export-menu.open { display: block; }
.export-menu a {
    display: block;
    padding: 10px 16px;
    font-size: 13.5px;
    color: var(--text);
    text-decoration: none;
    transition: background 0.12s;
}
.export-menu a:hover { background: var(--surface-3); }

/* ============================================================================
   Notification bell
   ============================================================================ */
.theme-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px; border-radius: 999px; flex-shrink: 0;
    background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
    cursor: pointer; transition: background 0.15s var(--ease);
}
.theme-toggle:hover { background: var(--surface-3); }
.theme-toggle .icon { width: 17px; height: 17px; }
.theme-toggle-icon-sun { display: none; }
[data-theme="light"] .theme-toggle-icon-moon { display: none; }
[data-theme="light"] .theme-toggle-icon-sun { display: inline-block; }

.notif-bell-wrap { position: relative; }
.notif-bell {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 999px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    color: var(--text);
    font-size: 1.05rem;
    cursor: pointer;
}
.notif-bell:hover { background: var(--surface-3); }
.notif-badge {
    position: absolute;
    top: -4px;
    right: -4px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 999px;
    background: var(--color-danger);
    color: #fff;
    font-size: 0.62rem;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
}
.notif-dropdown {
    display: none;
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    width: 320px;
    max-width: calc(100vw - 24px);
    max-height: 400px;
    overflow-y: auto;
    background: var(--surface-2);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-md);
    z-index: 200;
    box-shadow: var(--shadow);
}
.notif-dropdown.open { display: block; }
/* In the sidebar the bell sits ~200px from the left edge, in a column only
   236px wide - anchoring the dropdown's right edge to it (as the mobile
   topbar does, where the bell sits at the far right of a wide viewport)
   would push most of a 320px-wide panel off the left of the screen. Anchor
   from the left instead so it opens into the roomy main content area. */
.sidebar .notif-dropdown { left: 0; right: auto; }
.notif-dropdown-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 14px;
    border-bottom: 1px solid var(--border);
    font-size: 0.82rem;
    font-weight: 600;
}
.notif-dropdown-item {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    padding: 10px 14px;
    text-decoration: none;
    color: var(--text);
    border-bottom: 1px solid var(--border);
    font-size: 0.82rem;
}
.notif-dropdown-item:last-child { border-bottom: none; }
.notif-dropdown-item:hover { background: var(--surface-3); }
.notif-dropdown-item.unread { background: color-mix(in srgb, var(--accent) 8%, transparent); }
.notif-dropdown-item .icon { color: var(--accent); font-size: 1.1rem; margin-top: 2px; }
.notif-dropdown-empty { padding: 24px 14px; text-align: center; color: var(--text-soft); font-size: 0.82rem; }
.notif-item-time { display: block; color: var(--text-soft); font-size: 0.72rem; margin-top: 2px; }

/* ============================================================================
   Review modal
   ============================================================================ */
/* display:flex below beats the [hidden] attribute's UA display:none, which
   silently leaves a "hidden" modal on screen. Honour hidden explicitly so
   either convention works. */
.modal-backdrop[hidden] { display: none !important; }
.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.65);
    backdrop-filter: blur(4px);
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}
.modal-box {
    background: var(--surface);
    border-radius: var(--radius-lg);
    padding: 30px 32px;
    width: 100%;
    max-width: 440px;
    box-shadow: 0 40px 90px rgba(0, 0, 0, 0.25);
    /* A form-length modal is taller than a short phone. Without these the
       box overflows the viewport and its Cancel/Save buttons become
       unreachable - the backdrop is fixed, so the page behind cannot
       scroll to them. */
    max-height: calc(100vh - 48px);
    overflow-y: auto;
    overscroll-behavior: contain;
}
@media (max-width: 560px) {
    .modal-backdrop { padding: 12px; align-items: flex-start; }
    .modal-box { padding: 20px; max-height: calc(100vh - 24px); }
}
.star-rating {
    display: flex;
    gap: 6px;
    margin-top: 8px;
}
.star-btn {
    background: none;
    border: none;
    font-size: 28px;
    color: var(--text-soft);
    cursor: pointer;
    padding: 0 2px;
    line-height: 1;
    transition: color 0.12s, transform 0.1s;
}
.star-btn:hover,
.star-btn.active {
    color: #FBBF24;
}
.star-btn:hover { transform: scale(1.15); }

/* ============================================================================
   Toast notifications — flash messages render as these (see base.html)
   ============================================================================ */
#toast-container {
    position: fixed;
    bottom: calc(var(--bottom-nav-height) + 16px);
    left: 50%;
    transform: translateX(-50%);
    z-index: 1000;
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: center;
    pointer-events: none;
    width: min(360px, calc(100vw - 32px));
}
.toast {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface-2);
    border: 1px solid var(--color-border-strong);
    border-left: 3px solid var(--color-text-muted);
    border-radius: var(--radius-md);
    color: var(--color-text);
    font-size: var(--font-size-sm);
    font-weight: 500;
    box-shadow: var(--shadow-lg);
    pointer-events: auto;
    opacity: 0;
    transform: translateY(12px);
    transition: opacity 0.25s var(--ease), transform 0.25s var(--ease);
}
.toast.toast-visible { opacity: 1; transform: translateY(0); }
.toast-success { border-left-color: var(--color-success); }
.toast-error, .toast-danger { border-left-color: var(--color-danger); }
.toast-warning { border-left-color: var(--color-warning); }
.toast-info { border-left-color: var(--color-info); }

/* ============================================================================
   Skeleton loaders
   ============================================================================ */
.skeleton {
    background: linear-gradient(90deg, var(--color-surface-2) 25%, var(--color-surface-3) 50%, var(--color-surface-2) 75%);
    background-size: 200% 100%;
    animation: shimmer 1.5s infinite;
    border-radius: var(--radius-sm);
}
@keyframes shimmer {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}

/* ============================================================================
   Mobile card list — alternative to .table-wrap below 640px (list/jobs/
   clients/invoices pages toggle between the two via these two classes)
   ============================================================================ */
.card-list { display: none; flex-direction: column; gap: 0; margin: 0 calc(-1 * var(--space-6)); }
.card-list-item {
    display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
    padding: var(--space-4) var(--space-6); background: transparent; border-bottom: 1px solid var(--color-border);
    text-decoration: none; color: inherit; cursor: pointer;
}
.card-list-item:last-child { border-bottom: none; }
.card-list-item:hover { background: var(--color-surface-2); }
.card-list-item-main { min-width: 0; flex: 1; }
.card-list-item-title { font-weight: 500; font-size: var(--font-size-sm); color: var(--color-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.card-list-item-meta { font-size: var(--font-size-xs); color: var(--color-text-muted); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.card-list-item-aside { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex-shrink: 0; }
.card-list-item-amount { font-weight: 600; font-size: var(--font-size-sm); font-variant-numeric: tabular-nums; color: var(--color-text); }
.card-list-item-chevron { color: var(--color-text-subtle); font-size: 1.1rem; flex-shrink: 0; }

@media (max-width: 639px) {
    /* Only hide the table where a page has actually built a card-list
       replacement (.has-card-fallback). Every other .table-wrap (line items,
       team list, expenses, aging report, etc.) must stay visible — falling
       back to horizontal scroll — rather than silently disappearing. */
    .table-wrap.has-card-fallback { display: none; }
    .card-list { display: flex; }

    /* Quote/invoice line items are a data-entry form, not a read-only list —
       .card-list doesn't fit. Instead of forcing horizontal scroll through a
       row of tiny inputs, stack each row into a labelled mini-card. */
    #itemsTableWrap { overflow-x: visible; border: none; }
    #itemsTable, #itemsTable thead, #itemsTable tbody, #itemsTable tr, #itemsTable td { display: block; width: 100%; }
    #itemsTable { min-width: 0; }
    #itemsTable thead { position: absolute; left: -9999px; }
    #itemsTable tbody#itemsBody tr {
        border: 1px solid var(--border); border-radius: var(--radius-lg);
        padding: var(--space-3) var(--space-4); margin-bottom: var(--space-3);
        background: var(--surface);
    }
    #itemsTable tbody#itemsBody td {
        border-bottom: none; padding: var(--space-2) 0;
    }
    #itemsTable tbody#itemsBody td[data-label]::before {
        content: attr(data-label); display: block;
        font-size: var(--font-size-xs); color: var(--text-muted); margin-bottom: 4px;
    }
    #itemsTable tbody#itemsBody td input,
    #itemsTable tbody#itemsBody td select { width: 100%; }
    #itemsTable tbody#itemsBody td:last-child { padding-top: var(--space-3); text-align: right; }
}

/* ============================================================================
   Quick actions — big, obvious entry points on the Home screen
   ============================================================================ */
.quick-actions { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s4); margin-bottom: var(--s6); }
.quick-action {
    display: flex; align-items: center; gap: var(--s4);
    padding: var(--s5); border-radius: var(--radius-lg); text-decoration: none;
    min-height: 64px; font-weight: 500; font-size: 1.05rem; text-transform: lowercase;
    transition: transform 0.14s var(--ease), box-shadow 0.14s var(--ease);
}
.quick-action:active { transform: scale(0.98); }
.quick-action-icon { font-size: 1.6rem; flex-shrink: 0; }
.quick-action-primary { background: var(--color-primary); color: #fff; box-shadow: var(--shadow-primary); }
.quick-action-primary:hover { background: var(--color-primary-hover); }
.quick-action-secondary { background: var(--surface); border: 1px solid var(--border-strong); color: var(--text); }
.quick-action-secondary:hover { background: var(--surface-2); border-color: var(--border-strong); }
@media (max-width: 768px) {
    .quick-actions { grid-template-columns: 1fr; }
}

/* ============================================================================
   Wizard — step-by-step forms with a visible progress indicator
   ============================================================================ */
.wizard-progress { display: flex; align-items: center; gap: 8px; margin-bottom: var(--s6); }
.wizard-progress-track { flex: 1; height: 6px; border-radius: 999px; background: var(--surface-3); overflow: hidden; }
.wizard-progress-fill { height: 100%; background: var(--color-primary); border-radius: 999px; transition: width 0.25s var(--ease); }
.wizard-progress-label { font-size: 0.9rem; font-weight: 600; color: var(--text-muted); white-space: nowrap; }
.wizard-step { display: none; min-width: 0; }
.wizard-step.active { display: block; animation: fade 0.2s var(--ease); }
.wizard-step-title { font-size: 1.2rem; font-weight: 700; margin-bottom: var(--s1); }
.wizard-step-hint { color: var(--text-muted); margin-bottom: var(--s5); }
.wizard-nav { display: flex; justify-content: space-between; gap: var(--s3); margin-top: var(--s6); }
.wizard-nav .btn { flex: 1 1 auto; }

/* radio-card doc-type picker — big tappable cards instead of a <select> */
.choice-cards { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); }
.choice-card {
    display: flex; flex-direction: column; align-items: center; gap: 6px;
    padding: var(--s5) var(--s3); border-radius: var(--radius-lg);
    border: 2px solid var(--border-strong); background: var(--surface); cursor: pointer;
    text-align: center; min-height: 88px; justify-content: center;
    transition: border-color 0.14s var(--ease), background 0.14s var(--ease);
}
.choice-card .icon { font-size: 1.4rem; color: var(--text-muted); }
.choice-card strong { font-size: 1rem; }
.choice-card input { position: absolute; opacity: 0; width: 0; height: 0; }
.choice-card.selected { border-color: var(--color-primary); background: var(--color-primary-subtle); }
.choice-card.selected .icon { color: var(--color-primary); }
@media (max-width: 480px) { .choice-cards { grid-template-columns: 1fr; } }

/* "Add more details (optional)" progressive disclosure */
.optional-details > summary {
    display: inline-flex; align-items: center; gap: 6px; min-height: 48px;
    color: var(--color-primary); font-weight: 600; cursor: pointer; list-style: none;
}
.optional-details > summary::-webkit-details-marker { display: none; }
.optional-details > summary::before { content: "+"; font-size: 1.1rem; }
.optional-details[open] > summary::before { content: "−"; }
.optional-details-body { padding-top: var(--s4); display: flex; flex-direction: column; gap: var(--s4); }

/* draft-restore banner */
.draft-banner {
    display: flex; align-items: center; justify-content: space-between; gap: var(--s4); flex-wrap: wrap;
    padding: var(--s4) var(--s5); margin-bottom: var(--s5); border-radius: var(--radius-md);
    background: var(--color-info-subtle); border: 1px solid rgba(62, 124, 224, 0.3); color: var(--text);
}

/* first-use walkthrough */
.tour-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.55); z-index: 300; }
.tour-tooltip {
    position: fixed; z-index: 301; max-width: 300px; background: var(--surface);
    border: 1px solid var(--border-strong); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
    padding: var(--s5); display: flex; flex-direction: column; gap: var(--s3);
}
.tour-tooltip p { color: var(--text-muted); font-size: 0.95rem; }
.tour-tooltip-footer { display: flex; justify-content: space-between; align-items: center; gap: var(--s3); }
.tour-highlight { position: relative; z-index: 301; box-shadow: 0 0 0 4px var(--color-primary), var(--shadow-lg) !important; border-radius: var(--radius-lg); }


/* Business-type picker — radio cards used by the onboarding wizard and the
   Settings > Display tab. The radio itself is visually hidden but still
   focusable, so keyboard users get the :focus-visible outline on the card. */
.type-picker { display:grid; gap:var(--space-3); }
.type-card { display:block; cursor:pointer; }
.type-card input { position:absolute; opacity:0; pointer-events:none; }
.type-card-body {
  display:block; padding:var(--space-4);
  border:2px solid var(--color-border); border-radius:var(--radius-lg);
  background:var(--color-surface-2); transition:border-color .15s, background .15s;
}
.type-card:hover .type-card-body { border-color:var(--color-primary-border); }
.type-card input:checked + .type-card-body {
  border-color:var(--color-primary); background:var(--color-primary-subtle);
}
.type-card input:focus-visible + .type-card-body { outline:2px solid var(--color-primary); outline-offset:2px; }
.type-card-icon { font-size:20px; color:var(--color-primary); display:block; margin-bottom:var(--space-2); }
.type-card-body strong { display:block; font-size:var(--font-size-base); margin-bottom:2px; }
.type-card-blurb { display:block; color:var(--color-text-muted); font-size:var(--font-size-sm); }
.type-card-detail { display:block; color:var(--color-text-subtle); font-size:var(--font-size-xs); margin-top:var(--space-2); }

/* Money that has actually landed vs money still owed — colour carries the
   meaning at a glance, but the adjacent "Paid in full" / "Part-paid" chip
   states it in words too, so it never depends on colour alone. */
.amount-paid { color: var(--color-success); }
.amount-part { color: var(--color-warning); }

/* Inline advisory shown within a page section, as opposed to the transient
   flash banners at the top of the page. */
.flash-inline {
  padding: var(--space-3) var(--space-4); border-radius: var(--radius-md);
  font-size: var(--font-size-sm); margin-bottom: var(--space-3);
  border: 1px solid transparent;
}
.flash-inline-warn {
  background: color-mix(in srgb, var(--color-warning) 12%, transparent);
  border-color: color-mix(in srgb, var(--color-warning) 35%, transparent);
  color: var(--color-warning);
}

/* ── Project timeline (milestones) ────────────────────────────────────── */
.progress-track {
  height: 8px; border-radius: 999px; overflow: hidden;
  background: var(--color-surface-3);
}
.progress-fill {
  height: 100%; border-radius: 999px; background: var(--color-primary);
  transition: width .3s ease;
}

.timeline { list-style: none; margin: 0; padding: 0; }
.timeline-item {
  display: flex; align-items: flex-start; gap: var(--space-3);
  padding: var(--space-3) 0; position: relative;
}
/* Connecting spine between the dots, stopping short of the last one. */
.timeline-item:not(:last-child)::before {
  content: ""; position: absolute; left: 13px; top: 34px; bottom: -6px;
  width: 2px; background: var(--color-border);
}
.timeline-check { flex: 0 0 auto; }
.timeline-dot {
  width: 28px; height: 28px; border-radius: 50%; cursor: pointer;
  border: 2px solid var(--color-border); background: var(--color-surface-2);
  color: #fff; font-size: 13px; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  transition: border-color .15s, background .15s;
}
.timeline-dot:hover { border-color: var(--color-primary); }
.timeline-item.is-complete .timeline-dot {
  background: var(--color-success); border-color: var(--color-success);
}
.timeline-item.is-overdue .timeline-dot { border-color: var(--color-warning); }
.timeline-body { flex: 1 1 auto; min-width: 0; }
.timeline-body h4 { margin: 0 0 2px; font-size: var(--font-size-base); }
.timeline-body p { margin: 0; color: var(--color-text-muted); font-size: var(--font-size-sm); }
.timeline-item.is-complete .timeline-body h4 {
  text-decoration: line-through; color: var(--color-text-muted);
}

/* A 28px dot is fine for a mouse but under the ~44px comfortable touch
   target. Grow the hit area on touch devices without changing how the
   timeline looks, by padding the button and pulling the spine back into
   line with the larger dot. */
@media (pointer: coarse), (max-width: 560px) {
  .timeline-dot { width: 44px; height: 44px; font-size: 16px; }
  .timeline-item:not(:last-child)::before { left: 21px; top: 50px; }
  .timeline-body { padding-top: 8px; }
}

/* Branding logo on the in-app invoice/quote header, so the document you
   review looks like the one the client receives. */
.detail-hero-main { display: flex; align-items: center; gap: var(--space-4); min-width: 0; }
.doc-logo {
  max-height: 52px; max-width: 150px; width: auto; object-fit: contain;
  border-radius: var(--radius-sm); flex: 0 0 auto;
}
@media (max-width: 560px) {
  .detail-hero-main { gap: var(--space-3); }
  .doc-logo { max-height: 36px; max-width: 96px; }
}
