:root {
    /* Palette sampled directly from the Allied logo and alliedbiz.co.za site:
       --red is the logo wordmark red; --blue/--blue-dark are the deep teal-blue
       from the site's footer gradient (kept dark enough for text/button contrast);
       --blue-accent is the vivid sky-blue used across the site's hero/footer
       backgrounds, reserved for decorative accents rather than small text. */
    --blue: #08567d;
    --blue-dark: #063e5a;
    --blue-light: #e6f5fc;
    --blue-accent: #0098e4;
    --red: #d9232e;
    --red-dark: #a31a22;
    --red-light: #fcedee;
    --white: #ffffff;
    --gray-50: #f7f8fa;
    /* <body>'s own background, kept as its own variable rather than
       reusing --gray-50 directly -- --gray-50 does several other jobs
       (row hover, dropdown backgrounds, table header tints) that have
       nothing to do with the page canvas and shouldn't move if an
       admin picks a custom page color from Admin -> Branding. Aliased
       to --gray-50 here so an unbranded install looks exactly as it
       does today; Admin -> Branding overrides this one variable alone
       (see _brand_head.html) without touching --gray-50 or --card-bg. */
    --page-bg: var(--gray-50);
    --gray-100: #eef0f3;
    --gray-200: #dde1e6;
    --gray-300: #c3c9d1;
    --gray-400: #9aa2ad;
    --gray-600: #5b6470;
    --gray-800: #262b33;
    --radius: 8px;
    --shadow: 0 1px 3px rgba(20, 30, 60, 0.08), 0 1px 2px rgba(20, 30, 60, 0.06);
    --sidebar-width: 240px;

    /* Sidebar: light blue fill with dark, high-contrast text on top;
       Topbar: light grey, reusing --gray-100 which was already the exact
       shade we want. */
    --sidebar-bg: #a6c9ec;
    --sidebar-text: var(--gray-800);
    --sidebar-text-muted: var(--blue-dark);
    --sidebar-active-bg: var(--white);
    --sidebar-hover-bg: rgba(255, 255, 255, 0.4);
    --sidebar-divider: rgba(6, 62, 90, 0.18);
    --sidebar-count-bg: rgba(255, 255, 255, 0.6);
    --topbar-bg: var(--gray-100);
    /* Boxes/cards get their own tone instead of reusing --white: a pure-white
       card on this page's --gray-50 background read as almost no contrast at
       all against the page (light theme), and the reverse problem in dark
       theme -- the card sat darker than the header right above it rather
       than standing out from the near-black page beneath it. Matching
       --gray-100 (the header's own tone) fixes both at once and keeps
       card/header visually consistent as one "surface" tier, distinct from
       the page background under them -- see var(--white)'s own remaining
       uses (modals, dropdowns, table rows, etc.) for why those were left
       alone rather than folded into this too: they're a different role,
       not the same "box" this was actually about. */
    --card-bg: var(--gray-100);

    /* Status/semantic tints used by flashes, badges and pills. Kept as
       variables (rather than one-off hex values) so the dark theme below
       can swap them in one place. */
    --success-bg: #e6f4ea;
    --success-text: #1e7a3d;
    --success-border: #c3ecd3;
    --warning-bg: #fff2cf;
    --warning-text: #8a6400;
    --warning-border: #f7e3a3;
    --due-bg: #ffe8cf;
    --due-text: #a15a12;
    --danger-border: #f3b9c0;
    --info-border: #cdd9f2;

    /* Extra tints, Customer Type badges only (Government/Doctor) -- kept
       separate from the semantic status colors above so a Type badge is
       never mistaken for a status/warning indicator. */
    --purple-bg: #f1e9fb;
    --purple-text: #6b3fa0;
    --teal-bg: #e1f4f3;
    --teal-text: #157a72;

    color-scheme: light;
}

/* ==========================================================================
   Dark theme
   Toggled by setting data-theme="dark" on <html> (see theme.js). Every rule
   in this file is written against the variables above, so re-pointing them
   here is enough to re-skin the whole app — no rule below this block needed
   its own dark-mode override.
   ========================================================================== */
:root[data-theme="dark"] {
    color-scheme: dark;

    --blue: #3d8fd6;
    --blue-dark: #82c4f5;
    --blue-light: rgba(61, 143, 214, 0.16);
    --blue-accent: #58a6e0;
    --red: #e0626d;
    --red-dark: #ffb3ba;
    --red-light: rgba(224, 82, 96, 0.16);

    --white: #1b212c;
    --gray-50: #10141b;
    --gray-100: #202836;
    --gray-200: #2c3646;
    --gray-300: #3c4759;
    --gray-400: #838da0;
    --gray-600: #aab2c2;
    --gray-800: #e7ebf1;

    --shadow: 0 1px 3px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.35);

    --sidebar-bg: #131a24;
    --sidebar-hover-bg: rgba(255, 255, 255, 0.06);
    --sidebar-divider: rgba(255, 255, 255, 0.08);
    --sidebar-count-bg: rgba(255, 255, 255, 0.12);

    --success-bg: rgba(46, 160, 90, 0.16);
    --success-text: #6fd38f;
    --success-border: rgba(46, 160, 90, 0.35);
    --warning-bg: rgba(217, 168, 30, 0.16);
    --warning-text: #e8c05f;
    --warning-border: rgba(217, 168, 30, 0.35);
    --due-bg: rgba(224, 122, 41, 0.16);
    --due-text: #f0a868;
    --danger-border: rgba(224, 82, 96, 0.35);
    --info-border: rgba(61, 143, 214, 0.35);

    --purple-bg: rgba(155, 107, 214, 0.16);
    --purple-text: #c9a6ee;
    --teal-bg: rgba(45, 176, 168, 0.16);
    --teal-text: #6fd9d0;

    /* .btn-primary / .quick-add-menu use --blue-dark as a hover/pressed
       background elsewhere in the light theme; in dark mode --blue-dark is
       repurposed as a light "text on tinted background" color (badges,
       active nav item, etc.), so pressed states get their own darker blue
       here instead of reusing it. */
    --blue-press: #1f6fb0;
    --red-press: #b8434c;
}

:root[data-theme="dark"] .btn-primary:hover { background: var(--blue-press); }
:root[data-theme="dark"] .quick-add-menu summary:hover,
:root[data-theme="dark"] .quick-add-menu[open] summary { background: var(--blue-press); }
:root[data-theme="dark"] .btn-danger:hover { background: var(--red-press); }

:root[data-theme="dark"] .auth-page { background: var(--sidebar-bg); }

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    background: var(--page-bg);
    color: var(--gray-800);
    min-height: 100vh;
}

a { color: var(--blue); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---------- App shell (sidebar + main) ---------- */
.app-shell {
    display: flex;
    min-height: 100vh;
    align-items: stretch;
}

/* ---------- Sidebar ---------- */
.sidebar {
    width: var(--sidebar-width);
    flex: 0 0 var(--sidebar-width);
    background: var(--sidebar-bg);
    border-right: 1px solid var(--sidebar-divider);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    align-self: flex-start;
    height: 100vh;
    overflow-y: auto;
}

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 20px 20px 18px;
    border-bottom: 1px solid var(--sidebar-divider);
}
.brand-icon-img {
    height: 32px;
    width: auto;
    flex-shrink: 0;
    display: block;
}
.brand-text { min-width: 0; }
.brand-title {
    font-weight: 700;
    font-size: 14px;
    color: var(--sidebar-text);
    line-height: 1.25;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.brand-subtitle {
    font-size: 12px;
    color: var(--sidebar-text-muted);
    margin-top: 1px;
}

.sidebar-nav {
    flex: 1;
    padding: 14px 12px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.sidebar-nav a {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 10px 12px;
    border-radius: var(--radius);
    color: var(--sidebar-text);
    font-weight: 500;
    font-size: 14px;
}
.sidebar-nav a:hover { background: var(--sidebar-hover-bg); text-decoration: none; }
.sidebar-nav a.active { background: var(--sidebar-active-bg); color: var(--blue-dark); box-shadow: var(--shadow); }
.nav-label { display: flex; align-items: center; gap: 10px; }
.nav-icon {
    width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: var(--sidebar-text-muted);
}
.nav-icon svg { display: block; width: 100%; height: 100%; }
.sidebar-nav a.active .nav-icon { color: var(--blue-dark); }

/* Pins Reports and Admin to the bottom of the sidebar nav, directly above
   the sidebar footer — the main nav items stay grouped at the top and
   this block absorbs the remaining space. Each of Reports and Admin sits
   in its own .sidebar-nav-partition, so each gets its own divider above
   it and reads as a distinct section, with Reports directly above Admin. */
.sidebar-nav-bottom { margin-top: auto; display: flex; flex-direction: column; }
.sidebar-nav-partition { display: flex; flex-direction: column; gap: 2px; }
.sidebar-nav-partition .sidebar-divider { margin: 10px 12px 12px; }
.nav-count {
    background: var(--sidebar-count-bg);
    color: var(--blue-dark);
    font-size: 11px;
    font-weight: 700;
    padding: 1px 8px;
    border-radius: 999px;
    min-width: 20px;
    text-align: center;
}
.sidebar-nav a.active .nav-count { background: var(--blue-light); color: var(--blue-dark); }

/* Collapsible Sales / Technical / All Users sections -- same .nav-icon/
   .nav-label/.nav-count sizing as every flat sidebar link above, just
   wrapped in a <button> header (so no href, nothing for a screen
   reader to misread as a dead link) that toggles .sidebar-group-body's
   visibility. A group auto-opens (via the 'open' class rendered
   server-side) when the active page is inside it; otherwise its state
   persists per-browser via localStorage, same mechanism as the
   dark-theme toggle already uses elsewhere in this template. */
.sidebar-group-toggle {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    width: 100%; padding: 10px 12px; border: none; background: none;
    border-radius: var(--radius); color: var(--sidebar-text);
    font-weight: 600; font-size: 13px; text-align: left; cursor: pointer;
    font-family: inherit;
}
.sidebar-group-toggle:hover { background: var(--sidebar-hover-bg); }
.sidebar-group-chevron { width: 14px; height: 14px; flex-shrink: 0; color: var(--sidebar-text-muted); transition: transform 0.15s ease; }
.sidebar-group.open .sidebar-group-chevron { transform: rotate(90deg); }
.sidebar-group-body { display: none; flex-direction: column; gap: 2px; padding-left: 14px; margin-top: 2px; }
.sidebar-group.open .sidebar-group-body { display: flex; }

.sidebar-divider {
    height: 1px;
    background: var(--sidebar-divider);
    margin: 10px 12px;
}

.sidebar-footer {
    padding: 16px 20px 20px;
    border-top: 1px solid var(--sidebar-divider);
    font-size: 12px;
}
.sidebar-footer-links { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.sidebar-footer-user { margin-bottom: 10px; }
.sidebar-footer-user-name { font-size: 13px; font-weight: 600; color: var(--sidebar-text); }
.sidebar-footer-user-role { color: var(--sidebar-text-muted); }
.pill-link {
    display: inline-flex;
    align-items: center;
    padding: 5px 12px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    color: var(--sidebar-text-muted);
    background: var(--sidebar-hover-bg);
    border: 1px solid var(--sidebar-divider);
}
.pill-link:hover { background: var(--sidebar-active-bg); color: var(--blue-dark); text-decoration: none; }
.sidebar-footer-note { color: var(--sidebar-text-muted); line-height: 1.4; }

/* ---------- Main column ---------- */
.main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.topbar {
    background: var(--topbar-bg);
    border-bottom: 1px solid var(--gray-200);
    padding: 22px 32px;
    display: grid;
    /* Side groups never shrink below their buttons; the title takes what is left (about 55%) and wraps -- a long title (an auto-created alert ticket's) used to push under the buttons. */
    grid-template-columns: minmax(max-content, 1fr) minmax(0, 2.2fr) minmax(max-content, 1fr);
    align-items: center;
    gap: 20px;
    position: sticky;
    top: 0;
    z-index: 5;
}
.topbar-left { display: flex; align-items: center; gap: 12px; justify-content: flex-start; }
.topbar-titles { text-align: center; }
.topbar-titles { min-width: 0; }
.topbar-titles h1 { margin: 0; overflow-wrap: anywhere; word-break: break-word; line-height: 1.25; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }
.topbar-titles h1.is-long { font-size: 18px; }
.topbar-titles .subtitle { margin-top: 4px; }
.topbar-actions { display: flex; align-items: center; gap: 12px; justify-content: flex-end; flex-wrap: wrap; }

.global-search {
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--white);
    border: 1px solid var(--gray-200);
    border-radius: var(--radius);
    padding: 0 12px;
    flex: 1 1 160px;
    min-width: 0;
}
.global-search .search-icon { color: var(--gray-400); font-size: 13px; flex-shrink: 0; }
.global-search input {
    border: none;
    background: transparent;
    padding: 9px 0;
    width: 100%;
    min-width: 0;
    font-size: 14px;
}
.global-search input:focus { outline: none; box-shadow: none; }
.global-search:focus-within { border-color: var(--blue); box-shadow: 0 0 0 3px var(--blue-light); }

/* Search filter panel -- a <details> dropdown (same pattern as
   .quick-add-menu/.collapsible-card elsewhere) listing each searchable
   category with its own on/off toggle, replacing what used to be a
   plain two-option <select>. Lives inside the same GET form as the
   search box itself, so submitting includes whichever categories are
   currently checked. */
.search-filter { position: relative; border-left: 1px solid var(--gray-200); margin-left: 4px; }
.search-filter > summary {
    list-style: none;
    cursor: pointer;
    padding: 8px 10px;
    color: var(--gray-500);
    display: flex;
    align-items: center;
}
.search-filter > summary::-webkit-details-marker { display: none; }
.search-filter > summary:hover { color: var(--gray-700); }
.search-filter[open] > summary { color: var(--blue); }
.search-filter-panel {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    width: 320px;
    background: var(--white);
    border: 1px solid var(--gray-200);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg, var(--shadow));
    padding: 8px;
    z-index: 20;
}
.search-filter-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    padding: 8px;
    border-radius: 6px;
}
.search-filter-row:hover { background: var(--gray-100); }
.search-filter-row-label { display: flex; align-items: flex-start; gap: 10px; }
.search-filter-row-icon { font-size: 16px; line-height: 1.3; }
.search-filter-row-text strong { display: block; font-size: 13px; }
.search-filter-row-text span { display: block; font-size: 12px; color: var(--gray-500); margin-top: 1px; }
.search-filter-actions { display: flex; justify-content: flex-end; gap: 8px; padding: 8px 8px 2px; border-top: 1px solid var(--gray-200); margin-top: 4px; }

.filter-toggle { position: relative; flex-shrink: 0; width: 34px; height: 20px; }
.filter-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.filter-toggle-track {
    position: absolute; inset: 0;
    background: var(--gray-200);
    border-radius: 999px;
    transition: background 0.15s;
}
.filter-toggle-thumb {
    position: absolute; top: 2px; left: 2px;
    width: 16px; height: 16px;
    border-radius: 50%;
    background: var(--white);
    box-shadow: var(--shadow);
    transition: transform 0.15s;
}
.filter-toggle input:checked + .filter-toggle-track { background: var(--blue); }
.filter-toggle input:checked + .filter-toggle-track .filter-toggle-thumb { transform: translateX(14px); }
.filter-toggle input:focus-visible + .filter-toggle-track { box-shadow: 0 0 0 3px var(--blue-light); }

/* ---------- Layout ---------- */
.page { margin: 0; padding: 28px 32px 60px; }
.footer { text-align: center; color: var(--gray-400); font-size: 12px; padding: 24px; }

.auth-page {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Same dark blue as the primary/login button (--blue), for a matching feel. */
    background: var(--blue);
}
.auth-card {
    background: var(--white);
    border-radius: 12px;
    box-shadow: var(--shadow);
    padding: 40px;
    width: 360px;
}
.auth-card .brand { display: flex; align-items: center; justify-content: center; margin-bottom: 24px; }
.auth-card .brand img { height: 42px; width: auto; }

/* ---------- Flash messages ---------- */
.flash-stack { margin-bottom: 20px; display: flex; flex-direction: column; gap: 8px; }
.flash {
    padding: 12px 16px;
    border-radius: var(--radius);
    font-size: 14px;
    border: 1px solid transparent;
}
.flash-success { background: var(--success-bg); color: var(--success-text); border-color: var(--success-border); }
.flash-danger { background: var(--red-light); color: var(--red-dark); border-color: var(--danger-border); }
.flash-warning { background: var(--warning-bg); color: var(--warning-text); border-color: var(--warning-border); }
.flash-info { background: var(--blue-light); color: var(--blue-dark); border-color: var(--info-border); }

/* ---------- Typography / headers ---------- */
h1 { font-size: 24px; margin: 0 0 4px; color: var(--gray-800); }
h2 { font-size: 18px; margin: 0 0 12px; color: var(--gray-800); }
h3 { font-size: 15px; margin: 0 0 4px; color: var(--gray-800); }
.page-header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    margin-bottom: 24px;
    gap: 16px;
    flex-wrap: wrap;
}
.subtitle { color: var(--gray-600); font-size: 14px; margin-top: 4px; }

/* ---------- Content action rows (search / filter + primary button) ---------- */
.content-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 20px;
    flex-wrap: wrap;
}
.content-actions .search-form { margin-bottom: 0; flex: 1; max-width: 480px; }

/* ---------- Cards / stats ---------- */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 16px;
    margin-bottom: 28px;
}
.stat-card {
    background: var(--white);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 18px 20px;
    border: 1px solid var(--gray-200);
    border-top: 3px solid var(--blue-accent);
}
.stat-card.stat-danger { border-top-color: var(--red); }
.stat-card .stat-value { font-size: 28px; font-weight: 700; color: var(--gray-800); }
.stat-card .stat-label { font-size: 13px; color: var(--gray-600); margin-top: 2px; }

.card {
    background: var(--card-bg);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    border: 1px solid var(--gray-200);
    padding: 20px 24px;
    margin-bottom: 20px;
    /* A table (or anything else) wider than the card scrolls inside the
       card itself, rather than pushing the card -- and with it, the
       whole page -- wider than the viewport. This is the fix for "most
       blocks wrap and scrolling is needed" on a narrow screen: it was
       never the individual blocks each having their own bug, it was
       every table-holding card missing this one rule. */
    overflow-x: auto;
}

/* ---------- Warranty warning banner ---------- */
.warning-banner {
    background: var(--red-light);
    border: 1px solid var(--danger-border);
    border-left: 4px solid var(--red);
    border-radius: var(--radius);
    padding: 16px 20px;
    margin-bottom: 20px;
}
.warning-banner h2 { color: var(--red-dark); display: flex; align-items: center; gap: 8px; }
.warning-banner .warn-icon { font-size: 18px; }

/* ---------- Tables ---------- */
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--gray-100); }
th { color: var(--gray-600); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.03em; }
tr:hover td { background: var(--gray-50); }
td.numeric, th.numeric { text-align: right; }

/* ---------- Badges ---------- */
.badge {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
}
.badge-ok { background: var(--success-bg); color: var(--success-text); }
.badge-warning { background: var(--warning-bg); color: var(--warning-text); }
.badge-expired { background: var(--red-light); color: var(--red-dark); }
.badge-unknown { background: var(--gray-100); color: var(--gray-600); }
.badge-super-admin { background: var(--red-light); color: var(--red-dark); }
.badge-admin { background: var(--blue-light); color: var(--blue-dark); }
.badge-user { background: var(--gray-100); color: var(--gray-600); }
.badge-viewer { background: var(--blue-light); color: var(--blue); }
.badge-inactive { background: var(--gray-100); color: var(--gray-400); }
.badge-sla { background: var(--warning-bg); color: var(--warning-text); }

/* Customer Type badges (Customers list/detail) -- see CUSTOMER_TYPES and
   CUSTOMER_TYPE_LABELS in app/models.py for the full set of values. */
.badge-type-business { background: var(--blue-light); color: var(--blue-dark); }
.badge-type-private { background: var(--gray-100); color: var(--gray-600); }
.badge-type-sla { background: var(--warning-bg); color: var(--warning-text); }
.badge-type-school { background: var(--success-bg); color: var(--success-text); }
.badge-type-government { background: var(--purple-bg); color: var(--purple-text); }
.badge-type-doctor { background: var(--teal-bg); color: var(--teal-text); }
.badge-type-internal { background: var(--gray-100); color: var(--gray-400); }

/* ---------- Buttons ---------- */
.btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 9px 16px;
    border-radius: var(--radius);
    font-size: 14px;
    font-weight: 600;
    border: 1px solid transparent;
    cursor: pointer;
    text-decoration: none;
}
.btn:hover { text-decoration: none; }
.btn-primary { background: var(--blue); color: #fff; }
.btn-primary:hover { background: var(--blue-dark); }
.btn-danger { background: var(--red); color: #fff; }
.btn-danger:hover { background: var(--red-dark); }
/* Only the "not selected" half of a toggle pair (e.g. Daily / Weekly / Monthly) still uses .btn-ghost: every other button is solid blue (.btn-primary).
   It is a light blue tint with a blue outline, so it is in the blue theme but clearly the quieter one next to the solid selected button. */
.btn-ghost { background: var(--blue-light); color: var(--blue); border-color: var(--blue); }
.btn-ghost:hover { background: var(--blue-light); filter: brightness(0.95); }
.btn-small { padding: 6px 12px; font-size: 13px; }
.btn-pill { border-radius: 999px; }
.btn-success { background: var(--success-bg); color: var(--success-text); border: 1px solid var(--success-border); }
.btn-success:hover { background: var(--success-border); }
.btn-warning { background: var(--warning-bg); color: var(--warning-text); border: 1px solid var(--warning-border); }
.btn-warning:hover { background: var(--warning-border); }
.btn-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

/* ---------- Result pills (e.g. Connection Test outcome) ---------- */
.result-pill {
    display: inline-block;
    padding: 7px 16px;
    border-radius: 999px;
    font-size: 15px;
    font-weight: 600;
    line-height: 1.2;
    border: 1px solid transparent;
}
.result-pill-ok { background: var(--success-bg); color: var(--success-text); border-color: var(--success-border); }
.result-pill-warning { background: var(--warning-bg); color: var(--warning-text); border-color: var(--warning-border); }
.result-pill-danger { background: var(--red-light); color: var(--red-dark); border-color: var(--danger-border); }
.btn:disabled, .btn:disabled:hover,
.btn.disabled, .btn.disabled:hover {
    opacity: 0.45;
    cursor: not-allowed;
    background: var(--gray-200);
    color: var(--gray-600);
    pointer-events: none;
}
.pagination-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    padding: 14px 4px 4px;
    margin-top: 8px;
    border-top: 1px solid var(--gray-200);
}
.pagination-status { font-size: 13px; color: var(--gray-600); }

/* ---------- Forms ---------- */
form .form-row { margin-bottom: 16px; }
label { display: block; font-size: 13px; font-weight: 600; color: var(--gray-600); margin-bottom: 6px; }
input[type=text], input[type=email], input[type=password], input[type=date], input[type=time], input[type=search],
select, textarea {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--gray-200);
    border-radius: var(--radius);
    font-size: 14px;
    font-family: inherit;
    background: var(--white);
    color: var(--gray-800);
}
input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--blue);
    box-shadow: 0 0 0 3px var(--blue-light);
}
textarea { resize: vertical; min-height: 80px; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
/* Same issue as .tab-panel/.file-preview-overlay/.display-popup/.chat-feed
   below: .form-grid's own `display: grid` has the same specificity as the
   browser default `[hidden] { display: none }` rule, and author styles
   win ties over the UA stylesheet -- so a form-grid toggled via the
   `hidden` attribute/property (e.g. tickets/form.html's inline New
   Contact fields) would otherwise stay visible instead of collapsing. */
.form-grid[hidden] { display: none; }
.checkbox-row { display: flex; align-items: center; gap: 8px; }
.checkbox-row input { width: auto; }

/* ---------- Disk cards (Asset -> Disks tab) ---------- */
.disk-list { display: flex; flex-direction: column; gap: 16px; }
.disk-card {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px;
    border: 1px solid var(--gray-200);
    border-radius: var(--radius);
    padding: 18px 20px;
}
.disk-card-col { display: flex; flex-direction: column; gap: 10px; }
.disk-card-title { display: flex; align-items: center; gap: 8px; font-weight: 700; color: var(--gray-800); margin-bottom: 2px; }
.disk-icon { font-size: 16px; }
.disk-field { display: flex; align-items: baseline; gap: 12px; font-size: 14px; }
.disk-field span { color: var(--gray-600); min-width: 150px; flex-shrink: 0; }
.disk-field strong { color: var(--gray-800); font-weight: 600; }
.disk-more { margin-top: 2px; }
.disk-more summary { cursor: pointer; color: var(--blue); font-size: 13px; font-weight: 600; list-style: none; }
.disk-more summary::-webkit-details-marker { display: none; }
.disk-more .disk-field { margin-top: 8px; }
.disk-bar-track { background: var(--gray-100); border-radius: 999px; height: 8px; overflow: hidden; margin-top: 6px; }
.disk-bar-fill { height: 100%; border-radius: 999px; }
.disk-bar-ok { background: var(--blue); }
.disk-bar-warning { background: #e0a020; }
.disk-bar-critical { background: var(--red); }
.disk-bar-caption { display: flex; justify-content: space-between; font-size: 12px; color: var(--gray-600); margin-top: 4px; }
@media (max-width: 700px) {
    .disk-card { grid-template-columns: 1fr; }
}

.search-form { display: flex; gap: 10px; margin-bottom: 20px; max-width: 480px; flex-wrap: wrap; }
.search-form input { flex: 1; }

.empty-state { color: var(--gray-400); padding: 32px 20px; text-align: center; font-size: 14px; }
.empty-state::before {
    content: "\25A2";
    display: block;
    font-size: 22px;
    color: var(--gray-300);
    margin-bottom: 10px;
}
.empty-state-title { color: var(--gray-800); font-weight: 700; font-size: 15px; margin-bottom: 4px; }
.empty-state-text { color: var(--gray-600); font-size: 13px; max-width: 420px; margin: 0 auto; }

.section-title { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }

/* ---------- Collapsible sections (<details class="collapsible"> whose <summary class="section-title"> holds the heading) ----------
   Native <details>, so it works without JavaScript; a small script on the page only REMEMBERS which are shut. */
details.collapsible > summary { list-style: none; cursor: pointer; justify-content: flex-start; gap: 8px; margin-bottom: 0; user-select: none; }
details.collapsible > summary::-webkit-details-marker { display: none; }
details.collapsible > summary::before, details > summary.chev::before, .collapsible-card summary::before, .disk-more summary::before {
    content: ""; display: inline-block; flex: 0 0 auto; box-sizing: border-box; width: 12px; height: 12px; margin: 0 14px 3px 6px; vertical-align: middle;
    border-right: 3px solid currentColor; border-bottom: 3px solid currentColor; transform: rotate(-45deg); opacity: .85; transition: transform .12s ease; }
details.collapsible[open] > summary::before, details[open] > summary.chev::before, .collapsible-card[open] summary::before, .disk-more[open] summary::before { transform: rotate(45deg); margin-bottom: 6px; }
details > summary.chev { list-style: none; cursor: pointer; }
details > summary.chev::-webkit-details-marker { display: none; }
/* ONE arrow everywhere: the same 12px (3px stroke) chevron, drawn with borders so it looks identical in every browser and font, for every expand / collapse (router sections, profile boxes, site-link boxes, cards, "more" lines). */
details.collapsible > summary h2 { margin: 0; }
details.collapsible[open] > summary { margin-bottom: 12px; }
details.collapsible > summary:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; border-radius: 4px; }
details.collapsible.plain { margin-bottom: 16px; }
details.card.collapsible { margin-bottom: 16px; }
.collapsible-pill > summary::before { content: none !important; }
/* a collapsible box whose header also carries a status line (site-link boxes) */
details.collapsible > summary.box-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; }
.box-head .box-head-meta { margin-left: auto; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 13px; }

/* ---------- Admin landing ---------- */
.admin-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 16px;
}
.admin-tile {
    background: var(--white);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    border: 1px solid var(--gray-200);
    padding: 22px;
    display: block;
    color: inherit;
}
.admin-tile:hover { text-decoration: none; box-shadow: 0 4px 14px rgba(20, 30, 60, 0.12); }
.admin-tile-icon {
    width: 40px;
    height: 40px;
    border-radius: 8px;
    background: var(--blue-light);
    color: var(--blue-dark);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    margin-bottom: 14px;
}
.admin-tile h3 { margin: 0 0 4px; }
.admin-tile p { margin: 0; font-size: 13px; color: var(--gray-600); }
.breadcrumb { font-size: 13px; color: var(--gray-400); margin-bottom: 4px; }
.breadcrumb a { color: var(--gray-600); font-weight: 500; }

/* ---------- Ticket status pill row (dashboard) ---------- */
.pill-row {
    display: flex;
    align-items: center;
    gap: 40px;
    flex-wrap: wrap;
    row-gap: 18px;
}
.pill-stat { display: flex; align-items: center; gap: 12px; }
.pill-stat .pill-count { font-size: 26px; font-weight: 700; color: var(--gray-800); }
.status-pill {
    display: inline-block;
    padding: 4px 14px;
    border-radius: 999px;
    font-size: 13px;
    font-weight: 600;
}
.status-pill-open { background: var(--blue-light); color: var(--blue); }
.status-pill-pending { background: var(--warning-bg); color: var(--warning-text); }
.status-pill-due { background: var(--due-bg); color: var(--due-text); }
.status-pill-overdue { background: var(--red-light); color: var(--red-dark); }
.status-pill-neutral { background: var(--gray-100); color: var(--gray-600); }
.status-pill-ok { background: var(--success-bg); color: var(--success-text); }
button.status-pill {
    cursor: pointer;
    border: none;
    font: inherit;
}
button.status-pill:hover { filter: brightness(0.93); }

/* Background color for the ticket list's own quick-edit Status/Priority/
   Due controls (tickets/list.html) -- same color tokens as status-pill-*
   above, just applied to a <select>/<input> instead of a badge, so a
   given color still means the same thing at a glance either way. The
   Jinja side always emits field-color-<something-or-empty>; an empty
   suffix (no due date set, an unmapped value) matches no rule here and
   is harmless. */
select.field-color-yellow, input.field-color-yellow { background: var(--warning-bg); color: var(--warning-text); }
select.field-color-blue, input.field-color-blue { background: var(--blue-light); color: var(--blue); }
select.field-color-orange, input.field-color-orange { background: var(--due-bg); color: var(--due-text); }
select.field-color-green, input.field-color-green { background: var(--success-bg); color: var(--success-text); }
select.field-color-red, input.field-color-red { background: var(--red-light); color: var(--red-dark); }
select.field-color-gray, input.field-color-gray { background: var(--gray-100); color: var(--gray-600); }

/* ---------- Dashboard split row (two cards side by side) ---------- */
.dash-split {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    align-items: stretch;
    margin-bottom: 20px;
}
.dash-split .card { margin-bottom: 0; }

/* ---------- Search results ---------- */
.result-group { margin-bottom: 20px; }
.result-group h2 { font-size: 15px; }

/* ---------- Customer entity header ---------- */
.entity-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 20px;
    background: var(--white);
    border: 1px solid var(--gray-200);
    border-radius: var(--radius);
    padding: 18px 20px;
}
.entity-header-main { display: flex; align-items: center; gap: 16px; min-width: 0; }
.entity-back {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 999px;
    color: var(--gray-600);
    border: 1px solid var(--gray-200);
    flex-shrink: 0;
    font-size: 16px;
}
.entity-back:hover { background: var(--gray-100); text-decoration: none; }

.entity-avatar {
    width: 56px;
    height: 56px;
    border-radius: 10px;
    flex-shrink: 0;
    overflow: hidden;
    background: var(--blue-light);
    color: var(--blue-dark);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 18px;
    position: relative;
}
.entity-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.entity-avatar-edit {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(8, 86, 125, 0.75);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    text-align: center;
    line-height: 1.2;
    opacity: 0;
    transition: opacity 0.15s;
    cursor: pointer;
}
.entity-avatar:hover .entity-avatar-edit { opacity: 1; }

.entity-name-block { min-width: 0; }
.entity-name-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.entity-name-row h1 { margin: 0; font-size: 20px; }
.entity-rank-form select {
    width: auto;
    padding: 4px 10px;
    font-size: 12px;
    font-weight: 600;
    border-radius: 999px;
    background: var(--gray-100);
    color: var(--gray-600);
    border: 1px solid var(--gray-200);
}
.entity-meta { display: flex; flex-wrap: wrap; gap: 4px 18px; margin-top: 6px; font-size: 13px; color: var(--gray-600); }
.entity-meta span { display: inline-flex; align-items: center; gap: 6px; }
.entity-meta .meta-icon { color: var(--gray-400); font-size: 12px; }
.entity-actions { display: flex; align-items: flex-start; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }

.overflow-menu { position: relative; }
.overflow-menu summary {
    list-style: none;
    cursor: pointer;
    width: 34px;
    height: 34px;
    border-radius: 999px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--gray-200);
    color: var(--gray-600);
    font-size: 16px;
}
.overflow-menu summary::-webkit-details-marker { display: none; }
.overflow-menu summary:hover { background: var(--gray-100); }
.overflow-menu[open] summary { background: var(--gray-100); }
.overflow-menu-list {
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    background: var(--white);
    border: 1px solid var(--gray-200);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    min-width: 190px;
    z-index: 20;
    overflow: hidden;
}
.overflow-menu-list a, .overflow-menu-list button {
    display: block;
    width: 100%;
    text-align: left;
    padding: 10px 14px;
    font-size: 14px;
    color: var(--gray-800);
    background: none;
    border: none;
    cursor: pointer;
    font-family: inherit;
}

/* Quick-add dropdown (topbar "+ Add" button) — reuses .overflow-menu's
   positioning/list, just with a labeled primary-button-style trigger
   instead of the small round "..." icon. */
.quick-add-menu summary {
    width: auto;
    height: auto;
    border-radius: var(--radius);
    padding: 9px 16px;
    font-size: 14px;
    font-weight: 600;
    background: var(--blue);
    color: #fff;
    border: none;
    gap: 6px;
}
.quick-add-menu summary:hover { background: var(--blue-dark); }
.quick-add-menu[open] summary { background: var(--blue-dark); }
.quick-add-menu .caret { font-size: 10px; }
.overflow-menu-list a:hover, .overflow-menu-list button:hover { background: var(--gray-100); text-decoration: none; }
.overflow-menu-list .danger { color: var(--red); }

/* ---------- Tabs ---------- */
.tab-nav {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--gray-200);
    margin: 18px 0 0;
    overflow-x: auto;
    scrollbar-width: thin;
}
.tab-nav::-webkit-scrollbar { height: 4px; }
.tab-nav::-webkit-scrollbar-thumb { background: var(--gray-200); border-radius: 999px; }
.tab-nav-wrapper { display: flex; align-items: center; margin: 18px 0 0; }
.tab-nav-wrapper .tab-nav { margin: 0; flex: 1; min-width: 0; }
.tab-nav-arrow {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--white);
    border: 1px solid var(--gray-200);
    border-radius: 999px;
    box-shadow: var(--shadow);
    color: var(--gray-600);
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
    padding: 0;
}
.tab-nav-arrow-left { margin-right: 6px; }
.tab-nav-arrow-right { margin-left: 6px; }
.tab-nav-arrow:hover { color: var(--blue); }
.tab-nav-wrapper:not(.tab-nav-scrollable) .tab-nav-arrow { display: none; }

.collapsible-card {
    background: var(--white);
    border: 1px solid var(--gray-200);
    border-radius: var(--radius);
    padding: 14px 20px;
    margin-bottom: 20px;
}
.collapsible-card summary {
    cursor: pointer;
    font-weight: 600;
    font-size: 15px;
    list-style: none;
}
.collapsible-card summary::-webkit-details-marker { display: none; }
.collapsible-card[open] summary { margin-bottom: 14px; }

/* Modifier: a pill-button toggle instead of the plain triangle marker,
   for collapsible sections that are the main content of a page (e.g.
   Assets / Edge Gateways) rather than a secondary sub-section within a
   tab -- those keep the plain .collapsible-card look above unchanged. */
#network-devices-table th:nth-child(2),
#network-devices-table td:nth-child(2) {
    min-width: 100px;
}
.nd-type-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--gray-100);
    font-size: 12px;
    font-weight: 600;
    color: var(--gray-600);
}

.nd-scroll-area {
    /* Sized for ~4 fully-populated rows (Web/Web(HTTPS)/RDP buttons +
       SSH text + Monitor checkbox + Demote all stacked in one Edge
       Access cell, the tallest a row gets) plus the sticky header --
       an estimate from the CSS values involved, not a measured
       render, so nudge this if it's off in practice. A device with
       nothing in Edge Access is much shorter, so more than 4 of
       those fit at once. */
    max-height: 520px;
    overflow-y: auto;
}
.nd-scroll-area thead th {
    position: sticky;
    top: 0;
    background: var(--white);
    z-index: 2;
    box-shadow: 0 1px 0 var(--gray-200);
}

.table-scroll-x {
    overflow-x: auto;
}
.table-scroll-x-top {
    overflow-x: auto;
    overflow-y: hidden;
    height: 16px;
    margin-bottom: 4px;
}
.table-scroll-x-top-inner {
    height: 1px;
}

#network-devices-table th,
#network-devices-table td {
    vertical-align: top;
}
.nd-model-cell {
    min-width: 180px;
    max-width: 240px;
}
.nd-model-cell .attachment-meta-text {
    display: block;
    margin-top: 2px;
    max-width: 170px;
    line-height: 1.35;
}
.nd-toner-cell {
    min-width: 90px;
}
.nd-lastseen-cell {
    min-width: 90px;
    white-space: nowrap;
}

.sortable-th {
    cursor: pointer;
    user-select: none;
}
.sortable-th:hover { color: var(--blue); }
.sortable-th-indicator {
    display: inline-block;
    font-size: 10px;
    margin-left: 2px;
}

.collapsible-pill > summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    cursor: pointer;
    list-style: none;
}
.collapsible-pill > summary::-webkit-details-marker { display: none; }
.collapsible-pill > summary::before { content: none; }
.collapsible-pill-toggle .label-expand { display: none; }
.collapsible-pill:not([open]) .collapsible-pill-toggle .label-collapse { display: none; }
.collapsible-pill:not([open]) .collapsible-pill-toggle .label-expand { display: inline; }

.confirm-danger-dialog {
    border: none;
    border-radius: var(--radius);
    padding: 0;
    max-width: 440px;
    width: 90%;
    box-shadow: var(--shadow);
    overflow: hidden;
}
.confirm-danger-dialog::backdrop { background: rgba(0, 0, 0, 0.55); }
.confirm-danger-header {
    background: var(--red-light);
    color: var(--red-dark);
    padding: 20px 24px;
    display: flex;
    align-items: center;
    gap: 12px;
    border-bottom: 3px solid var(--red);
}
.confirm-danger-icon { font-size: 26px; line-height: 1; }
.confirm-danger-title { margin: 0; font-size: 17px; }
.confirm-danger-message { padding: 18px 24px; margin: 0; color: var(--gray-700); line-height: 1.5; }
.confirm-danger-actions { display: flex; justify-content: flex-end; gap: 10px; padding: 0 24px 20px; }
.tab-link {
    padding: 12px 4px;
    margin-right: 24px;
    font-size: 14px;
    font-weight: 600;
    color: var(--gray-600);
    border-bottom: 2px solid transparent;
    white-space: nowrap;
    background: none;
    border-top: none;
    border-left: none;
    border-right: none;
    cursor: pointer;
}
.tab-link:hover { color: var(--blue); text-decoration: none; }
.tab-link.active { color: var(--gray-800); border-bottom-color: var(--red); }

.tab-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 18px 0 16px; flex-wrap: wrap; }
.tab-panel[hidden] { display: none; }
/* Same reasoning as .card's own overflow-x above -- a table (Contacts,
   Network Devices, Tickets, etc.) sitting directly in a tab without its
   own nested card would otherwise be free to push the whole page wider
   than the viewport on a narrow screen instead of just scrolling in
   place. */
.tab-panel { overflow-x: auto; }

.inline-form-toggle { display: none; margin-bottom: 20px; }
.inline-form-toggle.open { display: block; }

/* ---------- Passwords ---------- */
.password-value { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; letter-spacing: 1px; }

/* ---------- Attachments ---------- */
.attachment-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--gray-100); }
.attachment-row:last-child { border-bottom: none; }
.attachment-file { display: flex; align-items: center; gap: 12px; min-width: 0; }
.attachment-icon {
    width: 36px;
    height: 36px;
    border-radius: 8px;
    background: var(--gray-100);
    color: var(--gray-600);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 700;
    flex-shrink: 0;
    text-transform: uppercase;
}
.attachment-name { font-weight: 600; color: var(--gray-800); }
.attachment-meta-text { font-size: 12px; color: var(--gray-600); }

/* ---------- Small avatar chip (customer list) ---------- */
.avatar-chip {
    width: 28px;
    height: 28px;
    border-radius: 6px;
    background: var(--blue-light);
    color: var(--blue-dark);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 700;
    overflow: hidden;
    vertical-align: middle;
    margin-right: 8px;
}
.avatar-chip img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---------- Theme switch (dark theme toggle) ---------- */
.theme-switch {
    display: flex;
    align-items: center;
    gap: 9px;
    cursor: pointer;
    font-size: 13px;
    font-weight: 600;
    color: var(--gray-600);
    user-select: none;
    white-space: nowrap;
}
.theme-switch input {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}
.theme-switch-track {
    position: relative;
    width: 38px;
    height: 22px;
    flex-shrink: 0;
    background: var(--gray-200);
    border-radius: 999px;
    transition: background 0.15s;
}
.theme-switch-thumb {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--white);
    box-shadow: var(--shadow);
    transition: transform 0.15s;
}
.theme-switch input:checked + .theme-switch-track { background: var(--blue); }
.theme-switch input:checked + .theme-switch-track .theme-switch-thumb { transform: translateX(16px); }
.theme-switch input:focus-visible + .theme-switch-track { box-shadow: 0 0 0 3px var(--blue-light); }
.theme-switch-icon { font-size: 13px; line-height: 1; }

/* ---------- File preview modal (Leads/Task/Customer/Asset documents) ---------- */
body.file-preview-open { overflow: hidden; }

.file-preview-overlay {
    position: fixed;
    inset: 0;
    background: rgba(10, 16, 28, 0.55);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    z-index: 1000;
}
.file-preview-overlay[hidden] { display: none; }

.file-preview-dialog {
    background: var(--white);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    width: min(920px, 100%);
    max-height: min(85vh, 900px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.file-preview-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 18px;
    border-bottom: 1px solid var(--gray-200);
    flex-shrink: 0;
}

.file-preview-title {
    font-weight: 600;
    color: var(--gray-800);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.file-preview-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}

.file-preview-close {
    border: none;
    background: transparent;
    font-size: 22px;
    line-height: 1;
    color: var(--gray-600);
    cursor: pointer;
    padding: 2px 8px;
    border-radius: 6px;
}
.file-preview-close:hover { background: var(--gray-100); color: var(--gray-800); }

.file-preview-body {
    padding: 18px;
    overflow: auto;
    flex: 1;
}

.file-preview-message {
    color: var(--gray-600);
    text-align: center;
    padding: 40px 0 16px;
}

.file-preview-frame {
    width: 100%;
    height: 72vh;
    border: none;
    display: block;
}

.file-preview-image {
    max-width: 100%;
    display: block;
    margin: 0 auto;
}

.file-preview-text {
    white-space: pre-wrap;
    word-break: break-word;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 13px;
    color: var(--gray-800);
}

.file-preview-table-wrap { overflow: auto; }

.file-preview-table {
    border-collapse: collapse;
    font-size: 13px;
    color: var(--gray-800);
}
.file-preview-table th,
.file-preview-table td {
    border: 1px solid var(--gray-200);
    padding: 6px 10px;
    text-align: left;
    white-space: nowrap;
}
.file-preview-table th { background: var(--gray-50); font-weight: 600; }

.file-preview-note {
    margin-top: 10px;
    font-size: 12px;
    color: var(--gray-600);
}

.file-preview-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 12px;
}
.file-preview-tab {
    border: 1px solid var(--gray-200);
    background: var(--gray-50);
    color: var(--gray-800);
    border-radius: 999px;
    padding: 4px 12px;
    font-size: 12.5px;
    cursor: pointer;
}
.file-preview-tab.active { background: var(--blue); border-color: var(--blue); color: #fff; }

.file-preview-docx {
    max-width: 720px;
    margin: 0 auto;
    color: var(--gray-800);
    line-height: 1.55;
}
.file-preview-docx table { border-collapse: collapse; margin: 12px 0; }
.file-preview-docx table td, .file-preview-docx table th { border: 1px solid var(--gray-200); padding: 6px 10px; }
.file-preview-docx img { max-width: 100%; }

@media (max-width: 640px) {
    .file-preview-overlay { padding: 0; }
    .file-preview-dialog { width: 100%; height: 100%; max-height: 100%; border-radius: 0; }
}

/* ---------- Display board (wall/TV dashboard at /display) ----------
   Always dark (the template hardcodes data-theme="dark" on <html>), so
   this deliberately doesn't need its own light/dark split — it just
   reuses the dark-theme variable values set above. Text sizes are
   bumped up throughout since this is read from across a room, not from
   a desk. */
.display-board { max-width: 1900px; margin: 0 auto; padding: 16px 28px 24px; }

/* Header reuses the same .topbar/.sidebar-brand markup and classes every
   other (staff-facing) page's header is built from, so this board reads
   as the same app instead of a bolted-on separate site — just without
   the +Add menu or global search, which don't apply to a read-only
   kiosk page with no logged-in staff account behind it. */
.display-brand { border-bottom: none; padding: 0; }
.display-topbar-actions { gap: 20px; }
.display-clock { text-align: right; }
.display-clock-time { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--gray-800); line-height: 1; }
.display-clock-date { font-size: 12px; color: var(--gray-600); margin-top: 4px; }

.display-grid {
    display: grid;
    /* Fixed at 3 columns (rather than auto-fit/minmax, which was
       collapsing to a single column any time the effective viewport —
       including a browser zoomed in on a wall-mounted screen — read as
       narrower than ~1360px) so this always lays out the same
       side-by-side 3-across grid; the media queries below step it down
       to 2 and then 1 column only for genuinely narrow screens. */
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
    align-items: start;
}
.display-panel h2 { font-size: 17px; margin-top: 0; }
.display-panel .pill-count { font-size: 30px; }
.display-panel table { font-size: 15px; }
.display-panel th { font-size: 12px; }

/* Every block on the grid renders as the same fixed-size tile (matching
   the compact "Ticket Status" pill-only block) instead of growing to
   whatever its longest list happens to be — a uniform grid reads much
   better from across a room. This only works because every list-style
   block is capped server-side to DISPLAY_LIST_LIMIT rows (see
   app/routes/display.py); overflow:hidden is just a safety net, not the
   mechanism doing the fitting. */
.display-panel {
    display: flex;
    flex-direction: column;
    /* Slightly shorter than this used to be, and .card's usual
       margin-bottom is dropped in favor of .display-grid's own gap —
       otherwise the two stack and the 3rd row (Leads/Resolved Tickets)
       needs a scroll to reach on a normal monitor. */
    height: 260px;
    margin-bottom: 0;
    overflow: hidden;
}
.display-panel h2 { flex-shrink: 0; }
.display-panel .section-title { flex-shrink: 0; }
/* Pill-only blocks (Ticket Status, Customers & Equipment) have nothing
   else to fill the fixed height with — let their pill row grow to fill
   it and vertically center its (possibly wrapped) rows, rather than
   leaving them stranded at the top above a slab of empty space. Blocks
   that pair a pill row with a table below it (Leads) deliberately don't
   get this — the table still needs room of its own. */
.display-panel-pills .pill-row { flex: 1; align-content: center; }
/* 2026-09: adding the Collected/Delivered ticket status pushed Ticket
   Status from 3 pill-rows to 4 (9 pills -> 10), which the fixed 260px
   .display-panel height above no longer had room for -- the bottom row
   (Overdue) was clipped by that panel's overflow:hidden. Tightening just
   this row-gap (row-gap only, not the 40px column gap) buys back enough
   vertical space for a 4th row without touching every other pill-only
   tile's spacing or the shared panel height. */
.display-panel-pills .pill-row { row-gap: 10px; }

/* The dedicated "View All" pages (display/resolved_tickets.html and its
   siblings) reuse the .card.display-panel look for visual consistency
   but show the full, uncapped list, so they opt back out of the fixed
   height and clipping above. */
.display-panel-full { height: auto; overflow: visible; margin-bottom: 20px; }

/* The Alerts tile (disk space, tickets stuck in Resolved, contacts
   needing review — see _combined_alerts in app/routes/display.py) used
   to be full-width banners above the grid; folded into a fixed-size
   grid tile instead so an alert appearing doesn't shove every other
   block down the page. Keeps the same red warning coloring those
   banners had. */
.display-panel-alert {
    background: var(--red-light);
    border: 1px solid var(--danger-border);
    border-left: 4px solid var(--red);
}
.display-panel-alert h2 { color: var(--red-dark); }

/* Green instead of red when there's currently nothing to flag — the
   template only adds .display-panel-alert when the tile actually has
   alerts to show (see display/index.html), so an all-clear board reads
   as all-clear at a glance instead of a permanently "alarming" red tile. */
.display-panel-alert-ok {
    background: var(--success-bg);
    border: 1px solid var(--success-border);
    border-left: 4px solid var(--success-text);
}
.display-panel-alert-ok h2 { color: var(--success-text); }
.alert-list { list-style: none; margin: 0; padding: 0; overflow-y: auto; }
.alert-list li {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 8px 0;
    border-bottom: 1px solid var(--danger-border);
    font-size: 14px;
    line-height: 1.4;
}
.alert-list li:last-child { border-bottom: none; }

/* New-ticket popup: fixed banner near the top of the viewport, slides
   down into view. Dismissed by display/index.html's own JS either after
   a timeout or on click; [hidden] falls back to plain display:none so it
   starts (and stays, if JS never un-hides it) completely off-screen. */
.display-popup {
    position: fixed;
    top: 100px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: 14px;
    background: var(--blue);
    color: var(--white);
    box-shadow: var(--shadow);
    border-radius: var(--radius);
    padding: 16px 24px;
    max-width: 90vw;
    z-index: 100;
    cursor: pointer;
    animation: display-popup-in 0.4s ease-out;
}
.display-popup[hidden] { display: none; }
.display-popup-icon { font-size: 24px; }
.display-popup-title { font-weight: 700; font-size: 15px; }
.display-popup-body { font-size: 14px; opacity: 0.9; }
@keyframes display-popup-in {
    from { transform: translate(-50%, -30px); opacity: 0; }
    to { transform: translate(-50%, 0); opacity: 1; }
}

@media (max-width: 1400px) {
    .display-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 1000px) {
    .display-grid { grid-template-columns: 1fr; }
    .display-topbar { grid-template-columns: 1fr; row-gap: 12px; }
    .display-topbar .topbar-actions { justify-content: center; }
}

/* ---------- Responsive ---------- */
@media (max-width: 860px) {
    .app-shell { flex-direction: column; }
    .sidebar {
        position: relative;
        width: 100%;
        flex: none;
        height: auto;
        border-right: none;
        border-bottom: 1px solid var(--gray-200);
    }
    .sidebar-nav { flex-direction: row; flex-wrap: wrap; }
    .sidebar-group { flex-direction: column; width: 100%; }
    .sidebar-group-body { width: 100%; }
    .sidebar-nav-bottom { margin-top: 0; flex-direction: row; align-items: center; flex-wrap: wrap; }
    .sidebar-nav-partition { flex-direction: row; align-items: center; flex-wrap: wrap; }
    .sidebar-nav-partition .sidebar-divider { display: none; }
    .topbar {
        padding: 18px 20px;
        grid-template-columns: 1fr;
        row-gap: 12px;
    }
    .topbar-left { order: 2; }
    .topbar-titles { order: 1; text-align: left; }
    .topbar-actions { order: 3; justify-content: flex-start; }
    .page { padding: 20px 20px 48px; }
    .dash-split { grid-template-columns: 1fr; }
}

/* True phone widths -- 860px above handles the tablet-ish transition
   (sidebar stacks above content) but doesn't address a screen this
   narrow on its own: the topbar's search box and Go To Display link
   were still being forced onto one unwrapping row, which either
   pushed the whole page wider than the viewport (needing horizontal
   scroll to see the rest) or squeezed the button's own text into an
   awkward two-line wrap -- both symptoms of the same underlying gap,
   not two separate bugs. */
@media (max-width: 480px) {
    .page { padding: 14px 14px 40px; }
    .topbar { padding: 14px 16px; }
    .topbar-actions { justify-content: stretch; }
    .global-search { flex: 1 1 100%; order: 1; }
    .topbar-display-link { order: 2; }
    /* Every table on a narrow screen scrolls within its own card
       instead of forcing the whole page wider -- see .card's own
       overflow-x below, which is what actually makes this possible;
       this just stops a cell's content from being squeezed into an
       unreadable wrap before that scrolling ever kicks in. */
    table { white-space: nowrap; }
}

/* ---------- Rich text editor (ticket reply / canned response body) ---------- */
.rich-editor-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    padding: 6px;
    border: 1px solid var(--gray-200);
    border-bottom: none;
    border-radius: var(--radius) var(--radius) 0 0;
    background: var(--gray-50);
}
.rich-editor-btn {
    min-width: 30px;
    height: 30px;
    padding: 0 8px;
    border: 1px solid transparent;
    border-radius: 6px;
    background: none;
    color: var(--gray-800);
    font-size: 13px;
    cursor: pointer;
}
.rich-editor-btn:hover { background: var(--gray-100); border-color: var(--gray-200); }
.rich-editor-sep { width: 1px; background: var(--gray-200); margin: 4px 4px; }
.rich-editor-surface {
    min-height: 140px;
    max-height: 420px;
    overflow-y: auto;
    padding: 10px 12px;
    border: 1px solid var(--gray-200);
    border-radius: 0 0 var(--radius) var(--radius);
    background: var(--white);
    color: var(--gray-800);
    font-size: 14px;
    line-height: 1.5;
}
.rich-editor-surface:focus { outline: 2px solid var(--blue-accent); outline-offset: -1px; }
.rich-editor-surface img { max-width: 100%; border-radius: 4px; }
.rich-editor-surface p { margin: 0 0 10px; }
.rich-editor-surface ul, .rich-editor-surface ol { margin: 0 0 10px 20px; }

.variable-chip-row { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
.variable-chip {
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--blue-light);
    color: var(--blue-dark);
    font-size: 12px;
    font-weight: 600;
    border: 1px solid transparent;
    cursor: pointer;
}
.variable-chip:hover { border-color: var(--blue-accent); }

/* ---------- Ticket Activity: chat-style feed ---------- */
.chat-feed { display: flex; flex-direction: column; gap: 14px; }
/* Toggled by the Activity tab's Collapse/Expand button (tickets/detail.html)
   — needed explicitly because .chat-feed's own `display: flex` above is
   an author-level rule and would otherwise beat the browser's default
   (lower-priority) [hidden] behavior. */
.chat-feed[hidden] { display: none; }
.chat-row { display: flex; }
.chat-row.chat-row-me { justify-content: flex-end; }
.chat-row.chat-row-them { justify-content: flex-start; }

.chat-bubble {
    max-width: 78%;
    padding: 10px 14px;
    border-radius: 14px;
    background: var(--gray-100);
    color: var(--gray-800);
    font-size: 14px;
    line-height: 1.45;
}
.chat-row-me .chat-bubble { background: var(--blue-light); border-bottom-right-radius: 4px; }
.chat-row-them .chat-bubble { background: var(--gray-100); border-bottom-left-radius: 4px; }
.chat-meta { font-size: 11px; color: var(--gray-600); margin-bottom: 4px; display: flex; gap: 6px; align-items: center; }
.chat-bubble-body { white-space: pre-wrap; word-wrap: break-word; }

.chat-email-card {
    max-width: 86%;
    border: 1px solid var(--gray-200);
    border-radius: 10px;
    background: var(--white);
    overflow: hidden;
}
.chat-row-me .chat-email-card { border-color: var(--blue-light); }
.chat-email-card-header {
    padding: 8px 14px;
    background: var(--gray-50);
    border-bottom: 1px solid var(--gray-200);
    font-size: 12px;
    color: var(--gray-600);
}
.chat-email-card-header strong { color: var(--gray-800); }
.chat-email-card-body { padding: 14px; font-size: 14px; line-height: 1.5; color: var(--gray-800); }
.chat-email-card-body img { max-width: 100%; }
/* Wraps any rendered *_html|safe rich-editor content shown back to
   someone -- a comment, a task's instructions, a reminder's notes,
   etc. Without this, a pasted screenshot renders at its full native
   resolution and can blow out whatever narrow column/bubble/list row
   it landed in -- the editor's own surface already constrains images
   while typing (.rich-editor-surface img above), but that rule only
   applies there, not to the saved content shown back afterward.
   !important on the image rule specifically: sanitize_html's own
   allowlist keeps width/height/style on <img> (a legitimately-sized
   image someone links to needs those), and some browsers write an
   inline style="width:...px" straight onto a pasted image -- an
   inline style otherwise wins over a plain class selector like this
   one, which is exactly how a single pasted screenshot ended up
   rendering at full native resolution and breaking the whole page
   layout the first time this shipped. */
.rich-content img { max-width: 100% !important; height: auto !important; border-radius: 4px; display: block; margin: 4px 0; }
.rich-content { word-wrap: break-word; overflow-wrap: break-word; max-width: 100%; overflow-x: auto; }
.chat-email-card-body p { margin: 0 0 10px; }
.chat-email-card-body p:last-child { margin-bottom: 0; }
/* A received email shown in its own formatting (cleaned HTML, see app/inbound_html.py) */
.inbound-html { overflow-x: auto; word-wrap: break-word; }
.inbound-html img { max-width: 100%; height: auto; }
.inbound-html blockquote { margin: 6px 0 6px 4px; padding-left: 10px; border-left: 2px solid #ccc; color: #555; }
.inbound-html table { max-width: 100%; }
.inbound-missing-img { color: var(--gray-500, #888); font-size: 12px; font-style: italic; }

.chat-composer { margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--gray-200); }
.rich-editor-surface:empty:before { content: attr(data-placeholder); color: var(--gray-400); pointer-events: none; }

/* ---------- Customer Picker (searchable, replaces a plain <select>
   loaded with every customer at once -- see static/js/customer_picker.js) ---------- */
.customer-picker { position: relative; }
.customer-picker-results {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 50;
    background: var(--white);
    border: 1px solid var(--gray-200);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    max-height: 260px;
    overflow-y: auto;
}
.customer-picker-result {
    padding: 8px 12px;
    font-size: 14px;
    cursor: pointer;
}
.customer-picker-result:hover { background: var(--gray-100); }
.customer-picker-result-suspended { color: var(--gray-400); font-style: italic; }
.customer-picker-empty {
    padding: 8px 12px;
    font-size: 13px;
    color: var(--gray-400);
}
/* key/value facts inside a site-link box */
.ls-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px 18px; margin: 10px 0 0; }
.ls-facts dt { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; opacity: .65; margin: 0; }
.ls-facts dd { margin: 2px 0 0; font-size: 14px; }
.dash-split details.card.collapsible { margin-bottom: 0; align-self: start; }

/* Row action buttons: one even row that wraps cleanly (no overlap), every button the same width */
.row-actions { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.row-actions form { display: block; margin: 0; }
.row-actions .btn { min-width: 92px; justify-content: center; line-height: 1.25; white-space: nowrap; box-sizing: border-box; }
