/* ===== Font Imports (must be first) ===== */
@import url('https://fonts.googleapis.com/css2?family=Chakra+Petch:wght@500;600;700&family=Manrope:wght@400;500;600;700;800&display=swap');

/* The card surface is a gradient. Plain gradients can't be transitioned (they
   animate discretely), so its two colour stops are registered as typed custom
   properties — those DO interpolate, letting the card cross-fade with the rest
   of the page on a theme change. See --bg-card below and the theme-animating
   block. */
@property --bg-card-stop-1 {
	syntax: "<color>";
	inherits: true;
	initial-value: #23242a;
}

@property --bg-card-stop-2 {
	syntax: "<color>";
	inherits: true;
	initial-value: #1c1d22;
}

/* Assemble the card gradient on `body` so its var() stops resolve against
   body's values — which flip with `light-mode` and interpolate under
   `theme-animating`. Declaring it on :root instead would bake the dark stops in
   and cards would never change theme. Cards inherit this value. */
body {
	--bg-card: linear-gradient(160deg, var(--bg-card-stop-1) 0%, var(--bg-card-stop-2) 100%);
}

/* ===== CSS Variables (Dark mode default) ===== */
/* "Atlas Cobalt" design system — see obsidian/CSS Design System.md and
   Admin → Design Rules for the full token reference. */
:root {
	/* Surfaces — Atlas Cobalt dark neutrals: neutral greys, NO blue cast.
	   Surfaces step up from the canvas with a visible border so cards/tables read.
	   canvas / (mid) / panel / sunken-header — every surface steps up. */
	--bg-primary: #191a1e;
	--bg-secondary: #1f2024;
	--bg-tertiary: #2a2b30;
	--bg-nav: #1f2024;
	--bg-input: #2a2b30;
	--bg-hover: rgba(70, 114, 216, 0.08);
	--bg-card-stop-1: #23242a;
	--bg-card-stop-2: #1c1d22;
	/* --bg-card is assembled from the stops on `body` (see below), NOT here — a
	   custom property resolves its inner var() at the element it's declared on,
	   so defining it on :root would bake in these dark stops and ignore the
	   light-mode override / the animating stops. */
	--bg-page: #141518;
	--bg-zebra: #212226;

	/* Text — soft off-white (never pure #fff), neutral grey steps, no blue cast */
	--text-primary: #dee1e5;
	--text-secondary: #b4b8bf;
	--text-muted: #9da1a9;
	--text-on-color: #ffffff;

	/* Primary — Atlas Cobalt accent (softened: less saturated so text reads easier) */
	--primary-color: #4672d8;
	--primary-hover: #3a61c4;
	--primary-subtle: rgba(70, 114, 216, 0.14);
	--accent-glow: rgba(70, 114, 216, 0.18);
	/* Links / report actions — brighter cobalt for contrast on dark surfaces */
	--link-color: #77a5ff;
	/* Brand accent gradient (cobalt → sky) — accent headers/badges. Single source; was duplicated across 6 files. */
	--gradient-brand: linear-gradient(135deg, #2563eb 0%, #38bdf8 100%);

	/* Semantic */
	--success-color: #22c55e;
	--success-hover: #1ba750;
	--success-subtle: rgba(34, 197, 94, 0.14);

	--warning-color: #f5a524;
	--warning-hover: #db9014;
	--warning-subtle: rgba(245, 165, 36, 0.14);

	--danger-color: #f04452;
	--danger-hover: #d93341;
	--danger-subtle: rgba(240, 68, 82, 0.14);

	--info-color: #38bdf8;
	--info-hover: #22a8e3;
	--info-subtle: rgba(56, 189, 248, 0.14);

	--purple-color: #8b5cf6;
	--purple-hover: #7c4fe0;
	--purple-subtle: rgba(139, 92, 246, 0.12);

	/* Overlay */
	--overlay-bg: rgba(0, 0, 0, 0.60);

	/* Layout */
	--sidebar-width: 260px;
	--topbar-height: 52px;

	/* Modal geometry — shared by the standard overlay (.modal/.modal-overlay)
	   and the native <dialog> pattern (.dash-report-modal) so every modal sits
	   the same distance from the top and bottom. Override per page if needed. */
	--modal-offset: calc(var(--topbar-height) + 16px);
	--modal-max-h: calc(100vh - var(--modal-offset) * 2);

	/* Borders & Shadows — visible neutral border + elevation ring so cards pop on dark */
	--border-color: #34363b;
	--shadow-sm: 0 0 0 1px rgba(255, 255, 255, 0.04), 0 2px 6px rgba(0, 0, 0, 0.45);
	--shadow-md: 0 0 0 1px rgba(255, 255, 255, 0.04), 0 8px 24px rgba(0, 0, 0, 0.5);
	--shadow-lg: 0 0 0 1px rgba(255, 255, 255, 0.05), 0 16px 40px rgba(0, 0, 0, 0.55);

	/* Scrollbars — one size for every scroll area on the site (page, cards,
	   table wrappers, modals). Don't re-declare a width/height in a page file:
	   a per-page override is what makes bars look inconsistent between pages.
	   The thumb is a white/black alpha rather than a solid hex on purpose: the
	   track is transparent, so the thumb tints whatever surface it happens to
	   sit on (page, card, modal) and keeps the same contrast on all of them. A
	   solid --border-color thumb reads as a near-invisible dark bar on
	   --bg-primary, which is what Firefox showed once it stopped drawing its own
	   light native thumb. --scrollbar-thumb-hover is Chrome/Safari only —
	   Firefox's scrollbar-color has no hover state. */
	--scrollbar-size: 8px;
	--scrollbar-thumb: rgba(255, 255, 255, 0.22);
	--scrollbar-thumb-hover: rgba(255, 255, 255, 0.38);

	/* Sheen — a low-contrast corner-light overlay applied as background-image
	   over a component's own background-colour, so solid fills (buttons, active
	   tabs, pill thumbs, badges) read as slightly raised instead of flat.
	   Deliberately subtle: it should be felt, not seen. Because it's an image
	   (not a colour) the component keeps its background-color and its :hover
	   colour change still works. 135deg matches --gradient-brand — a flat
	   top-to-bottom fade reads as a band rather than as light falling on the
	   surface. --sheen-neutral is for surface-coloured components
	   (.btn-secondary, tab surfaces), where a white wash strong enough for a
	   saturated fill would blow out. */
	--sheen: linear-gradient(135deg, rgba(255, 255, 255, 0.13) 0%, rgba(255, 255, 255, 0.02) 55%, rgba(0, 0, 0, 0.07) 100%);
	--sheen-neutral: linear-gradient(135deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0) 55%, rgba(0, 0, 0, 0.07) 100%);

	/* Border radius */
	/* Small controls (checkboxes) only. --radius-sm (8px) on a 16px box renders
	   a full circle, so checkboxes get their own softly-squared radius. */
	--radius-xs: 4px;
	--radius-sm: 8px;
	--radius-md: 12px;
	--radius-lg: 16px;
	/* Pills are squared off to match buttons — points at --radius-sm rather than
	   a fully-rounded 999px so every pill/badge reads as a rectangular button. */
	--radius-pill: var(--radius-sm);
	/* Fully-rounded / stadium shape for genuinely round elements — toggle-switch
	   tracks and circular dots/indicators. Use this (not --radius-pill) when the
	   element must stay a circle or stadium rather than a squared-off button. */
	--radius-round: 999px;

	/* Transitions */
	--transition: all 0.2s ease;

	/* Spacing rhythm */
	--sp-1: 4px;
	--sp-2: 8px;
	--sp-3: 12px;
	--sp-4: 16px;
	--sp-5: 20px;
	--sp-6: 24px;

	/* Typography */
	--font-display: 'Chakra Petch', -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
	--font-body: 'Manrope', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
	--font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;

	/* Font-size scale — the only sizes the UI should use. --fs-md is the body
	   default (set on `body` below), so most text needs no explicit font-size.
	   Theme-independent, so light-mode.css doesn't override these. */
	--fs-2xs: 0.5rem;    /* 8px  — micro labels */
	--fs-xs: 0.625rem;   /* 10px — tiny badges/meta */
	--fs-sm: 0.75rem;    /* 12px — secondary/dense text, most badges */
	--fs-md: 0.875rem;   /* 14px — base UI/body text */
	--fs-lg: 1rem;       /* 16px — emphasis, section labels */
	--fs-xl: 1.125rem;   /* 18px — card titles */
	--fs-2xl: 1.25rem;   /* 20px — subheadings */
	--fs-3xl: 1.5rem;    /* 24px — page/section headings */
	--fs-4xl: 2rem;      /* 32px — scale cap (large icons, hero numbers) */

	/* RGB companions — for rgba(var(--x-rgb), alpha) tints. Keep in sync with the
	   colour tokens above; overridden in light-mode.css where the hue shifts. */
	--primary-rgb: 70, 114, 216;
	--success-rgb: 34, 197, 94;
	--danger-rgb: 240, 68, 82;
	--warning-rgb: 245, 165, 36;
	--info-rgb: 56, 189, 248;
	--purple-rgb: 139, 92, 246;
	--text-secondary-rgb: 180, 184, 191;
	/* Legacy aliases referenced by existing feature CSS */
	--danger-color-rgb: var(--danger-rgb);
	--warning-color-rgb: var(--warning-rgb);
}

/* ===== Mobile token overrides ===== */
/* Redefining the token VALUES (not per-component rules) at the phone breakpoint,
   so every var() reference scales automatically — the same mechanism light-mode
   uses. Only the *large* end of each scale is dialled back: hero headings and
   generous margins dominate a narrow viewport, while body text and small
   control gaps must stay legible/tappable, so --fs-sm/md/lg and --sp-1..4 are
   left untouched. These phone-scale token overrides stay at 768px; the
   sidebar→hamburger nav collapse happens higher up at 1080px. */

/* ===== Reset & Base Styles ===== */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: var(--font-body);
    font-size: var(--fs-md);
    background-color: var(--bg-page);
    color: var(--text-primary);
    /* Base line-height for the whole site. Two values only: this 1.25 default
       (inherited everywhere, incl. form controls) and a compressed
       `line-height: 1` applied by hand where text must be tight (icons,
       badges, pills, big numbers). Don't introduce other values. */
    line-height: 1.25;
    overflow-x: hidden;
}

/* Display type — headings & numeric stat values use Chakra Petch (Atlas Cobalt) */
h1, h2, h3, h4, h5, h6,
.page-title,
.stats-number,
.stat-value {
	font-family: var(--font-display);
	font-weight: 600;
}

/* ===== Animated background blobs ===== */
.main-bg {
    position: fixed;
    inset: 0;
    z-index: 0;
    overflow: hidden;
    pointer-events: none;
}

.main-blob {
    position: absolute;
    border-radius: var(--radius-round);
    filter: blur(120px);
    opacity: 0.055;
    animation: main-blob-drift linear infinite;
    will-change: transform;
}

.main-blob-1 {
    width: 900px;
    height: 900px;
    background: radial-gradient(circle at 40% 40%, var(--primary-hover), transparent 65%);
    top: -300px;
    left: -200px;
    animation-duration: 40s;
}

.main-blob-2 {
    width: 700px;
    height: 700px;
    background: radial-gradient(circle at 60% 60%, var(--info-color), transparent 65%);
    bottom: -250px;
    right: -150px;
    animation-duration: 34s;
    animation-delay: -14s;
}

.main-blob-3 {
    width: 500px;
    height: 500px;
    background: radial-gradient(circle at 50% 50%, var(--primary-color), transparent 65%);
    top: 50%;
    left: 40%;
    animation-duration: 50s;
    animation-delay: -25s;
    opacity: 0.03;
}

@keyframes main-blob-drift {
    0% {
        transform: translate(0, 0) scale(1);
    }

    25% {
        transform: translate(60px, -50px) scale(1.04);
    }

    50% {
        transform: translate(-40px, 70px) scale(0.97);
    }

    75% {
        transform: translate(50px, 30px) scale(1.02);
    }

    100% {
        transform: translate(0, 0) scale(1);
    }
}

body.light-mode .main-blob {
    display: none;
}

/* ===== Impersonation Banner ===== */
.impersonation-banner {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 10000;
	background: linear-gradient(90deg, var(--warning-color), var(--warning-hover));
	color: var(--text-on-color);
    font-size: var(--fs-md);
    font-weight: 500;
    box-shadow: 0 2px 8px rgba(0,0,0,0.25);
}

.impersonation-inner {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-5);
}

.impersonation-stop {
	color: var(--text-on-color);
    text-decoration: none;
    background: rgba(255,255,255,0.2);
    padding: var(--sp-1) var(--sp-3);
    border-radius: var(--radius-pill);
    font-size: var(--fs-sm);
    font-weight: 600;
    transition: background 0.2s;
    margin-left: var(--sp-2);
}

.impersonation-stop:hover {
    background: rgba(255,255,255,0.35);
}

/* When impersonating, shift everything down */
body:has(.impersonation-banner) .sidebar {
    top: 34px;
    height: calc(100vh - 34px);
}

body:has(.impersonation-banner) .top-navbar {
    top: 34px;
}

body:has(.impersonation-banner) .main-content {
    padding-top: calc(var(--topbar-height) + 34px);
}

/* ===== Sidebar Navigation ===== */
.sidebar {
    position: fixed;
    top: 0;
    left: 0;
    height: 100vh;
    width: var(--sidebar-width);
    background-color: var(--bg-nav);
    display: flex;
    flex-direction: column;
    transition: var(--transition);
    border-right: 1px solid var(--border-color);
    z-index: 1000;
}

/* Hidden state — the sidebar slides fully off-screen and the content/topbar
   reclaim the space (see .main-content.expanded / .top-navbar.expanded). */
.sidebar.hidden {
    transform: translateX(-100%);
}

/* Sidebar Header */
.sidebar-header {
    padding: 0 var(--sp-5);
    border-bottom: 1px solid var(--border-color);
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: var(--topbar-height);
    flex-shrink: 0;
}

.sidebar-header h3 {
    font-size: var(--fs-2xl);
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
}

.sidebar-logo {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    overflow: hidden;
    height: 36px;
}

.logo-full {
    height: 36px;
    width: auto;
    display: block;
    transition: opacity 0.2s ease;
}

/* Light/dark background logo visibility */
.logo-light-bg {
    display: none !important;
}

body.light-mode .logo-dark-bg {
    display: none !important;
}

body.light-mode .logo-light-bg.logo-full {
    display: block !important;
}

/* Navigation Menu */
.sidebar-nav {
    flex: 1;
    overflow-y: auto;
    padding: var(--sp-2);
    padding-top: var(--sp-1);
}

.nav-section {
    margin-bottom: 0;
}

.sidebar-nav > .nav-section,
.sidebar-nav > .nav-link.single {
    position: relative;
}

.sidebar-nav > * + * {
    margin-top: var(--sp-1);
    padding-top: var(--sp-1);
}

.sidebar-nav > * + *::before {
    content: "";
    position: absolute;
    top: 0;
    left: 4px;
    right: 4px;
    height: 1px;
    background: var(--border-color);
    opacity: 0.3;
}

.nav-section-header {
    padding: var(--sp-3) var(--sp-4) var(--sp-1);
    font-weight: 800;
    font-size: var(--fs-xs);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    user-select: none;
}

.nav-section-content {
    padding-bottom: var(--sp-1);
}

.nav-link:hover {
    background-color: var(--bg-hover);
    color: var(--text-primary);
	border-left-color: rgba(var(--primary-rgb), 0.2);
}

.nav-link.active {
	background-color: rgba(var(--primary-rgb), 0.08);
	background-image: var(--sheen-neutral);
    color: var(--text-primary);
}

.nav-link.single {
    padding: var(--sp-3) var(--sp-4);
    display: flex;
    align-items: center;
    font-weight: 600;
    font-size: var(--fs-sm);
    text-transform: uppercase;
    color: var(--text-secondary);
    border-left: none;
    border-radius: var(--radius-sm);
}

.nav-link.single i {
    color: var(--text-muted);
    margin-right: 2px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
}

.nav-link.single:hover {
    color: var(--text-primary);
    border-left: none;
}

/* Nav badge counters */
.nav-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    margin-left: auto;
    border-radius: var(--radius-pill);
    font-size: var(--fs-xs);
    font-weight: 700;
    line-height: 1;
	background-color: var(--primary-color, #6366f1);
	background-image: var(--sheen);
	color: var(--text-on-color);
}

.nav-badge.unread {
	background-color: var(--warning-color);
}

.nav-link.disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.nav-link.disabled:hover {
    padding-left: var(--sp-4);
}

.nav-section-content .nav-link + .nav-link {
    margin-top: 2px;
}

.nav-link {
    display: flex;
    align-items: center;
    padding: 6px 16px;
    color: var(--text-secondary);
    text-decoration: none;
    transition: var(--transition);
    white-space: nowrap;
    overflow: hidden;
    border-radius: var(--radius-sm);
}

.nav-section-header,
.nav-link:hover {
    transform: none;
    box-shadow: none;
}

.nav-link.single.active,
.nav-link.active {
    box-shadow: none;
}

/* ===== Top Navbar ===== */
.top-navbar {
    position: fixed;
    top: 0;
    left: var(--sidebar-width);
    right: 0;
    height: var(--topbar-height);
    background-color: var(--bg-nav);
    border-bottom: 1px solid var(--border-color);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 var(--sp-4);
    z-index: 999;
    transition: var(--transition);
}

.top-navbar.expanded {
    left: 0;
}

.top-navbar-left {
    display: flex;
    align-items: center;
    flex: 1;
}

.page-content {
    display: flex;
    flex-direction: column;
    margin: 0 auto;
    max-width: 1620px;
    padding-top: 0;
    gap: var(--sp-6);
}

.page-content.card {
    border-radius: var(--radius-md);
}

.page-title {
    font-size: var(--fs-xl);
    font-weight: 600;
    margin: 0;
}

/* Breadcrumb-style page navigation (replaces the old back-arrow link).
   Parent segments are muted links, the current page is emphasised. */
.page-breadcrumb {
	display: inline-flex;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--sp-2);
	min-width: 0;
}

.page-breadcrumb a {
	color: var(--text-secondary);
	text-decoration: none;
	transition: var(--transition);
}

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

.page-breadcrumb .breadcrumb-sep {
	color: var(--text-muted);
	font-weight: 400;
}

.page-breadcrumb .breadcrumb-current {
	color: var(--text-primary);
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.top-navbar-right {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
}

.top-navbar-center {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    pointer-events: none;
}

.top-navbar-center .top-search {
    pointer-events: auto;
}

/* Top Search — the <form> is the canonical .search-input-wrapper (and the
   positioning context for .search-dropdown below it). Only the fixed width,
   pill shape, lighter fill and navbar height are chrome-specific. */
.top-search {
	width: 420px;
}

.top-search form {
	height: 32px;
	padding: 0 16px;
	background-color: var(--bg-primary);
	border-radius: var(--radius-pill);
}

.top-search input[type="search"] {
	padding: 0;
}

/* Live search dropdown */
.search-dropdown {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    max-height: 70vh;
    overflow-y: auto;
    background-color: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md, var(--radius-sm));
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
    z-index: 1100;
    padding: var(--sp-1) 0;
}

.search-dropdown[hidden] {
    display: none;
}

.search-dropdown-group-label {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px 4px;
    font-size: var(--fs-sm);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}

.search-dropdown-group-label i {
    position: static;
    left: auto;
    font-size: var(--fs-sm);
    color: var(--text-muted);
    pointer-events: auto;
}

.search-dropdown-item {
    display: block;
    padding: 7px 14px;
    text-decoration: none;
    color: var(--text-primary);
    cursor: pointer;
}

.search-dropdown-item:hover,
.search-dropdown-item.is-active {
    background-color: var(--bg-secondary, rgba(0, 0, 0, 0.05));
}

.search-dropdown-item-title {
    font-size: var(--fs-md);
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.search-dropdown-item-subtitle {
    font-size: var(--fs-sm);
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.search-dropdown-empty,
.search-dropdown-footer {
    padding: 10px 14px;
    font-size: var(--fs-sm);
    color: var(--text-muted);
    text-align: center;
}

.search-dropdown-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    padding: 12px 14px;
    font-size: var(--fs-sm);
    color: var(--text-muted);
}

.search-dropdown-spinner {
    width: 14px;
    height: 14px;
    border: 2px solid var(--border-color);
    border-top-color: var(--primary-color);
    border-radius: var(--radius-round);
    animation: search-dropdown-spin 0.6s linear infinite;
}

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

.search-dropdown-footer a {
    color: var(--primary-color);
    text-decoration: none;
    font-weight: 600;
}

.search-dropdown-footer a:hover {
    text-decoration: underline;
}

/* Location Selector */
/* Top-bar location picker — a kebab-menu whose trigger shows the current
   value inline (see .kebab-trigger-labeled). The dropdown reuses all the
   .kebab-dropdown / .kebab-item styling so its list matches the site-wide
   3-dot menu instead of the OS-rendered native <select> list. */
.top-location-menu {
	flex-shrink: 0;
}

/* NOTE: the .kebab-trigger-labeled rules live further down, immediately after
   the base .kebab-trigger block — they override its fixed 32px width, so they
   must come after it in source order (same specificity). */

.top-location-menu.open .top-location-caret {
	transform: rotate(180deg);
}

.top-location-dropdown {
	min-width: 220px;
}

/* Footer row holding the Apply button */
.top-location-actions {
	display: flex;
	justify-content: flex-end;
	padding: var(--sp-1) var(--sp-1) 0;
}

/* Theme Toggle — labelled sliding switch (Light / Dark) */
.theme-switch {
	position: relative;
	height: 34px;
	padding: 0;
	flex-shrink: 0;
	border: 1px solid var(--border-color);
	border-radius: var(--radius-round);
	background: var(--bg-secondary);
	box-shadow: var(--shadow-sm);
	cursor: pointer;
	transition: border-color var(--transition), box-shadow var(--transition);
}

.theme-switch:hover {
	border-color: var(--primary-color);
	box-shadow: var(--shadow-md);
}

.theme-switch-track {
	position: relative;
	display: block;
	width: 84px;
	height: 100%;
}

/* Only the active theme's label is shown; it sits opposite the thumb and swaps
   sides as the thumb slides across. */
.theme-switch-label {
	position: absolute;
	top: 0;
	bottom: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	font-size: var(--fs-sm);
	font-weight: 600;
	letter-spacing: 0.01em;
	white-space: nowrap;
	color: var(--text-secondary);
	pointer-events: none;
	transition: opacity var(--transition);
}

/* Dark active (default): thumb on the left, "Dark" fills the space to its right. */
.theme-switch-label-dark {
	left: 30px;
	right: 8px;
}

/* Light active: thumb on the right, "Light" fills the space to its left. */
.theme-switch-label-light {
	left: 8px;
	right: 30px;
	opacity: 0;
}

.theme-switch-thumb {
	position: absolute;
	top: 2px;
	left: 3px;
	width: 28px;
	height: 28px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border-radius: var(--radius-round);
	background: var(--primary-color);
	box-shadow: var(--shadow-sm);
	/* Springy overshoot so the slide feels physical rather than linear. */
	transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1), background var(--transition);
	z-index: 1;
}

.theme-switch-thumb i {
	display: block;
	font-size: var(--fs-md);
	line-height: 1;
	color: var(--text-on-color);
	/* Fade/rotate the icon as it swaps so the change reads as one motion. */
	transition: transform var(--transition), opacity var(--transition);
}

/* Default (dark): only the moon icon shows inside the thumb. */
.theme-switch-thumb .theme-icon-light {
	display: none;
}

/* Light mode: thumb slides right, icon + label swap to the light variants. */
body.light-mode .theme-switch-thumb {
	transform: translateX(50px);
}

body.light-mode .theme-switch-thumb .theme-icon-dark {
	display: none;
}

body.light-mode .theme-switch-thumb .theme-icon-light {
	display: inline-flex;
}

body.light-mode .theme-switch-label-dark {
	opacity: 0;
}

/* Smooth the colour swap when toggling themes so light mode doesn't flash in
   abruptly — the page darkens/lightens gradually over ~2.4s. Applied only during
   the toggle (via the `theme-animating` class added in JS) so it never adds
   cost to normal interactions. */
body.theme-animating *,
body.theme-animating *::before,
body.theme-animating *::after {
	transition: background-color 2.4s ease, border-color 2.4s ease, color 2.4s ease, fill 2.4s ease, box-shadow 2.4s ease !important;
}

/* Body owns the card gradient stops; cards inherit the animating value so their
   gradient cross-fades. Transitioning the stops here (not on every descendant)
   avoids each card re-triggering its own transition while chasing the inherited
   value. */
body.theme-animating {
	transition: background-color 2.4s ease, border-color 2.4s ease, color 2.4s ease, fill 2.4s ease, box-shadow 2.4s ease, --bg-card-stop-1 2.4s ease, --bg-card-stop-2 2.4s ease !important;
}

/* The thumb still needs its own transform transition during the toggle, or the
   blanket rule above (which omits transform) makes it snap instead of slide.
   Matched to the 2.4s colour cross-fade so the thumb finishes sliding just as
   the theme settles (the overshoot easing gives it a small bounce on arrival). */
body.theme-animating .theme-switch-thumb {
	transition: transform 2.4s cubic-bezier(0.34, 1.56, 0.64, 1), background-color 2.4s ease !important;
}

body.light-mode .theme-switch-label-light {
	opacity: 1;
}

/* Validation bell */
.validation-bell-wrapper {
    position: relative;
    display: inline-flex;
    align-items: center;
}

.validation-bell-btn {
    position: relative;
    width: 32px;
    height: 32px;
    border-radius: var(--radius-md);
    border: 1px solid var(--warning-color, #f59e0b);
    background: var(--bg-primary);
    color: var(--warning-color, #f59e0b);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--fs-lg);
    transition: var(--transition);
}

.validation-bell-btn:hover {
	background: rgba(var(--warning-rgb), 0.12);
}

.validation-bell-badge {
    position: absolute;
    top: -4px;
    right: -4px;
	background: var(--danger-color);
	color: var(--text-on-color);
    font-size: var(--fs-xs);
    font-weight: 700;
    border-radius: var(--radius-sm);
    min-width: 16px;
    height: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 var(--sp-1);
    line-height: 1;
}

.validation-bell-dropdown {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    width: 420px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    box-shadow: 0 8px 24px rgba(0,0,0,0.25);
    z-index: 2000;
    overflow: hidden;
}

.validation-bell-header {
    padding: 10px 14px;
    font-size: var(--fs-sm);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-secondary);
    border-bottom: 1px solid var(--border-color);
}

.validation-bell-loading,
.validation-bell-empty {
    padding: 14px;
    font-size: var(--fs-md);
    color: var(--text-secondary);
    text-align: center;
}

/* Bell dropdown table */
.vbell-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--fs-sm);
}

.vbell-table thead tr th {
    padding: 6px 4px;
    text-align: center;
    border-bottom: 2px solid var(--border-color);
    font-size: var(--fs-sm);
    color: var(--text-secondary);
    white-space: nowrap;
}

.vbell-table thead tr th.vbell-th-order {
    text-align: left;
    padding-left: var(--sp-3);
}

.vbell-table tbody tr {
    border-bottom: 1px solid var(--border-color);
    transition: background 0.1s;
}

.vbell-table tbody tr:last-child {
    border-bottom: none;
}

.vbell-table tbody tr:hover {
    background: var(--bg-hover, rgba(0,0,0,0.02));
}

.vbell-td-order {
    padding: 8px 6px 8px 12px;
    text-align: left;
    max-width: 190px;
}

.vbell-order-top {
    display: flex;
    align-items: center;
    gap: 5px;
}

.vbell-sale {
    font-size: var(--fs-md);
    font-weight: 700;
    color: var(--text-primary);
}

.vbell-type {
    font-size: var(--fs-xs);
    font-weight: 700;
    text-transform: uppercase;
    padding: 2px 4px;
    border-radius: var(--radius-sm);
	background: rgba(var(--warning-rgb), 0.15);
	color: var(--warning-color);
	border: 1px solid rgba(var(--warning-rgb), 0.35);
}

.vbell-customer {
    display: block;
    font-size: var(--fs-sm);
    color: var(--text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 180px;
}

.vbell-meta {
    display: block;
    font-size: var(--fs-xs);
    color: var(--text-secondary);
    opacity: 0.7;
    margin-top: 2px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 180px;
}

.vbell-td-done,
.vbell-td-todo,
.vbell-td-na,
.vbell-td-saving {
    padding: var(--sp-2) var(--sp-1);
    text-align: center;
    font-size: var(--fs-md);
    font-weight: 700;
    min-width: 28px;
    cursor: pointer;
    user-select: none;
    transition: background 0.1s;
}

.vbell-td-done {
	color: var(--success-color);
}

.vbell-td-done:hover {
	background: rgba(var(--success-rgb), 0.10);
}

.vbell-td-todo {
	color: var(--warning-color);
}

.vbell-td-todo:hover {
	background: rgba(var(--warning-rgb), 0.10);
}

.vbell-td-na {
    color: var(--text-secondary);
    opacity: 0.45;
    cursor: default;
}

.vbell-td-saving {
    color: var(--text-secondary);
    cursor: wait;
}

.validation-bell-dismiss {
    background: none;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    font-size: var(--fs-sm);
    padding: 4px 6px;
    border-radius: var(--radius-sm);
    line-height: 1;
    transition: var(--transition);
}

.validation-bell-dismiss:hover {
	color: var(--danger-color);
	background: rgba(var(--danger-rgb), 0.1);
}

.validation-bell-footer {
    padding: 8px 14px;
    border-top: 1px solid var(--border-color);
    text-align: right;
}

.validation-bell-view-all {
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--primary-color);
    text-decoration: none;
}

.validation-bell-view-all:hover {
    text-decoration: underline;
}

/* Profile Menu */
.profile-menu-wrapper {
    position: relative;
}

.profile-menu-btn {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-round);
    border: 1px solid var(--border-color);
    background: var(--bg-primary);
    color: var(--primary-color);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--fs-2xl);
    transition: var(--transition);
    padding: 0;
}

.profile-menu-btn:hover {
    border-color: var(--primary-color);
    background: var(--primary-subtle);
}

.profile-dropdown {
    display: none;
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    width: 220px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
    z-index: 2000;
    overflow: hidden;
}

.profile-dropdown.open {
    display: block;
}

.profile-dropdown-header {
    padding: var(--sp-4);
    display: flex;
    align-items: center;
    gap: var(--sp-3);
}

.profile-dropdown-avatar {
    font-size: var(--fs-4xl);
    color: var(--primary-color);
    flex-shrink: 0;
    line-height: 1;
}

.profile-dropdown-name {
    font-weight: 600;
}

.profile-dropdown-role {
    font-size: var(--fs-sm);
    color: var(--text-secondary);
    margin-top: 2px;
}

.profile-dropdown-divider {
    height: 1px;
    background: var(--border-color);
}

.profile-dropdown-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: var(--sp-3) var(--sp-4);
    color: var(--text-primary);
    text-decoration: none;
    transition: background 0.15s;
}

.profile-dropdown-item:hover {
    background: var(--bg-hover);
}

.profile-dropdown-logout {
    color: var(--danger-color);
}

.profile-dropdown-logout:hover {
    background: var(--danger-subtle);
}

.top-login {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-4);
    border-radius: var(--radius-pill);
    background: var(--primary-color);
	color: var(--text-on-color);
    text-decoration: none;
    font-size: var(--fs-md);
    font-weight: 500;
    transition: var(--transition);
}

.top-login:hover {
    opacity: 0.9;
}

/* ===== Main Content Area ===== */
.main-content {
    margin-left: var(--sidebar-width);
    margin-top: var(--topbar-height);
    min-height: calc(100vh - var(--topbar-height));
    transition: var(--transition);
    padding: var(--sp-6);
}

.main-content.expanded {
    margin-left: 0;
}

.content-wrapper {
    max-width: 1620px;
    margin: 0 auto;
}

/* ===== Cards ===== */
.card {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}

.card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--sp-3);
    border-bottom: 1px solid var(--border-color);
    background-color: transparent;
    font-weight: 600;
    font-size: var(--fs-lg);
}

.card-body {
    padding: var(--sp-4);
    padding-top: var(--sp-3);
}

/* ===== Stats Cards ===== */
.stats-card {
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: var(--sp-4);
    text-align: center;
    transition: var(--transition);
}

.stats-card:hover {
    box-shadow: var(--shadow-md);
}

.stats-number {
    font-size: var(--fs-2xl);
    font-weight: 700;
    color: var(--primary-color);
}

.stats-label {
    font-size: var(--fs-sm);
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 1px;
}

/* ===== View Mode Switcher (shared across pages) ===== */
/* Usage: <div class="view-mode-switcher"><a class="view-mode-btn active">…</a>…</div> */
.view-mode-switcher {
    display: inline-flex;
    gap: 0;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: var(--sp-1);
    align-items: center;
    margin-bottom: var(--sp-4);
}

.view-mode-btn {
    padding: var(--sp-1) var(--sp-4);
    display: flex;
    align-items: center;
    border-radius: var(--radius-md);
    border: none;
    background: transparent;
    color: var(--text-secondary);
    font-weight: 500;
    cursor: pointer;
    text-decoration: none;
    transition: background 0.15s, color 0.15s;
    white-space: nowrap;
}

.view-mode-btn.active {
    background: var(--bg-primary);
    color: var(--text-primary);
    box-shadow: 0 1px 3px rgba(0,0,0,0.12);
}

.view-mode-btn:hover:not(.active) {
    color: var(--text-primary);
    text-decoration: none;
}

/* ===== Kebab Menu ===== */
/* Single, site-wide 3-dot contextual menu. Structure:
   <div class="kebab-menu">
     <button class="kebab-trigger" onclick="toggleKebab(this, event)">
       <i class="bi bi-three-dots-vertical"></i>
     </button>
     <div class="kebab-dropdown">
       <a class="kebab-item">…</a>
       <button class="kebab-item danger">…</button>
       <div class="kebab-divider"></div>
       <span class="kebab-label">Section</span>
     </div>
   </div>
   The global toggleKebab()/closeAllKebabs() helpers in base.html handle open/close
   and position the dropdown (position:fixed) so it escapes any clipping container. */
.kebab-menu {
    position: relative;
    display: inline-flex;
    align-items: center;
}

.kebab-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    cursor: pointer;
    font-size: var(--fs-lg);
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}

.kebab-trigger:hover,
.kebab-menu.open .kebab-trigger {
    background: var(--bg-hover);
    color: var(--text-primary);
    border-color: var(--border-color);
}

/* Labeled variant of .kebab-trigger (top-bar location picker): auto width with
   an inline value + caret, and a persistent border so it reads as a control.
   Must stay after .kebab-trigger — it overrides that rule's fixed 32px width
   and zero padding at the same specificity. */
.kebab-trigger-labeled {
	width: auto;
	max-width: 200px;
	height: 32px;
	gap: 6px;
	padding: 0 10px;
	font-size: var(--fs-md);
	font-weight: 500;
	color: var(--text-primary);
	border-color: var(--border-color);
	background: var(--bg-primary);
}

.kebab-trigger-labeled .bi-geo-alt {
	color: var(--primary-color);
}

.kebab-trigger-labeled .top-location-current {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.kebab-trigger-labeled .top-location-caret {
	font-size: var(--fs-sm);
	opacity: 0.7;
	transition: transform var(--transition);
}

.kebab-dropdown {
    display: none;
    position: fixed;
    z-index: 9000;
    min-width: 210px;
    padding: 6px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    flex-direction: column;
    /* overflow visible so nested popovers (e.g. edging diagram) can escape */
    overflow: visible;
}

.kebab-menu.open .kebab-dropdown,
.kebab-dropdown.open {
    display: flex;
}

.kebab-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 10px;
    font-size: var(--fs-md);
    font-weight: 500;
    color: var(--text-primary);
    background: none;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    text-decoration: none;
    text-align: left;
    white-space: nowrap;
    transition: background 0.12s;
}

.kebab-item:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
}

/* Unavailable action (e.g. "Move up" on the first row) — kept visible so the
   menu doesn't change shape, but clearly inert. */
.kebab-item:disabled {
    opacity: 0.4;
    cursor: default;
}

.kebab-item:disabled:hover {
    background: none;
    color: var(--text-secondary);
}

.kebab-item i {
    font-size: var(--fs-lg);
    color: var(--success-color);
    width: 16px;
    text-align: center;
    flex-shrink: 0;
}

/* Muted (e.g. "add missing data") variant */
.kebab-item.muted i,
.kebab-item-muted i {
    color: var(--text-muted);
}

/* Danger variant */
.kebab-item.danger,
.kebab-item-danger {
    color: var(--danger-color);
}

.kebab-item.danger i,
.kebab-item-danger i {
    color: var(--danger-color);
}

.kebab-item.danger:hover,
.kebab-item-danger:hover {
    background: var(--danger-subtle);
    color: var(--danger-color);
}

.kebab-item.disabled,
.kebab-item-disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
}

/* Divider + section label inside the dropdown */
.kebab-divider,
.kebab-separator {
    height: 1px;
    background: var(--border-color);
    margin: var(--sp-1) 0;
}

.kebab-dropdown hr {
    border: none;
    border-top: 1px solid var(--border-color);
    margin: var(--sp-1) 0;
}

.kebab-label,
.kebab-dropdown-header {
    display: block;
    padding: 6px 10px 2px;
    font-size: var(--fs-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}

.kebab-item.active {
    color: var(--success-color);
}

.kebab-check-icon {
    margin-left: auto;
    font-size: var(--fs-lg);
    color: var(--success-color);
    opacity: 0;
    transition: opacity 0.1s;
}

.kebab-item.active .kebab-check-icon {
    opacity: 1;
}

/* Toggle item variant: label row with a checkbox/control on the right */
.kebab-item-toggle {
    justify-content: space-between;
    gap: var(--sp-3);
    cursor: pointer;
}

.kebab-item-toggle > span {
    display: inline-flex;
    align-items: center;
    gap: 10px;
}

.kebab-item-toggle i {
    color: inherit;
}

.kebab-item-toggle input[type="checkbox"] {
    flex-shrink: 0;
    cursor: pointer;
    --checkbox-color: var(--success-color);
}

/* Collapsible "Location" row inside the mobile kebab — the branch list lives in
   .mobile-loc-body and is toggled open via the caret. */
.mobile-loc-toggle {
    justify-content: space-between;
    width: 100%;
}

.mobile-loc-caret {
    transition: var(--transition);
}

.mobile-loc-toggle.open .mobile-loc-caret {
    transform: rotate(180deg);
}

/* ===== Buttons ===== */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    height: 32px;
    padding: 0 var(--sp-4);
    border-radius: var(--radius-sm);
    font-size: var(--fs-sm);
    font-weight: 500;
    line-height: 1;
    text-decoration: none;
    border: 1px solid transparent;
    cursor: pointer;
    transition: var(--transition);
    letter-spacing: 0.01em;
    box-sizing: border-box;
}

.btn i {
    font-size: var(--fs-sm);
    line-height: 1;
}

.btn i::before {
    vertical-align: 0;
}

/* Disabled state — overrides variant colours and their :hover so a disabled
   button (e.g. a paused Sync) reads as clearly inert in both themes. */
.btn:disabled,
.btn[disabled],
.btn:disabled:hover,
.btn[disabled]:hover {
	background-color: var(--bg-tertiary);
	/* Strip the sheen too — a disabled button should read flat and inert. */
	background-image: none;
	color: var(--text-muted);
	border-color: var(--border-color);
	cursor: not-allowed;
	opacity: 0.65;
	box-shadow: none;
}

/* Solid variants carry the sheen so they read as raised. Ghost/outline/link
   variants are deliberately excluded — a gradient over a transparent fill just
   reads as a smudge (outline buttons pick it up on :hover, once filled). */
.btn-primary,
.btn-success,
.btn-danger,
.btn-warning,
.btn-info,
.btn-purple,
.btn-save {
	background-image: var(--sheen);
}

.btn-primary {
    background-color: var(--primary-color);
    color: var(--text-on-color);
}

.btn-primary:hover {
    background-color: var(--primary-hover);
	box-shadow: 0 2px 6px rgba(var(--primary-rgb), 0.20);
}

.btn-success {
    background-color: var(--success-color);
    color: var(--text-on-color);
}

.btn-success:hover {
	background-color: var(--success-hover);
	box-shadow: 0 2px 6px rgba(var(--success-rgb), 0.20);
}

.btn-danger {
    background-color: var(--danger-color);
    color: var(--text-on-color);
}

.btn-danger:hover {
    background-color: var(--danger-hover);
	box-shadow: 0 2px 6px rgba(var(--danger-rgb), 0.20);
}

.btn-warning {
    background-color: var(--warning-color);
	color: var(--text-on-color);
}

.btn-warning:hover {
    background-color: var(--warning-hover);
	box-shadow: 0 2px 6px rgba(var(--warning-rgb), 0.20);
}

.btn-info {
	background-color: var(--info-color);
	color: var(--text-on-color);
}

.btn-info:hover {
	background-color: var(--info-hover);
	box-shadow: 0 2px 6px rgba(var(--info-rgb), 0.20);
}

.btn-purple {
	background-color: var(--purple-color);
	color: var(--text-on-color);
}

.btn-purple:hover {
	background-color: var(--purple-hover);
	box-shadow: 0 2px 6px rgba(var(--purple-rgb), 0.20);
}

.btn-secondary {
    background-color: var(--bg-tertiary);
	background-image: var(--sheen-neutral);
    color: var(--text-primary);
    border-color: var(--border-color);
}

.btn-secondary:hover {
    background-color: var(--bg-hover);
    border-color: var(--text-muted);
}

/* Ghost Button (minimal, for icon actions) */
.btn-ghost {
    background: transparent;
    color: var(--text-secondary);
    border: none;
    padding: var(--sp-2) var(--sp-3);
}

.btn-ghost:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
}

/* Ghost variants that carry a semantic colour (transparent, coloured text, subtle hover) */
.btn-ghost-primary,
.btn-ghost-success,
.btn-ghost-warning,
.btn-ghost-danger,
.btn-ghost-info,
.btn-ghost-purple {
	background: transparent;
	border: none;
	padding: var(--sp-2) var(--sp-3);
}

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

.btn-ghost-success {
	color: var(--success-color);
}

.btn-ghost-warning {
	color: var(--warning-color);
}

.btn-ghost-danger {
	color: var(--danger-color);
}

.btn-ghost-info {
	color: var(--info-color);
}

.btn-ghost-purple {
	color: var(--purple-color);
}

.btn-ghost-primary:hover {
	background: var(--primary-subtle);
}

.btn-ghost-success:hover {
	background: var(--success-subtle);
}

.btn-ghost-warning:hover {
	background: var(--warning-subtle);
}

.btn-ghost-danger:hover {
	background: var(--danger-subtle);
}

.btn-ghost-info:hover {
	background: var(--info-subtle);
}

.btn-ghost-purple:hover {
	background: var(--purple-subtle);
}

/* Link-style button (transparent, primary, underline on hover) */
.btn-link {
	background: transparent;
	color: var(--primary-color);
	border: none;
	padding: var(--sp-2) var(--sp-3);
}

.btn-link:hover {
	color: var(--primary-hover);
	text-decoration: underline;
}

/* Icon-only button: square, no text padding (pair with a colour variant, e.g. .btn-ghost) */
.btn-icon {
	width: 32px;
	padding: 0;
	flex-shrink: 0;
}

/* Outline Button Variants */
/* Once an outline button fills on :hover it's a solid button, so it takes the
   same sheen as the solid variants rather than flattening out. */
.btn-outline-primary:hover,
.btn-outline-success:hover,
.btn-outline-danger:hover,
.btn-outline-warning:hover,
.btn-outline-info:hover {
	background-image: var(--sheen);
}

.btn-outline-secondary:hover {
	background-image: var(--sheen-neutral);
}

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

.btn-outline-primary:hover {
    background-color: var(--primary-color);
    color: var(--text-on-color);
	box-shadow: 0 2px 6px rgba(var(--primary-rgb), 0.18);
}

.btn-outline-success {
    background-color: transparent;
    color: var(--success-color);
    border-color: var(--success-color);
}

.btn-outline-success:hover {
    background-color: var(--success-color);
    color: var(--text-on-color);
	box-shadow: 0 2px 6px rgba(var(--success-rgb), 0.18);
}

.btn-outline-secondary {
    background-color: transparent;
    color: var(--text-secondary);
    border-color: var(--border-color);
}

.btn-outline-secondary:hover {
    background-color: var(--bg-tertiary);
    color: var(--text-primary);
    border-color: var(--text-secondary);
}

.btn-outline-danger {
    background-color: transparent;
    color: var(--danger-color);
    border-color: var(--danger-color);
}

.btn-outline-danger:hover {
    background-color: var(--danger-color);
    color: var(--text-on-color);
	box-shadow: 0 2px 6px rgba(var(--danger-rgb), 0.18);
}

.btn-outline-warning {
    background-color: transparent;
    color: var(--warning-color);
    border-color: var(--warning-color);
}

.btn-outline-warning:hover {
    background-color: var(--warning-color);
    color: #1a1d24;
	box-shadow: 0 2px 6px rgba(var(--warning-rgb), 0.18);
}

.btn-outline-info {
	background-color: transparent;
	color: var(--info-color);
	border-color: var(--info-color);
}

.btn-outline-info:hover {
	background-color: var(--info-color);
	color: var(--text-on-color);
	box-shadow: 0 2px 6px rgba(var(--info-rgb), 0.18);
}

.btn-cancel {
    padding: var(--sp-2) var(--sp-5);
    background: transparent;
    color: var(--text-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    font-size: var(--fs-md);
    cursor: pointer;
    transition: all 0.2s;
}

.btn-cancel:hover {
    border-color: var(--text-primary);
    color: var(--text-primary);
}

.btn-save {
    padding: var(--sp-2) var(--sp-5);
	/* background-color, not the `background` shorthand — the shorthand would
	   wipe the --sheen background-image set above. */
	background-color: var(--success-color);
    color: var(--text-on-color);
    border: none;
    border-radius: var(--radius-sm);
    font-size: var(--fs-md);
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
}

.btn-save:hover {
	background-color: var(--success-hover);
}

.btn-save:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.btn-sm {
    height: 32px;
    padding: 0 var(--sp-3);
    font-size: var(--fs-sm);
}

/* Inline/in-table button — sits inside a row without setting its height. */
.btn-xs {
	height: 24px;
	padding: 0 var(--sp-2);
	font-size: var(--fs-sm);
	gap: var(--sp-1);
}

.btn-xs i {
	font-size: var(--fs-sm);
}

/* ===== Attention Pulse ===== */
@keyframes pulse-primary {
    0%, 100% {
		box-shadow: 0 0 0 0 rgba(var(--primary-rgb), 0.5);
    }

    50% {
		box-shadow: 0 0 0 8px rgba(var(--primary-rgb), 0);
    }
}

@keyframes pulse-success {
    0%, 100% {
		box-shadow: 0 0 0 0 rgba(var(--success-rgb), 0.5);
    }

    50% {
		box-shadow: 0 0 0 8px rgba(var(--success-rgb), 0);
    }
}

@keyframes pulse-danger {
    0%, 100% {
		box-shadow: 0 0 0 0 rgba(var(--danger-rgb), 0.5);
    }

    50% {
		box-shadow: 0 0 0 8px rgba(var(--danger-rgb), 0);
    }
}

@keyframes pulse-warning {
    0%, 100% {
		box-shadow: 0 0 0 0 rgba(var(--warning-rgb), 0.5);
    }

    50% {
		box-shadow: 0 0 0 8px rgba(var(--warning-rgb), 0);
    }
}

.btn-pulse-primary {
    animation: pulse-primary 2s ease-in-out infinite;
}

.btn-pulse-success {
    animation: pulse-success 2s ease-in-out infinite;
}

.btn-pulse-danger {
    animation: pulse-danger 2s ease-in-out infinite;
}

.btn-pulse-warning {
    animation: pulse-warning 2s ease-in-out infinite;
}

.btn-pulse-primary:hover,
.btn-pulse-success:hover,
.btn-pulse-danger:hover,
.btn-pulse-warning:hover {
    animation: none;
}

/* ===== Utility Classes ===== */
.hidden,
.d-none {
    display: none !important;
}

/* ===== Forms ===== */
.form-label,
label {
    display: block;
    font-weight: 500;
    color: var(--text-primary);
}

.form-control,
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="search"],
input[type="file"],
textarea,
select {
    width: 100%;
    padding: 6px 8px;
    background-color: var(--bg-input);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font-size: var(--fs-md);
    line-height: inherit;
    transition: var(--transition);
}

.form-control:focus,
input:focus,
textarea:focus,
select:focus {
    outline: none;
    border-color: var(--primary-color);
    box-shadow: 0 0 0 1px var(--primary-color);
}

input::placeholder,
textarea::placeholder {
    color: var(--text-muted);
}

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

input[type="number"] {
    appearance: none;
    -moz-appearance: textfield;
}

/* ===== Checkboxes (site-wide custom style) ===== */
/* Override per instance by setting --checkbox-color (e.g. success green). */
input[type="checkbox"] {
    --checkbox-color: var(--primary-color);
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    flex-shrink: 0;
    width: 16px;
    height: 16px;
    margin: 0;
    padding: 0;
    cursor: pointer;
    border: 1.5px solid var(--border-color);
    border-radius: var(--radius-xs);
    background: var(--bg-input);
    display: inline-block;
    vertical-align: middle;
    position: relative;
    box-shadow: none;
    transition: background 0.15s, border-color 0.15s;
}

input[type="checkbox"]:hover {
    border-color: var(--checkbox-color);
}

input[type="checkbox"]:checked,
input[type="checkbox"]:indeterminate {
    background: var(--checkbox-color);
    border-color: var(--checkbox-color);
}

input[type="checkbox"]:checked::after {
    content: '';
    position: absolute;
    left: 50%;
    top: 50%;
    width: 4px;
    height: 8px;
    border: solid var(--text-on-color);
    border-width: 0 2px 2px 0;
    transform: translate(-50%, -55%) rotate(45deg);
}

input[type="checkbox"]:indeterminate::after {
    content: '';
    position: absolute;
    left: 50%;
    top: 50%;
    width: 8px;
    height: 2px;
    background: var(--text-on-color);
    transform: translate(-50%, -50%);
}

input[type="checkbox"]:focus-visible {
    outline: 2px solid var(--checkbox-color);
    outline-offset: 2px;
}

input[type="checkbox"]:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* ===== Site-wide ± qty stepper ===== */
.qty-stepper-input {
    display: inline-flex;
    align-items: stretch;
    width: 102px;
    min-width: 92px;
    height: 28px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    overflow: hidden;
    vertical-align: middle;
    transition: border-color 0.2s ease;
}

/* Focus highlights the whole pill, not the inner input — this is what keeps
   the − input + reading as one control instead of three divided segments. */
.qty-stepper-input:focus-within {
	border-color: var(--primary-color);
}

/* Center stepper pills when placed directly inside a table cell */
td > .qty-stepper-input {
    display: flex;
    margin: 0 auto;
}

.qty-step-btn {
    width: 26px;
    border: none;
    background: transparent;
    color: var(--primary-color);
    cursor: pointer;
    font-size: var(--fs-md);
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    flex-shrink: 0;
    user-select: none;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.qty-stepper-input .qty-step-btn:hover {
    background: var(--bg-hover);
    color: var(--primary-hover);
}

/* Any input inside the pill (incl. Django `.form-control` widgets) renders
   borderless/transparent so the − input + reads as one joined pill, not three
   separate boxes. `.qty-stepper-input input` (0,1,1) beats a bare `.form-control`. */
.qty-stepper-input input,
.qty-step-value {
    flex: 1 1 auto;
    min-width: 30px;
    width: auto;
    border: none;
    background: transparent;
    color: var(--text-primary);
    text-align: center;
    font-size: var(--fs-md);
    font-weight: 400;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.01em;
    padding: 0 2px;
    outline: none;
    box-shadow: none;
    -moz-appearance: textfield;
    appearance: textfield;
}

/* Suppress the global input focus ring/border inside the pill — the pill's own
   :focus-within handles the focus affordance. Beats `input:focus` on specificity. */
.qty-stepper-input input:focus,
.qty-stepper-input .qty-step-value:focus {
	border: none;
	box-shadow: none;
	outline: none;
}

.qty-stepper-input input::-webkit-inner-spin-button,
.qty-stepper-input input::-webkit-outer-spin-button,
.qty-step-value::-webkit-inner-spin-button,
.qty-step-value::-webkit-outer-spin-button {
    -webkit-appearance: none !important;
    margin: 0 !important;
    display: none !important;
}

/* ===== Tables =====
   `.table` is the one canonical data table for the whole site. Page CSS should
   only ever add column widths, max-heights and genuinely page-unique cells on
   top of it — never restyle the base (padding, colours, borders, hover). If a
   table needs to look different, use a modifier below or add one here. */

/* Scroll container — pair with .table when the table can overflow. */
.table-wrap {
	overflow-x: auto;
	border: 1px solid var(--border-color);
	border-radius: var(--radius-sm);
	background-color: var(--bg-secondary);
}

/* Table already sits inside a .card (or another bordered panel), which supplies
   the edge — the wrapper only needs to own the scroll. Without this, pages hand-
   roll their own bare `overflow-x: auto` wrapper to avoid a double border. */
.table-wrap-flush {
	border: none;
	border-radius: 0;
	background-color: transparent;
}

.table {
    width: 100%;
    border-collapse: collapse;
    background-color: var(--bg-secondary);
    overflow: hidden;
}

.table thead th {
    background-color: var(--bg-tertiary);
    padding: var(--sp-2) var(--sp-3);
    text-align: left;
    font-weight: 600;
    text-transform: uppercase;
	/* fs-sm / 0.05em is what 38 of the site's 42 tables already used before
	   they were consolidated here — this is the established convention. */
	font-size: var(--fs-sm);
	letter-spacing: 0.05em;
    border-bottom: 1px solid var(--border-color);
    color: var(--text-secondary);
	white-space: nowrap;
}

.table tbody tr {
    border-bottom: 1px solid var(--border-color);
    transition: var(--transition);
}

/* Zebra striping — aids row scanning on data tables (hover rule below wins) */
.table tbody tr:nth-child(even) {
    background-color: var(--bg-zebra);
}

/* Opt out of automatic striping when not every <tr> is a data row — expandable
   detail rows, category/section headers, etc. `:nth-child` counts those too, so
   the parity lands on the wrong rows (a table of data+detail pairs stripes only
   the hidden detail rows, i.e. looks unstriped). Add `.table-zebra-manual` and
   let the template tag its data rows with `.zebra-row`, which knows which rows
   actually count. Declared above `:hover` on purpose so hover still wins.

   Child combinators, not descendants: a sub-table nested in a detail row is its
   own `.table` and must keep automatic striping rather than inherit the opt-out. */
.table-zebra-manual > tbody > tr:nth-child(even) {
	background-color: transparent;
}

.table-zebra-manual > tbody > tr.zebra-row {
	background-color: var(--bg-zebra);
}

.table tbody tr:hover {
    background-color: var(--bg-hover);
}

.table tbody td {
    padding: var(--sp-2) var(--sp-3);
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
	vertical-align: middle;
}

.table tbody tr:last-child {
	border-bottom: none;
}

/* --- Table modifiers ------------------------------------------------ */

/* Compact rows. */
.table-sm td,
.table-sm th {
    padding: var(--sp-1) var(--sp-2);
}

/* Header stays put while the body scrolls (needs a height-bounded wrapper). */
.table-sticky thead th {
	position: sticky;
	top: 0;
	z-index: 1;
}

/* No row separators — for dense sub-tables and breakdowns. */
.table-flush tbody tr {
	border-bottom: none;
}

/* Column widths honoured exactly; pair with explicit th widths. */
.table-fixed {
	table-layout: fixed;
}

/* --- Mobile: wide data tables scroll instead of breaking the layout ------ */
/* Dense tables have far more columns than a phone is wide. Rather than let them
   squash to unreadable or force the whole page sideways, each table (or its
   scroll wrapper) becomes its own horizontal scroll area. */

/* ===== Badges ===== */
.badge {
    display: inline-block;
    padding: var(--sp-1) var(--sp-3);
    border-radius: var(--radius-pill);
    font-size: var(--fs-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    border: 1px solid;
}

.badge-primary {
    background-color: var(--primary-subtle);
    color: var(--primary-color);
}

.badge-success {
    background-color: var(--success-subtle);
    color: var(--success-color);
}

.badge-warning {
    background-color: var(--warning-subtle);
    color: var(--warning-color);
}

.badge-danger {
    background-color: var(--danger-subtle);
    color: var(--danger-color);
}

.badge-info {
	background-color: var(--info-subtle);
	color: var(--info-color);
}

.badge-purple {
	background-color: var(--purple-subtle);
	color: var(--purple-color);
}

.badge-neutral {
	background-color: var(--bg-tertiary);
	color: var(--text-secondary);
}

/* Compact size modifier — pairs with .badge (mirrors .table-sm). */
.badge-sm {
	padding: 2px 8px;
	font-size: var(--fs-sm);
}

/* ===== Alerts ===== */
.alert {
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--radius-sm);
    margin-bottom: var(--sp-4);
    border-left: 3px solid;
}

.alert-info {
    background-color: var(--info-subtle);
    border-color: var(--info-color);
    color: var(--text-primary);
}

.alert-warning {
    background-color: var(--warning-subtle);
    border-color: var(--warning-color);
    color: var(--text-primary);
}

.alert-danger {
    background-color: var(--danger-subtle);
    border-color: var(--danger-color);
}

.alert-success {
    background-color: var(--success-subtle);
    border-color: var(--success-color);
}

/* ===== Modal ===== */
/* Full-screen flex container — always TOP-aligned, scrolls when tall.
   Both the wrapper-style modal (.modal) and the standalone overlay
   (.modal-overlay) share the same alignment so every modal in the app
   behaves identically. */
.modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 2000;
    align-items: flex-start;
    justify-content: center;
    padding: var(--modal-offset) 16px;
    overflow-y: auto;
}

.modal.show {
    display: flex !important;
}

.modal.active {
    display: flex !important;
}

/* Lock background scrolling while a modal is open */
body:has(.modal.show),
body:has(.modal.active),
body:has(.modal-overlay.active) {
    overflow: hidden;
}

/* When overlay is inside .modal, it's just a backdrop behind the dialog */
.modal > .modal-overlay {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.40);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    z-index: -1;
}

/* Standalone overlay (used as the modal wrapper on most pages).
   Top-aligned + blurred backdrop, matching .modal above. */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.40);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    z-index: 10000;
    display: none;
    align-items: flex-start;
    justify-content: center;
    padding: var(--modal-offset) 16px;
    overflow-y: auto;
}

.modal-overlay.active {
    display: flex;
}

/* ===== Native <dialog> element centering ===== */
dialog {
    margin: auto;
    max-height: 90vh;
    overflow-y: auto;
}

dialog::backdrop {
    background: rgba(0, 0, 0, 0.5);
}

.modal-dialog {
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    width: 760px;
    max-width: 90vw;
    max-height: 90vh;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    position: relative;
}

.modal-dialog .modal-content {
    border: none;
    box-shadow: none;
    margin: 0;
    max-width: none;
    border-radius: 0;
}

/* Modal content used directly inside a flex modal: no auto vertical margins */
.modal > .modal-content {
    margin-top: 0;
    margin-bottom: 0;
}

.modal-content {
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    box-sizing: border-box;
    width: 100%;
    margin: 0 auto;
    max-width: 1000px;
    max-height: var(--modal-max-h);
    display: flex;
    flex-direction: column;
    position: relative;
}

/* ===== Standard modal sizes (set via class on .modal-content) =====
   Use one of these on the content element to control width. */
.modal--sm {
    width: 100%;
    max-width: 480px;
}

.modal--md {
    width: 100%;
    max-width: 720px;
}

.modal--lg {
    width: 100%;
    max-width: 1000px;
}

.modal-content-csv-table {
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    margin: 32px auto;
    max-width: 1200px;
    position: relative;
}

/* .modal-box + .modal-header h2 consolidated here from per-page CSS */
.modal-box {
	background: var(--bg-primary);
	border: 1px solid var(--border-color);
	border-radius: var(--radius-md);
	width: 520px;
	max-width: 95vw;
	max-height: 90vh;
	overflow-y: auto;
	box-shadow: var(--shadow-lg);
}

.modal-header {
    padding: var(--sp-4) var(--sp-5);
    border-bottom: 1px solid var(--border-color);
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.modal-header h3 {
    margin: 0;
    font-size: var(--fs-2xl);
}

.modal-header h2 {
	margin: 0;
	font-size: var(--fs-xl);
	display: flex;
	align-items: center;
	gap: var(--sp-2);
}

.modal-close {
    background: none;
    border: none;
    font-size: var(--fs-4xl);
    line-height: 1;
    color: var(--text-secondary);
    cursor: pointer;
    padding: 0;
    width: 30px;
    height: 30px;
}

.modal-close:hover {
    color: var(--text-primary);
}

.modal-body {
    padding: var(--sp-5);
    overflow-y: auto;
    flex: 1 1 auto;
}

.modal-footer {
    padding: var(--sp-4) var(--sp-5);
    border-top: 1px solid var(--border-color);
    display: flex;
    justify-content: flex-end;
    gap: var(--sp-3);
}

.login-container form p,
.login-container form .form-group {
    display: flex;
    flex-direction: column;
    margin-bottom: var(--sp-4);
}

.login-container form p label,
.login-container form .form-group label {
    margin-bottom: var(--sp-2);
    font-weight: 500;
}

.login-container form p input,
.login-container form p select,
.login-container form p textarea,
.login-container form .form-group input {
    padding: var(--sp-3);
    background-color: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    color: var(--text-primary);
}

.login-container .btn-primary {
    width: 100%;
    padding: var(--sp-3);
    margin-top: var(--sp-3);
}

/* ===== Utility Classes ===== */
.field-div {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

/* Alignment utilities. `!important` is deliberate: these are explicit opt-in
   overrides applied at the call site, so they must beat component rules. */
.text-center {
	text-align: center !important;
}

.text-right {
	text-align: right !important;
}

.text-left {
	text-align: left !important;
}

/* ===== Global helper utilities =====
   Single-purpose classes so pages stop redefining the same rule. Semantic
   text colours pair with the design tokens; layout helpers cover the handful
   of one-liners that were duplicated across dozens of feature sheets.

   The semantic colours carry `!important` on purpose: `.table tbody td` (0,1,2)
   outranks a bare utility class (0,1,0), so without it a `<td class="text-danger">`
   silently renders as body text. Pages were each re-declaring these with their
   own `!important` to work around it — this is that fix, done once. */
.text-accent {
	color: var(--primary-color) !important;
}

.text-success {
	color: var(--success-color) !important;
}

.text-danger {
	color: var(--danger-color) !important;
}

.text-warning {
	color: var(--warning-color) !important;
}

.text-info {
	color: var(--info-color) !important;
}

.text-secondary {
	color: var(--text-secondary);
}

/* .text-muted already defined above */

.flex-1 {
	flex: 1;
}

.w-full {
	width: 100%;
}

.nowrap {
	white-space: nowrap;
}

/* Ellipsis-truncate an inline cell/label. Pair with title="" for the full text.
   Replaces the per-page max-width+ellipsis cell classes features used to define. */
.truncate {
	display: inline-block;
	max-width: 200px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	vertical-align: middle;
}

/* House style for a link inside a data table (identifiers, references, names) —
   replaces the bespoke cell-link class each feature used to define. Opt-in, so
   it never disturbs links that carry their own styling. */
.table-link,
.table-link:visited {
	color: var(--primary-color);
	text-decoration: none;
	font-weight: 600;
}

.table-link:hover {
	color: var(--primary-hover);
	text-decoration: underline;
}

.cursor-pointer {
	cursor: pointer;
}

.overflow-x-auto {
	overflow-x: auto;
}

/* ===== Sidebar Toggle Button (top bar) ===== */
.mobile-hamburger {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border: none;
    background: none;
    color: var(--text-primary);
    font-size: var(--fs-3xl);
    cursor: pointer;
    border-radius: var(--radius-sm);
    transition: var(--transition);
    margin-right: var(--sp-2);
    flex-shrink: 0;
}

.mobile-hamburger:hover {
	background: var(--bg-hover);
}

.mobile-menu-close-icon {
    display: none;
}

/* ===== Mobile-only top-bar controls ===== */
/* On mobile the top bar collapses to a search icon + a kebab; the theme toggle,
   profile menu and notification bell fold into the kebab dropdown. These are
   display:none on desktop and revealed in the ≤1080px media query below. */
.mobile-topbar-only {
	display: none;
}

.mobile-topbar-btn {
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	border: none;
	background: none;
	color: var(--text-primary);
	font-size: var(--fs-2xl);
	cursor: pointer;
	border-radius: var(--radius-sm);
	transition: var(--transition);
	flex-shrink: 0;
}

.mobile-topbar-btn:hover {
	background: var(--bg-hover);
}

/* Count pill for a kebab item (e.g. "Orders to check") */
.kebab-badge {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 20px;
	height: 20px;
	margin-left: auto;
	padding: 0 6px;
	border-radius: var(--radius-pill);
	background: var(--warning-color);
	color: var(--text-on-color);
	font-size: var(--fs-xs);
	font-weight: 700;
	line-height: 1;
}

/* ===== Mobile Overlay ===== */
.mobile-overlay {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 999;
    opacity: 0;
    transition: opacity 0.3s ease;
}

.mobile-overlay.active {
    display: block;
    opacity: 1;
}

/* ===== Mobile Close Button (inside sidebar) ===== */
.mobile-nav-close {
    display: none;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border: none;
    background: none;
    color: var(--text-secondary);
    font-size: var(--fs-2xl);
    cursor: pointer;
    border-radius: var(--radius-sm);
    transition: var(--transition);
}

.mobile-nav-close:hover {
	background: var(--bg-hover);
    color: var(--text-primary);
}

/* ===== Responsive Design ===== */

/* ===== Scrollbar Styling =====
   Two rendering engines to cover. Blink/WebKit honours the ::-webkit-scrollbar
   pseudo-elements; Firefox ignores them entirely and would otherwise fall back
   to the full-width native OS scrollbar (~17px on Windows), which is where the
   oversized bars come from. Firefox reads the standard scrollbar-* properties
   instead — but declaring those unconditionally would make Chrome drop the
   pseudo-element styling and switch to its own (thicker) native thin bar, so
   they're fenced behind @supports and only reach engines with no
   ::-webkit-scrollbar support. */
::-webkit-scrollbar {
	width: var(--scrollbar-size);
	height: var(--scrollbar-size);
}

/* Transparent track: the bar then reads as a thin thumb floating over whatever
   surface it's on, rather than a full-height stripe in a fixed colour that
   looks wrong over cards/modals that aren't --bg-primary. */
::-webkit-scrollbar-track {
	background: transparent;
}

::-webkit-scrollbar-thumb {
	background: var(--scrollbar-thumb);
	border-radius: var(--radius-sm);
}

::-webkit-scrollbar-thumb:hover {
	background: var(--scrollbar-thumb-hover);
}

/* Where a vertical and horizontal bar meet — otherwise a native grey square. */
::-webkit-scrollbar-corner {
	background: transparent;
}

/* Firefox-only. -moz-appearance is a Firefox alias with no Blink/WebKit
   equivalent, so this block is invisible to Chrome/Edge/Safari — they keep the
   8px pseudo-element bars above. (Don't swap this for
   `@supports not selector(::-webkit-scrollbar)`: engines disagree on whether an
   unimplemented pseudo-element makes selector() false, so it can silently match
   nowhere — or match in Chrome and downgrade it to a thicker native bar.) */
@supports (-moz-appearance: none) {
	/* scrollbar-width doesn't inherit, so it has to be set on every element that
	   can scroll rather than just on :root. */
	* {
		scrollbar-width: thin;
		scrollbar-color: var(--scrollbar-thumb) transparent;
	}
}

/* ===== Page Header ===== */
.page-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: var(--sp-6);
}

.page-header h1 {
    font-size: var(--fs-4xl);
    font-weight: 600;
    margin: 0;
}

/* ===== Toolbar =====
   The row of controls that sits above a table/board — search, filters, view
   switcher on the left, actions on the right. Every feature was hand-rolling
   this same flex row under its own prefix; use these instead.

     <div class="toolbar">
       <input class="form-control" …>
       <div class="toolbar-actions"><button class="btn btn-primary">…</button></div>
     </div>

   .toolbar-actions carries margin-left:auto, so it pins right without the
   parent needing justify-content. */
.toolbar {
	display: flex;
	align-items: center;
	gap: var(--sp-3);
	margin-bottom: var(--sp-3);
	flex-wrap: wrap;
}

.toolbar-actions {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	margin-left: auto;
	flex-shrink: 0;
	flex-wrap: wrap;
}

/* Title on the left, a single control on the right, nothing in between. Use
   this instead of wrapping one lone button in a .toolbar-actions div. */
.toolbar-spread {
	justify-content: space-between;
}

/* Toolbar sharing a row with something else (e.g. type tabs): grows to fill the
   remaining width and drops its own bottom margin. */
.toolbar-inline {
	flex: 1;
	min-width: 0;
	margin-bottom: 0;
}

/* Toolbar sitting flush inside a card/panel header rather than above it. */
.toolbar-flush {
	margin-bottom: 0;
	padding: var(--sp-2) var(--sp-3);
	border-bottom: 1px solid var(--border-color);
}

/* ===== Period Navigator =====
   Prev / current-period / next, used by any page that pages through weeks or
   months (fitter schedule, timesheets, fit board, material report). The arrows
   are ordinary .btn .btn-icon buttons — square and --radius-sm like every other
   control on the site, deliberately NOT circles.

     <div class="period-nav">
       <a class="btn btn-icon btn-secondary" …><i class="bi bi-chevron-left"></i></a>
       <div class="period-nav-label">
         <span class="period-nav-range">05 May – 11 May 2026</span>
         <span class="period-nav-meta">This week</span>
       </div>
       <a class="btn btn-icon btn-secondary" …><i class="bi bi-chevron-right"></i></a>
     </div> */
.period-nav {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--sp-2);
	padding: var(--sp-2);
	background: var(--bg-secondary);
	border: 1px solid var(--border-color);
	border-radius: var(--radius-md);
	margin-bottom: var(--sp-4);
}

.period-nav-label {
	text-align: center;
	min-width: 0;
}

.period-nav-range {
	display: block;
	font-weight: 700;
	font-size: var(--fs-lg);
}

/* Sub-line under the range: either inert context ("This week") or a link back
   to the current period. */
.period-nav-meta {
	color: var(--text-muted);
	font-size: var(--fs-sm);
}

.period-nav-reset {
	color: var(--primary-color);
	font-size: var(--fs-sm);
	font-weight: 600;
	text-decoration: none;
}

.period-nav-reset:hover {
	text-decoration: underline;
}

/* Inline variant — no panel, for a nav that already sits inside a toolbar. */
.period-nav-inline {
	padding: 0;
	background: none;
	border: 0;
	border-radius: 0;
	margin-bottom: 0;
	gap: var(--sp-2);
}

/* ===== Stats Grid ===== */
.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--sp-5);
    margin-bottom: var(--sp-6);
}

.stats-card {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--sp-2) var(--sp-4);
}

.form-row {
    display: grid;
    grid-template-columns: 2fr 1.5fr 1.5fr auto;
    gap: var(--sp-4);
    align-items: end;
}

.tab-nav {
    display: flex;
    gap: var(--sp-2);
    border-bottom: 2px solid var(--border-color);
    background-color: transparent;
}

.tab-button {
    padding: 8px 22px;
    background: none;
    border: 1px solid transparent;
    border-bottom: none;
    color: var(--text-secondary);
    cursor: pointer;
    font-weight: 500;
    font-size: var(--fs-md);
    transition: all 0.15s;
    margin-bottom: -2px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    white-space: nowrap;
    text-decoration: none;
}

.tab-button:hover {
    background-color: var(--bg-secondary);
	background-image: var(--sheen-neutral);
    color: var(--text-primary);
}

.tab-button.active {
    color: var(--primary-color);
    background-color: var(--bg-primary);
	background-image: var(--sheen-neutral);
    border-color: var(--border-color);
    border-bottom-color: var(--bg-primary);
}

.tab-button .badge {
    font-size: var(--fs-sm);
    padding: 2px 8px;
}

/* Pill-style tab variant */
.tab-nav-pills {
    display: flex;
    gap: var(--sp-1);
    border-bottom: none;
	background-color: var(--bg-tertiary);
	background-image: var(--sheen-neutral);
    border-radius: var(--radius-lg);
}

.tab-nav-pills .tab-button {
    border: none;
    margin-bottom: 0;
    border-radius: var(--radius-md);
    padding: var(--sp-2) var(--sp-4);
    font-size: var(--fs-sm);
}

.tab-nav-pills .tab-button:hover {
    background-color: var(--bg-hover);
}

.tab-nav-pills .tab-button.active {
    background-color: var(--primary-color);
	background-image: var(--sheen);
    color: var(--text-on-color);
    box-shadow: var(--shadow-sm);
}

.tab-nav-pills[data-pill-slider] {
	position: relative;
	display: inline-flex;
	align-items: stretch;
	padding: 0;
	background-color: transparent;
	/* Transparent track — no sheen to paint (pages that re-add a solid tray
	   background, e.g. .it-location-tabnav, re-add the sheen with it). */
	background-image: none;
	border: none;
}

.tab-pill-thumb {
	position: absolute;
	/* Fills the active pill's full height (no inset) so the tint reads as a flat
	   highlight. Vertical variant re-pins bottom:auto and JS drives its height. */
	top: 0;
	bottom: 0;
	left: 0;
	z-index: 0;
	background-color: var(--primary-color);
	background-image: var(--sheen);
	/* Solid fill so the active label (--text-on-color) reads in both themes. */
	opacity: 1;
	border-radius: var(--radius-md);
	transition: var(--transition);
	pointer-events: none;
	box-shadow: var(--shadow-sm);
}

.tab-nav-pills[data-pill-slider] .tab-button {
	position: relative;
	z-index: 1;
	padding: var(--sp-2) var(--sp-4);
	font-size: var(--fs-md);
	border-radius: var(--radius-md);
	color: var(--text-secondary);
	background-color: transparent;
	/* Same weight on active and inactive so switching never reflows the row
	   (a weight change widens the glyphs and shoves neighbours / the thumb). */
	font-weight: 500;
	transition: background-color var(--transition), color var(--transition);
}

.tab-nav-pills[data-pill-slider] .tab-button:hover {
	background-color: var(--bg-hover);
	color: var(--text-primary);
}

/* The active label sits on the solid primary thumb, so it uses --text-on-color. */
.tab-nav-pills[data-pill-slider] .tab-button.active {
	background-color: transparent;
	/* The thumb behind this label carries the sheen — inheriting it here from
	   .tab-nav-pills .tab-button.active would paint a second gradient over a
	   transparent fill and read as a smudge on the label. */
	background-image: none;
	box-shadow: none;
	/* The solid primary thumb behind the label is the active affordance, so the
	   label just switches to --text-on-color. No weight change or faux-bold
	   text-shadow — those thickened the glyphs and read as strange/smeared. */
	color: var(--text-on-color);
}

/* ── Cross-page tab transition ────────────────────────────────────────────
   Tabs that navigate to another URL rather than swapping content in place
   (wired by window.initCrossPageTabs). .tab-swapping fades the outgoing
   content while the thumb slides; .tab-glide-in plays on the page being
   navigated to, so the pair reads like the in-page AJAX swap. */
.tab-swapping {
	opacity: 0.4;
	transition: var(--transition);
}

.tab-glide-in {
	animation: tabGlideIn 0.24s ease;
}

@keyframes tabGlideIn {
	from {
		opacity: 0;
		transform: translateY(6px);
	}

	to {
		opacity: 1;
		transform: translateY(0);
	}
}

/* ── Vertical pill tab column — .tab-nav-pills-vertical[data-pill-slider] ──
   Same sliding-thumb mechanism as the horizontal sales pills, stacked into a
   left-hand column. Here the CSS pins the thumb's left/right to the tray inset
   and the global pill-slider script drives its height + Y (mirror of the
   horizontal case, where CSS pins top/bottom and JS drives width + X). */
.tab-nav-pills-vertical {
	flex-direction: column;
	align-items: stretch;
}

.tab-nav-pills-vertical[data-pill-slider] {
	display: flex;
}

.tab-nav-pills-vertical .tab-button {
	width: 100%;
	justify-content: space-between;
	text-align: left;
	gap: var(--sp-3);
}

.tab-nav-pills-vertical[data-pill-slider] .tab-pill-thumb {
	left: calc(var(--sp-1) + 2px);
	right: calc(var(--sp-1) + 2px);
	top: 0;
	bottom: auto;
	width: auto;
}

.tab-content {
    padding: 0;
}

.tab-panel {
    display: none;
}

.tab-panel.active {
    display: flex;
    flex-direction: column;
    gap: var(--sp-6);
}

/* ===== Global Utilities ===== */
.icon-warning {
	color: var(--warning-color);
}

.required-star {
    color: var(--danger-color);
}

.modal-body .form-group {
    margin-bottom: var(--sp-4);
}

.modal-body .form-check {
    margin-bottom: var(--sp-2);
}

/* ===== Empty State ===== */
.empty-state {
    text-align: center;
    padding: 60px 20px;
    color: var(--text-secondary);
}

.empty-icon {
    font-size: var(--fs-4xl);
    margin-bottom: var(--sp-4);
    opacity: 0.4;
}

.empty-state p,
.empty-state-large p {
    margin: var(--sp-3) 0 var(--sp-5);
    color: var(--text-secondary);
}

/* ===== Responsive Grid ===== */

/* ===== Additional Styles ===== */
.errorlist {
    list-style: none;
    padding: 0;
    margin: 0;
    color: var(--danger-color);
}

.errorlist li {
    padding: var(--sp-1) 0;
    font-size: var(--fs-md);
}

.text-muted {
    color: var(--text-muted);
}

.checkbox-label {
    display: flex;
    align-items: center;
    margin: var(--sp-2) var(--sp-1) var(--sp-1) var(--sp-1);
}

#id_all_items_ordered,
#id_job_finished {
    height: 20px;
    width: 20px;
    margin-left: var(--sp-3);
}

#csv_file {
    margin-bottom: var(--sp-5);
}

.job-info-link {
	color: var(--text-on-color);
}

/* ===== Global Toast Notifications ===== */
.toast-container {
    position: fixed;
    top: 20px;
    right: 20px;
    z-index: 10000;
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-width: 400px;
    pointer-events: none;
}

.toast {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--radius-sm);
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    box-shadow: 0 4px 16px rgba(0,0,0,0.35);
    pointer-events: auto;
    opacity: 0;
    transform: translateX(30px);
    transition: opacity 0.3s ease, transform 0.3s ease;
}

.toast.toast-visible {
    opacity: 1;
    transform: translateX(0);
}

.toast.toast-hiding {
    opacity: 0;
    transform: translateX(30px);
}

.toast-success {
    border-left: 4px solid var(--success-color);
}

.toast-error,
.toast-danger {
    border-left: 4px solid var(--danger-color);
}

.toast-warning {
    border-left: 4px solid var(--warning-color);
}

.toast-info {
    border-left: 4px solid var(--primary-color);
}

.toast-text {
    flex: 1;
}

.toast-copy,
.toast-close {
    background: none;
    border: none;
    color: var(--text-secondary);
    font-size: var(--fs-lg);
    cursor: pointer;
    padding: 0 2px;
    line-height: 1;
}

.toast-copy {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.5rem;
}

.toast-copy:hover,
.toast-close:hover {
    color: var(--text-primary);
}

.toast-copy-success {
    color: var(--success-color);
}

/* ── Search input (canonical, app-wide) ────────────────────────────────────
   The single search-bar component. A flex wrapper holding a Bootstrap search
   icon and a borderless input. Pages that need a different radius (pill) or a
   fixed/max width override just those properties on their own scoped selector
   — the look, focus outline, icon and placeholder all come from here.
     <div class="search-input-wrapper">
       <i class="bi bi-search"></i>
       <input type="text" placeholder="…">
     </div>                                                                   */
.search-input-wrapper {
	position: relative;
	display: flex;
	align-items: center;
	flex: 1;
	min-width: 0;
	gap: var(--sp-2);
	background: var(--bg-secondary);
	border: 1px solid var(--border-color);
	border-radius: var(--radius-md);
	padding: 0 var(--sp-3);
	transition: border-color var(--transition);
}

.search-input-wrapper:focus-within {
	/* Solid blue outline only — no glow/shadow. */
	border-color: var(--primary-color);
}

/* gap on the wrapper spaces the icon, input and any inline clear button. */
.search-input-wrapper i {
	color: var(--text-secondary);
	flex-shrink: 0;
}

.search-input-wrapper input {
	flex: 1;
	min-width: 0;
	border: none;
	background: none;
	padding: var(--sp-2) 0;
	font-size: var(--fs-md);
	color: var(--text-primary);
	width: 100%;
	outline: none;
}

/* The wrapper shows the focus outline via :focus-within, so suppress the
   input's own focus ring to avoid a doubled outline inside the rounded box. */
.search-input-wrapper input:focus {
	box-shadow: none;
}

.search-input-wrapper input::placeholder {
	color: var(--text-muted);
}

/* Inline clear button/link, rendered as the last child of the wrapper so the
   wrapper's gap spaces it. Works as <button> or <a>; add hidden/`display:none`
   from the page when it is only shown while a query is active.
     <button type="button" class="search-clear" title="Clear search">&times;</button> */
.search-clear {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	border: none;
	background: none;
	padding: 0 var(--sp-1);
	color: var(--text-secondary);
	font-size: var(--fs-2xl);
	line-height: 1;
	text-decoration: none;
	cursor: pointer;
}

/* Author-set display beats the UA [hidden] rule, so restore it explicitly. */
.search-clear[hidden] {
	display: none;
}

.search-clear:hover {
	color: var(--text-primary);
}

.entity-hero-header {
    padding: var(--sp-4);
    display: flex;
    align-items: center;
    gap: 0;
    flex-wrap: wrap;
}

/* Left: avatar + name/subtitle */
.entity-hero-identity {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-shrink: 0;
    padding-right: var(--sp-5);
    min-width: 180px;
}

.entity-hero-avatar {
    width: 46px;
    height: 46px;
    border-radius: var(--radius-round);
    background: var(--primary-color);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.entity-hero-avatar i {
    font-size: var(--fs-3xl);
	color: var(--text-on-color);
}

.entity-hero-identity-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.entity-hero-name {
    margin: 0;
    font-size: var(--fs-xl);
    font-weight: 700;
}

.entity-hero-name a {
    color: var(--text-primary);
    text-decoration: none;
}

.entity-hero-name a:hover {
    color: var(--primary-color);
    text-decoration: underline;
}

.entity-hero-since {
    font-size: var(--fs-sm);
    color: var(--text-secondary);
}

/* Middle: info columns (Phone | Email | Address) */
.entity-hero-cols {
    display: flex;
    gap: 0;
    flex: 1;
    flex-wrap: wrap;
    border-left: 1px solid var(--border-color);
    border-right: 1px solid var(--border-color);
}

.entity-hero-col {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 0 var(--sp-5);
    min-width: 140px;
}

.entity-hero-col + .entity-hero-col {
    border-left: 1px solid var(--border-color);
}

.entity-hero-col-label {
    font-size: var(--fs-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-secondary);
}

.entity-hero-col-value {
    font-size: var(--fs-md);
    color: var(--text-primary);
    white-space: nowrap;
}

.entity-hero-col-email {
    max-width: 200px;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Right status block and action buttons are now separate flex items */
.entity-hero-status-block {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-start;
    column-gap: 30px;
    row-gap: 6px;
    padding: 0 22px;
    border-left: 1px solid var(--border-color);
    flex-shrink: 0;
}

/* Each section: label stacked above its value, sections read left-to-right */
.entity-hero-status-row {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-1);
}

/* Smaller, squared-off status badge inside the hero bar */
.entity-hero-status-block .customer-active-badge {
    padding: 2px 8px;
    border-radius: var(--radius-sm);
    font-size: var(--fs-xs);
}

.entity-hero-updated {
    flex-basis: 100%;
    font-size: var(--fs-sm);
    color: var(--text-secondary);
    white-space: nowrap;
}

.entity-hero-actions {
    display: flex;
    gap: 6px;
    align-items: center;
    padding-left: var(--sp-4);
    border-left: 1px solid var(--border-color);
    flex-shrink: 0;
}

/* Save and cancel buttons are hidden until edit mode is toggled via JS */
.entity-hero-actions #btn-save,
.entity-hero-actions #btn-cancel {
    display: none;
}

.entity-hero-links {
    display: flex;
    gap: var(--sp-2);
    align-items: center;
    flex-wrap: wrap;
}

/* Copy-to-clipboard button inside hero card columns */
.entity-hero-copy-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    padding: var(--sp-1) var(--sp-1);
    font-size: var(--fs-sm);
    cursor: pointer;
    line-height: 1;
    transition: color 0.15s, border-color 0.15s, background-color 0.15s;
    flex-shrink: 0;
}

.entity-hero-copy-btn:hover {
    color: var(--text-primary);
    border-color: var(--text-secondary);
	background-color: var(--bg-hover);
}

.entity-hero-copy-btn.copied {
    color: var(--success-color);
    border-color: var(--success-color);
	background-color: rgba(var(--success-rgb), 0.1);
}

[data-theme="dark"] .entity-hero-copy-btn:hover {
	background-color: var(--bg-hover);
}

[data-theme="dark"] .entity-hero-copy-btn.copied {
	background-color: rgba(var(--success-rgb), 0.2);
}

.entity-hero-col-address {
    white-space: normal;
}

/* Value + copy button side by side */
.entity-hero-col-value-row {
    display: flex;
    align-items: center;
    gap: 6px;
}

/* "Show Details" toggle (replaces the "Customer Since" line on order/sale pages) */
.entity-hero-toggle {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: none;
    border: none;
    padding: 0;
    margin-top: 2px;
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--text-secondary);
    cursor: pointer;
    text-align: left;
}

.entity-hero-toggle:hover {
    color: var(--text-primary);
    text-decoration: underline;
}

.entity-hero-toggle i {
    font-size: var(--fs-sm);
    transition: transform 0.2s ease;
}

.entity-hero-details-menu.open .entity-hero-toggle i {
    transform: rotate(180deg);
}

/* Contact details popup (Phone | Email | multi-line Address) */
.entity-hero-details-dropdown {
    min-width: 240px;
    gap: var(--sp-1);
}

.entity-hero-detail-item {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 6px 8px;
}

.entity-hero-detail-item + .entity-hero-detail-item {
    border-top: 1px solid var(--border-color);
}

/* Multi-line address inside the popup */
.entity-hero-col-address-multiline {
    white-space: normal;
}

/* Status-block value rows (Fit Date, Value, Next Step) */
.entity-hero-status-val {
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--text-primary);
}

/* Stack the hero sections on narrow/cramped viewports so the vertical
   dividers between sections don't leave dangling borders when items wrap. */

/* =============================================
   Detail page component library
   Promoted from order_details.css, which had become the de-facto shared
   base for every entity detail page (sale, product, remedial, customer,
   OS doors). These names are detail-page-unique, so pages can now load
   just their own sheet on top of this base instead of pulling in the
   whole order_details.css.
   ============================================= */

/* ── Two-column detail layout ── */
.order-details-grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--sp-6);
}

.main-column {
	display: flex;
	flex-direction: column;
	gap: var(--sp-6);
	min-width: 0;
}

.sidebar-column {
	min-width: 0;
}

/* ── Info sections (grouped read-only fields inside a card) ── */
.info-section-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: var(--sp-3);
}

.info-section-title {
	margin: 0;
	font-size: var(--fs-lg);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.5px;
	border-bottom: 1px solid;
	padding-bottom: var(--sp-1);
	flex: 1;
}

/* Entity-type accents so a section reads as customer / sale / job at a glance */
.info-section-title.customer {
	color: var(--primary-color);
	border-bottom-color: var(--primary-color);
}

.info-section-title.sale {
	color: var(--success-color);
	border-bottom-color: var(--success-color);
}

.info-section-title.job {
	color: var(--warning-color);
	border-bottom-color: var(--warning-color);
}

.info-display {
	display: flex;
	flex-direction: column;
	gap: 6px;
}

/* ── Label / value field rows ── */
.field-label {
	font-size: var(--fs-sm);
	color: var(--text-secondary);
}

.field-value {
	font-size: var(--fs-md);
	color: var(--text-primary);
}

.field-value-large {
	font-size: var(--fs-md);
	font-weight: 600;
	color: var(--text-primary);
}

.field-row-with-button {
	display: flex;
	align-items: center;
	justify-content: space-between;
}

/* Small trailing link-out button (Anthill / Xero / etc.) */
.external-link-btn {
	padding: 2px 8px;
	font-size: var(--fs-sm);
	white-space: nowrap;
}

/* ── Payment milestone breakpoints ──
   Marked as thin lines inside a payment progress bar, with the meaning in a
   key beside the bar rather than hanging off each mark. Shared by the sale
   page's payment pool and the calendar's appointment modal.
   mix-blend-mode keeps the line visible over both the filled and empty track. */
.pay-bp {
	position: absolute;
	top: 0;
	bottom: 0;
	width: 2px;
	margin-left: -1px;
	background: rgba(255, 255, 255, 0.85);
	mix-blend-mode: difference;
	z-index: 2;
	pointer-events: none;
}

/* Fixed breakpoint positions (deposit / stock / pre-fit) */
.pay-bp-20 {
	left: 20%;
}

.pay-bp-55 {
	left: 55%;
}

.pay-bp-90 {
	left: 90%;
}

/* ── Optional field reveal ──
   For a field most records don't use (e.g. a job's second fitter): the input
   stays hidden behind this button instead of sitting empty on every record.
   Shared by the calendar's appointment modal and the sale page. */
.optional-add-btn {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	margin: var(--sp-1) 0;
	padding: var(--sp-1) var(--sp-3);
	border: 1px dashed var(--border-color);
	border-radius: var(--radius-sm);
	background: transparent;
	color: var(--text-secondary);
	font-size: var(--fs-sm);
	cursor: pointer;
	transition: var(--transition);
}

.optional-add-btn:hover {
	border-color: var(--primary-color);
	border-style: solid;
	color: var(--primary-color);
}

/* Square variant, for sitting directly beside the field it extends */
.optional-add-btn--icon {
	width: 26px;
	height: 26px;
	padding: 0;
	margin: 0;
	gap: 0;
	justify-content: center;
}

/* Drops the revealed field back out of sight */
.optional-remove-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex-shrink: 0;
	width: 26px;
	height: 26px;
	padding: 0;
	border: 1px solid transparent;
	border-radius: var(--radius-sm);
	background: transparent;
	color: var(--text-muted);
	font-size: var(--fs-sm);
	cursor: pointer;
	transition: var(--transition);
}

.optional-remove-btn:hover {
	border-color: var(--danger-color);
	color: var(--danger-color);
}

.form-grid-3col {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--sp-4);
	align-items: start;
}

/* ── Card chrome used by detail pages ── */
.card-header h3 {
	display: flex;
	align-items: center;
	gap: var(--sp-4);
	margin: 0;
	font-size: var(--fs-lg);
	font-weight: 700;
	letter-spacing: 0.3px;
	text-transform: uppercase;
}

/* Horizontal spacing between title and inline control is the flex gap above;
   these elements' own left margins would otherwise double it. */
.card-header h3 .badge-ml {
	margin-left: 0;
}

/* Opt-in zero padding so a table sits flush to the card edges. */
.card-body.flush {
	padding: 0;
}

/* Opt-in explicit padding. Kept !important so it still wins on pages whose
   own sheet zeroes .card-body out wholesale. */
.card-body.padded {
	padding: var(--sp-4) !important;
}

/* ===== Detail Tab Panels ===== */
/* Content panels for the combined sale/order detail page (nav bar uses the standard .tab-nav/.tab-button) */

.detail-tab-panel {
    display: none;
}

.detail-tab-panel.active {
    display: block;
    padding-top: var(--sp-4);
}

.detail-tab-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: var(--sp-6);
    color: var(--text-muted);
    gap: var(--sp-2);
}

.detail-tab-empty i {
    font-size: var(--fs-4xl);
}

/* ===== Sale+Order Combined Page Layout ===== */
/* Persistent two-column layout: tab panels on the left, financial summary on the right */

.sale-page-layout {
    display: flex;
    gap: var(--sp-6);
    align-items: flex-start;
}

.sale-page-main {
    flex: 3;
    min-width: 0;
}

.sale-page-summary-col {
    flex: 1;
    min-width: 240px;
    max-width: 320px;
    /* Stick to the viewport while the page (left column) scrolls.
       `top` matches the natural offset (topbar + .main-content padding-top)
       so the column locks exactly where it sits — no jump/stutter on scroll.
       If the cards are taller than the viewport, scroll them independently. */
    position: sticky;
    top: calc(var(--topbar-height) + 24px);
    max-height: calc(100vh - var(--topbar-height) - 48px);
    overflow-y: auto;
    padding-right: var(--sp-1);
}

.modal-body .form-group label .required {
    color: var(--danger-color);
}

.modal-body .form-group input,
.modal-body .form-group select {
    padding: var(--sp-2);
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    color: var(--text-primary);
    font-size: var(--fs-md);
    transition: border-color 0.2s;
    outline: none;
}

.modal-body .form-group input:focus,
.modal-body .form-group select:focus {
    outline: none;
    border-color: var(--primary-color);
	box-shadow: 0 0 0 1px var(--primary-color);
}

/* .checkbox-input / .pnx-item-checkbox / .select-all-pnx used to redeclare the
   checkbox look here. They now inherit the single site-wide
   input[type="checkbox"] style above — don't reintroduce a second variant. */

/* ===== Pagination =====
   Shared inner controls for paginated list pages. The outer wrapper
   (.customers-pagination, .apay-pagination, .inv-pagination, …) stays
   page-specific for positioning; these inner classes are the standard.
   Squared per the button standard (--radius-sm). */
.pagination-info {
	font-size: var(--fs-sm);
	color: var(--text-secondary);
}

.pagination-controls {
	display: flex;
	align-items: center;
	gap: var(--sp-1);
}

.page-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 32px;
	height: 32px;
	padding: 0 var(--sp-2);
	border-radius: var(--radius-sm);
	font-size: var(--fs-sm);
	font-weight: 500;
	color: var(--text-secondary);
	text-decoration: none;
	background: transparent;
	border: 1px solid transparent;
	cursor: pointer;
	transition: var(--transition);
}

.page-btn:hover {
	background: var(--bg-hover);
	color: var(--text-primary);
}

.page-btn.active {
	background: var(--primary-color);
	color: var(--text-on-color);
	border-color: var(--primary-color);
}

.page-btn:disabled {
	opacity: 0.4;
	cursor: default;
}

.page-ellipsis {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 24px;
	height: 32px;
	font-size: var(--fs-sm);
	color: var(--text-muted);
}

/* ===== Consolidated shared components (auto-merged) ===== */
.role-badge.admin {
    background: var(--danger-subtle);
    color: var(--danger-color);
}

.role-badge.accounting {
    background: var(--primary-subtle);
    color: var(--primary-color);
}

.role-badge.director {
    background: var(--purple-subtle);
    color: var(--purple-color);
}

.role-badge.user {
    background: var(--success-subtle);
    color: var(--success-color);
}

.role-badge.franchise {
    background: var(--warning-subtle);
    color: var(--warning-color);
}

.role-badge.fitter {
	background: var(--info-subtle);
	color: var(--info-color);
}

.role-badge.custom {
	background: var(--bg-tertiary);
	color: var(--text-secondary);
}

.header-content h1 {
    font-size: var(--fs-4xl);
    font-weight: 700;
    margin: 0 0 var(--sp-2) 0;
}

.header-subtitle {
    font-size: var(--fs-lg);
    color: var(--text-secondary);
    margin: 0;
}

.stats-dashboard {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--sp-4);
    margin-bottom: 32px;
}

/* Base stat card — flex row: [.stat-icon] [.stat-content > .stat-value + .stat-label].
   Consolidated from import_history/material_report (identical bases) so pages
   stop redefining it. Colour modifiers + responsive tweaks are below/above. */
.stat-card {
	background: var(--bg-secondary);
	border: 1px solid var(--border-color);
	border-radius: var(--radius-md);
	padding: var(--sp-5);
	display: flex;
	align-items: center;
	gap: var(--sp-4);
	transition: var(--transition);
}

.stat-card:hover {
	box-shadow: var(--shadow-sm);
}

.stat-icon {
    font-size: var(--fs-4xl);
    line-height: 1;
}

.stat-content {
    flex: 1;
}

.stat-value {
	font-size: var(--fs-4xl);
	font-weight: 700;
	line-height: 1;
	margin-bottom: var(--sp-1);
}

.stat-label {
	font-size: var(--fs-md);
	color: var(--text-secondary);
	text-transform: uppercase;
	letter-spacing: 0.5px;
}

.stat-card.stat-primary {
    border-left: 4px solid var(--primary-color);
}

.stat-card.stat-primary .stat-value {
    color: var(--primary-color);
}

.stat-card.stat-info {
    border-left: 4px solid var(--info-color);
}

.stat-card.stat-info .stat-value {
    color: var(--info-color);
}

.stat-card.stat-success {
    border-left: 4px solid var(--success-color);
}

.stat-card.stat-success .stat-value {
    color: var(--success-color);
}

.stat-card.stat-warning {
    border-left: 4px solid var(--warning-color);
}

.stat-card.stat-warning .stat-value {
    color: var(--warning-color);
}

.stat-card.stat-danger {
	border-left: 4px solid var(--danger-color);
}

.stat-card.stat-danger .stat-value {
	color: var(--danger-color);
}

.results-section {
    margin-bottom: 32px;
}

.results-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: var(--sp-5);
}

.results-header .section-title {
    margin: 0;
    font-size: var(--fs-2xl);
    font-weight: 600;
}

.results-count {
    font-size: var(--fs-lg);
    font-weight: 400;
    color: var(--text-secondary);
}

.po-row:hover .expand-icon {
    color: var(--text-primary);
}

.status-badge.status-received {
    background: var(--success-subtle);
    color: var(--success-color);
}

.status-badge.status-partial {
    background: var(--warning-subtle);
    color: var(--warning-color);
}

.status-badge.status-not-received {
    background: var(--danger-subtle);
    color: var(--danger-color);
}

.detail-row > td {
    padding: 0 !important;
    background: var(--bg-primary);
}

.details-container {
    padding: var(--sp-4);
    background: var(--bg-secondary);
}

.details-actions {
    display: flex;
    gap: 10px;
}

.empty-title {
    font-size: var(--fs-3xl);
    font-weight: 600;
    margin: 0 0 var(--sp-3) 0;
    color: var(--text-primary);
}

.detail-row.hidden {
    display: none;
}

.costing-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--sp-1) var(--sp-2);
    font-size: var(--fs-sm);
    font-weight: 600;
    border-radius: var(--radius-sm);
    min-width: 28px;
}

.costing-badge.success {
    background-color: var(--success-subtle);
    color: var(--success-color);
}

.costing-badge.danger {
    background-color: var(--danger-subtle);
    color: var(--danger-color);
}

.filter-tab.active {
	background-color: var(--primary-color);
	background-image: var(--sheen);
    color: var(--text-on-color);
}

.merge-btn:hover {
    background: var(--primary-color);
    color: var(--text-on-color);
}

.modal-body .form-group label {
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.3px;
}

.modal-body .form-row {
    display: flex;
    gap: var(--sp-4);
}

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

#searchPaymentsModal[open] {
    display: flex;
    flex-direction: column;
}

.status-icon.success {
    color: var(--success-color);
}

.decision-options {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}

.decision-proceed {
    background-color: var(--success-color);
    color: var(--text-on-color);
    border-color: var(--success-color);
}

.decision-dead {
    background-color: var(--danger-color);
    color: var(--text-on-color);
    border-color: var(--danger-color);
}

/* .badge-required / .badge-attachment are gantt-only — their base now comes
   from the global .badge (.badge-sm) and their colour from the scoped rules in
   gantt.css, so the standalone global definitions were removed. */

.accessory-price-info {
    font-size: 0.8em;
    min-width: 110px;
}

.accessory-price-info > div {
    display: flex;
    justify-content: space-between;
    gap: var(--sp-2);
}

.accessory-remaining {
    font-weight: bold;
}

.accessory-remaining-negative {
    color: var(--danger-color);
}

.accessory-remaining-positive {
    color: var(--success-color);
}

.accessory-remaining-zero {
    color: var(--warning-color);
}

.accessory-price-info > div.stock-detail-hidden {
    display: none;
}

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

.incoming-highlight {
	color: var(--primary-color);
    font-weight: 600;
}

.incoming-zero {
    color: var(--text-primary);
    font-weight: normal;
}

.egger-tile img {
    width: 100%;
    aspect-ratio: 1;
    object-fit: cover;
    display: block;
}

.egger-tile-code {
    padding: 6px;
    text-align: center;
    font-size: var(--fs-sm);
    font-weight: 600;
    background: var(--bg-tertiary);
}

.egger-lightbox {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 10000;
    background: rgba(0, 0, 0, 0.85);
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.egger-lightbox img {
    max-width: 90vw;
    max-height: 90vh;
    border-radius: var(--radius-sm);
    box-shadow: 0 0 40px rgba(0, 0, 0, 0.5);
}

.tabs {
	display: flex;
	align-items: center;
	gap: var(--sp-3);
	margin-bottom: var(--sp-4);
}

.tabs .tab-nav-pills {
    flex-shrink: 0;
}

.tabs .tab-actions {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
	flex-shrink: 0;
}

.form-group .required {
    color: var(--danger-color);
}

.form-group input {
    padding: var(--sp-2) var(--sp-3);
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font-size: var(--fs-md);
    transition: border-color 0.2s;
}

/* Guard for .search-input-wrapper (defined above).
   Broad rules like `.form-group input` and `.modal-body .form-group input`
   out-specify `.search-input-wrapper input`, so a search bar dropped into a
   form group would get a second bordered box drawn inside its wrapper. The
   doubled class lifts this reset above them; it must stay *after* those rules
   in source order. Page files that still win (a heavier selector such as
   `.filter-group input[type="text"]`) scope themselves with `>` instead. */
.search-input-wrapper.search-input-wrapper input {
	border: none;
	border-radius: 0;
	background: none;
	box-shadow: none;
	padding: var(--sp-2) 0;
}

/* Same guard for focus: `.form-group input:focus` rules add a glow ring, which
   would sit inside the wrapper's own :focus-within outline. One outline only. */
.search-input-wrapper.search-input-wrapper input:focus {
	border-color: transparent;
	box-shadow: none;
}

/* ═══════════════════════════════════════════════════════ */
/*  Shared Utilities — moved from customers.css &         */
/*  customer_detail.css for global reuse across all pages */
/* ═══════════════════════════════════════════════════════ */

/* ── Customer Active Badge ── */
/* Base shape from the global .badge (pair with .badge in markup); only the
   status colours are defined here. Context size/spacing tweaks live in the
   scoped rules above (.entity-hero-status-block, .card-header). */
.customer-active-badge.active {
    background: var(--success-subtle);
    color: var(--success-color);
}

.customer-active-badge.inactive {
	background: rgba(var(--text-secondary-rgb), 0.15);
    color: var(--text-muted);
}

.customer-active-badge.danger {
    background: var(--danger-subtle);
    color: var(--danger-color);
}

.customer-active-badge.new {
	background: rgba(var(--primary-rgb), 0.15);
	color: var(--primary-color);
}

.customer-active-badge.contacted {
	background: rgba(var(--warning-rgb), 0.15);
	color: var(--warning-color);
}

.customer-active-badge.qualified {
	background: rgba(var(--purple-rgb), 0.15);
    color: var(--purple-color);
}

.customer-active-badge.proposal {
	background: rgba(var(--info-rgb), 0.15);
	color: var(--info-color);
}

.customer-active-badge.converted {
	background: rgba(var(--success-rgb), 0.15);
    color: var(--success-color);
}

.customer-active-badge.lost {
	background: rgba(var(--text-secondary-rgb), 0.15);
    color: var(--text-muted);
}

/* ── Customer Name Link ── */
.customer-name-link {
    color: var(--primary-color);
    text-decoration: none;
    font-weight: 500;
}

.customer-name-link:hover {
    text-decoration: underline;
}

/* ── Customer Monospace Code ── */
.customer-mono {
    font-family: monospace;
    font-size: var(--fs-md);
}

/* ── Tab Count Badge ── */
.tab-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: var(--radius-sm);
    font-size: var(--fs-sm);
    font-weight: 700;
    background: var(--bg-secondary);
    color: var(--text-secondary);
}

.customer-order-badge {
    display: inline-block;
    padding: 2px 8px;
	background: var(--primary-subtle);
	color: var(--primary-color);
    border-radius: var(--radius-sm);
    font-size: var(--fs-sm);
    font-weight: 500;
    text-decoration: none;
    transition: background 0.15s;
}

.customer-order-badge:hover {
	background: rgba(var(--primary-rgb), 0.24);
    text-decoration: none;
}

/* ── Shared Edit Input ── */
.customer-edit-input {
    width: 100%;
    padding: var(--sp-2) var(--sp-3);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-sm);
    font-size: var(--fs-md);
    font-family: inherit;
    background: var(--bg-primary);
    color: var(--text-primary);
    transition: border-color 0.15s, box-shadow 0.15s;
    box-sizing: border-box;
}

.customer-edit-input:focus {
    outline: none;
    border-color: var(--primary-color);
	box-shadow: 0 0 0 1px var(--primary-color);
}

.customer-edit-input::placeholder {
    color: var(--text-muted);
}

/* ── Save Notification ── */
.save-notification {
    display: none;
    padding: 10px 16px;
    border-radius: var(--radius-sm);
    margin-bottom: var(--sp-3);
    align-items: center;
    gap: var(--sp-2);
    font-size: var(--fs-md);
}

.save-notification.success {
    display: flex;
	background: rgba(var(--success-rgb), 0.12);
    color: var(--success-color);
}

.save-notification.error {
    display: flex;
    background: var(--danger-subtle);
    color: var(--danger-color);
}

/* ── Header Actions ── */
.header-actions {
    display: flex;
    gap: var(--sp-2);
    align-items: center;
}

/* ── Hidden Edit Values ── */
.edit-val {
    display: none;
}

/* =============================================
   Admin pages component library
   Promoted from the old admin_pages.css so every admin page loads a
   single page-specific sheet on top of this shared base. The .admin-*
   and .user-badge/.empty-state-block names are admin-unique; the
   .status-badge rules are scoped under .admin-page so they don't
   collide with the differently-styled .status-badge on other pages.
   ============================================= */
.admin-page {
	padding: 0;
}

.admin-page .page-header {
	margin-bottom: var(--sp-6);
}

.admin-page .page-header h1 {
	font-size: var(--fs-3xl);
	font-weight: 700;
	margin: 0 0 var(--sp-1) 0;
	display: flex;
	align-items: center;
	gap: 10px;
}

.admin-page .page-header h1 i {
	color: var(--primary-color);
}

.admin-page .page-subtitle {
	color: var(--text-secondary);
	margin: 0 0 var(--sp-4) 0;
}

.admin-card {
	background: var(--bg-secondary);
	border: 1px solid var(--border-color);
	border-radius: var(--radius-md);
	overflow: hidden;
	box-shadow:
		0 1px 0 rgba(255,255,255,0.04) inset,
		0 8px 24px rgba(0,0,0,0.35);
}

/* Headers use the global .card-header class; no bespoke layout needed. */
.admin-card-body {
	padding: var(--sp-3);
}

.admin-card-header h2 {
	font-size: var(--fs-lg);
	font-weight: 600;
	color: var(--text-primary);
	margin: 0;
}

/* Admin Table */
.admin-table-wrapper {
	overflow-x: auto;
}

.admin-table thead th {
	padding: var(--sp-3) var(--sp-4);
	font-size: var(--fs-sm);
	letter-spacing: 0.05em;
	background: var(--bg-secondary);
	white-space: nowrap;
}

.admin-table tbody td {
	font-size: var(--fs-md);
	border-bottom: 1px solid var(--border-color);
	vertical-align: middle;
}

.admin-table tbody tr:last-child td {
	border-bottom: none;
}

/* User Badge */
.user-badge {
	display: inline-flex;
	align-items: center;
	gap: var(--sp-2);
	font-weight: 500;
}

.user-badge i {
	font-size: var(--fs-xl);
	color: var(--primary-color);
}

/* Status Badges — scoped to .admin-page (other pages define .status-badge differently) */
.admin-page .status-badge {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 24px;
	height: 24px;
	border-radius: var(--radius-round);
	font-size: var(--fs-sm);
}

.admin-page .status-badge.status-active {
	background: var(--success-subtle);
	color: var(--success-color);
}

.admin-page .status-badge.status-inactive {
	background: var(--danger-subtle);
	color: var(--danger-color);
}

/* Empty State (block variant is admin-unique; the bare .empty-state override
   was unused by admin templates and is intentionally left to the global one) */
.empty-state-block {
	text-align: center;
	padding: 60px 20px;
}

.empty-state-block i {
	font-size: var(--fs-4xl);
	color: var(--text-secondary);
	opacity: 0.4;
	margin-bottom: var(--sp-4);
	display: block;
}

.empty-state-block h3 {
	font-size: var(--fs-xl);
	font-weight: 600;
	margin: 0 0 var(--sp-2) 0;
}

.empty-state-block p {
	color: var(--text-secondary);
	max-width: 500px;
	margin: 0 auto;
}

/* =============================================
   Calendar shell
   Shared chrome for the calendar-style pages (Fit Board, Gantt Chart):
   top toolbar, nav/date cluster and the view-toggle pill. Promoted from
   the old calendar_shell.css. Page sheets (fit_board.css, gantt.css)
   still layer their own overrides on top.
   ============================================= */
.cal-toolbar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--sp-4);
	padding: var(--sp-2) var(--sp-3);
	background: var(--bg-secondary);
	border-radius: var(--radius-lg);
	margin-bottom: var(--sp-4);
	flex-wrap: wrap;
	position: sticky;
	top: calc(var(--topbar-height, 52px) + 8px);
	z-index: 100;
}

/* Compact buttons inside the toolbar */
.cal-toolbar .btn {
	padding: var(--sp-1) var(--sp-3);
	font-size: var(--fs-sm);
	height: 30px;
}

.cal-toolbar-right {
	display: flex;
	align-items: center;
	gap: var(--sp-2);
}

/* ── Nav / date cluster ── */
.calendar-nav {
	display: flex;
	gap: var(--sp-3);
	align-items: center;
	flex-wrap: wrap;
}

.calendar-date {
	font-size: var(--fs-lg);
	font-weight: 700;
	text-transform: uppercase;
	margin: 0;
	white-space: nowrap;
}

/* ── View toggle ── */
.view-toggle {
	display: flex;
	background: var(--bg-primary);
	border: 1px solid var(--border-color);
	border-radius: var(--radius-pill);
	overflow: hidden;
}

.view-toggle-btn {
	padding: var(--sp-1) var(--sp-4);
	font-size: var(--fs-sm);
	font-weight: 600;
	color: var(--text-secondary);
	text-decoration: none;
	transition: all 0.2s;
	border-right: 1px solid var(--border-color);
}

.view-toggle-btn:last-child {
	border-right: none;
}

.view-toggle-btn:hover {
	background: var(--bg-secondary);
	color: var(--text-primary);
}

.view-toggle-btn.active {
	background: var(--primary-color);
	color: var(--text-on-color);
}

@media (max-width: 968px) {
    /* Stack the sale page columns and restore normal document scrolling */
    .sale-page-layout {
        flex-direction: column;
    }

    .sale-page-summary-col {
        max-width: none;
        position: static;
        max-height: none;
        overflow-y: visible;
        padding-right: 0;
    }

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

    .form-row {
        grid-template-columns: 1fr;
    }

    .tab-nav {
        flex-wrap: wrap;
    }

    .tab-button {
        flex: 1 1 50%;
    }
}

@media (max-width: 900px) {
	/* Keep the name and the action buttons together on the top row so the Edit
	   button stays pinned to the top-right corner; the detail columns, status
	   block and links each wrap onto their own full-width row underneath.
	   `order` places the actions immediately after the identity while the
	   full-width blocks (flex-basis:100%) are forced onto new rows. */
	.entity-hero-header {
		align-items: flex-start;
		row-gap: 14px;
	}

	.entity-hero-identity {
		flex: 1 1 auto;
		padding-right: var(--sp-3);
		min-width: 0;
	}

	.entity-hero-actions {
		order: 2;
		border-left: none;
		padding-left: 0;
		flex-shrink: 0;
	}

	.entity-hero-cols {
		order: 3;
		flex-basis: 100%;
		flex-direction: column;
		border-left: none;
		border-right: none;
		border-top: 1px solid var(--border-color);
		border-bottom: 1px solid var(--border-color);
		padding: var(--sp-3) 0;
		gap: var(--sp-3);
	}

	.entity-hero-col {
		padding: 0;
		min-width: 0;
	}

	.entity-hero-col + .entity-hero-col {
		border-left: none;
	}

	.entity-hero-status-block {
		order: 4;
		flex-basis: 100%;
		border-left: none;
		padding: 0;
		column-gap: var(--sp-6);
	}

	.entity-hero-links {
		order: 5;
		flex-basis: 100%;
		width: 100%;
	}
}

@media (max-width: 1080px) {
	/* ===== Top nav / sidebar collapse to mobile form =====
	   At/below this width the sidebar becomes an off-canvas overlay driven by
	   the hamburger, and the top bar folds its controls (theme, profile, bell,
	   location, full search) into a search icon + kebab. Phone-scale typography
	   and spacing kick in lower down at 768px — this breakpoint only
	   restructures the navigation chrome. The matching JS width check lives in
	   base.html (openMobileNav / resize handlers). */

	/* Hide sidebar by default; it slides in as an overlay, pinned below the top
	   bar, at full width. */
	.sidebar {
		transform: translateX(-100%);
		width: 100%;
		z-index: 1001;
		top: var(--topbar-height);
		height: calc(100vh - var(--topbar-height));
	}

	.sidebar.mobile-open {
		transform: translateX(0);
	}

	/* Show the close button inside the sidebar */
	.mobile-nav-close {
		display: flex;
	}

	/* Hide the sidebar header (logo/close) — the top bar owns that now */
	.sidebar-header {
		display: none;
	}

	/* Tighter nav padding */
	.nav-section-header {
		padding: 8px 12px 2px;
	}

	.nav-link,
	.nav-section-content .nav-link {
		padding: var(--sp-1) var(--sp-3);
	}

	/* Top navbar takes full width, stays above the overlay */
	.top-navbar {
		left: 0 !important;
		z-index: 1002;
		padding: 0 var(--sp-2);
	}

	.top-navbar.expanded {
		left: 0;
	}

	/* Main content reclaims the sidebar's space */
	.main-content {
		margin-left: 0 !important;
	}

	.main-content.expanded {
		margin-left: 0;
	}

	/* Reveal the mobile-only search icon + kebab; fold the standalone theme
	   toggle, profile menu, notification bell and location picker away. */
	.mobile-topbar-only {
		display: inline-flex;
	}

	.theme-switch,
	.profile-menu-wrapper,
	.validation-bell-wrapper,
	.top-location-menu {
		display: none;
	}

	/* The search icon reveals the global search as a full-width dropdown bar
	   pinned under the navbar, toggled by .search-open on #topNavbar. */
	.top-navbar-center {
		display: block;
		position: fixed;
		top: var(--topbar-height);
		left: 0;
		right: 0;
		padding: var(--sp-2) var(--sp-3);
		background: var(--bg-nav);
		border-bottom: 1px solid var(--border-color);
		box-shadow: var(--shadow-md);
		z-index: 1002;
		opacity: 0;
		visibility: hidden;
		pointer-events: none;
		transform: translateY(-8px);
		transition: opacity var(--transition), transform var(--transition), visibility var(--transition);
	}

	/* The banner pushes the navbar down 34px — keep the search bar under it. */
	body:has(.impersonation-banner) .top-navbar-center {
		top: calc(var(--topbar-height) + 34px);
	}

	.top-navbar.search-open .top-navbar-center {
		opacity: 1;
		visibility: visible;
		pointer-events: auto;
		transform: translateY(0);
	}

	.top-navbar-center .top-search,
	.top-navbar-center .top-search form {
		width: 100%;
	}

	.top-navbar-right {
		gap: var(--sp-2);
	}

	/* The bar already sits in its own panel here — drop the pill outline. */
	.top-search form {
		border: none;
		background: none;
	}
}

@media (max-width: 768px) {
	:root {
		/* Cap the top of the type scale — 32/24/20px headings are oversized on a
		   phone. Body/label sizes below --fs-xl are unchanged. */
		--fs-4xl: 1.5rem;    /* 32 → 24 */
		--fs-3xl: 1.25rem;   /* 24 → 20 */
		--fs-2xl: 1.125rem;  /* 20 → 18 */
		--fs-xl: 1rem;       /* 18 → 16 */

		/* Base UI/body text — 14px reads a touch large on a phone. Dropping the
		   body default to 12px cascades to every element that inherits it or
		   references var(--fs-md) directly (buttons, inputs, table cells). */
		--fs-md: 0.75rem;    /* 14 → 12 */

		/* Tighten the large spacing steps so dense pages reclaim horizontal room.
		   The small steps (4–16px) stay as-is to keep controls comfortable. */
		--sp-6: 16px;        /* 24 → 16 */
		--sp-5: 14px;        /* 20 → 14 */

		/* On a phone the topbar-sized vertical inset (52+16px) dwarfs the 16px the
		   overlay leaves on the sides. Match it to the horizontal padding so modals
		   sit a uniform 16px from every edge and extend into the reclaimed vertical
		   space (--modal-max-h derives from this token, so the height grows too). */
		--modal-offset: 16px;
	}

	/* iOS Safari auto-zooms the page whenever a focused form control has a
	   computed font-size below 16px. Our controls inherit var(--fs-md), which
	   is 12px on mobile (above), so every text field would trigger the zoom.
	   --fs-lg is 1rem (16px) and is deliberately left un-shrunk in this mobile
	   block, so it hits the platform threshold exactly — pin the controls to it
	   so focusing an input never zooms the viewport. Body/label text stays at
	   the smaller mobile scale; only the fields themselves grow. */
	input[type="text"],
	input[type="email"],
	input[type="password"],
	input[type="number"],
	input[type="search"],
	input[type="tel"],
	input[type="url"],
	input[type="date"],
	input[type="datetime-local"],
	input[type="month"],
	input[type="time"],
	textarea,
	select {
		font-size: var(--fs-lg);
	}

	/* The sanctioned .table-wrap plus every bespoke wrapper — they all end in
	   -wrap / -wrapper / -container, so substring matching covers the lot,
	   including the few that were missing overflow-x. */
	[class*="table-wrap"],
	[class*="table-container"],
	.table-responsive {
		overflow-x: auto;
	}

	/* Any table with no scroll wrapper turns into its own scroll area:
	   width:100% (from the base rule) keeps narrow tables full-width, while
	   wider column sets overflow and scroll horizontally within it. Targets the
	   bare `table` element, not just `.table`, so bespoke/inline-styled tables
	   (e.g. shortages, ordering) that never got the base class scroll too. */
	table {
		display: block;
		overflow-x: auto;
	}

	/* ...but a table already inside a scroll wrapper stays a normal table so it
	   fills the bordered wrapper (which is doing the scrolling) at 100% width. */
	[class*="table-wrap"] > table,
	[class*="table-container"] > table,
	.table-responsive > table {
		display: table;
		overflow: hidden;
	}

    /* Trim side padding so cramped mobile screens use more of the available
       width. (Nav/sidebar collapse to mobile form now happens at 1080px, above.) */
    .main-content {
        padding: var(--sp-2) var(--sp-1);
    }

    .page-content {
        padding-left: var(--sp-1);
        padding-right: var(--sp-1);
    }

    .page-title {
        font-size: var(--fs-lg);
    }

    /* Remove card body extra padding on mobile */
    .card-header {
        padding: var(--sp-2);
    }

    .card-body {
        padding: var(--sp-2);
    }

    /* Reset content-wrapper margin */
    .content-wrapper {
        margin: 0;
    }

    /* Page header tighter on mobile */
    .page-header {
        margin-bottom: var(--sp-2);
    }

    .page-header h1 {
        font-size: var(--fs-2xl);
    }

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

    .header-actions {
        width: 100%;
    }
}

@media (max-width: 568px) {
    .page-header {
        flex-direction: column;
        align-items: flex-start;
        gap: var(--sp-4);
    }

    .stats-grid {
        grid-template-columns: 1fr;
    }

    .tab-button {
        flex: 1 1 100%;
        font-size: var(--fs-md);
        padding: var(--sp-3) var(--sp-4);
    }
}

@media (max-width: 480px) {
    .stats-dashboard {
        grid-template-columns: 1fr;
    }

    .header-content h1 {
        font-size: var(--fs-3xl);
    }

    .stat-card {
        padding: var(--sp-4);
    }

    .stat-icon {
        font-size: var(--fs-3xl);
    }

    .stat-value {
        font-size: var(--fs-3xl);
    }
}

@media (prefers-reduced-motion: reduce) {
	.tab-pill-thumb {
		transition: none;
	}

	.tab-swapping {
		transition: none;
	}

	.tab-glide-in {
		animation: none;
	}
}
