/* ============================================================
   CompEdge Solutions: Admin Panel
   Design: dark navy sidebar + lime green accent, Inter/Space Grotesk
   ============================================================ */

:root {
    --nav-w:      260px;
    --clr-navy:   #0f172a;
    --clr-navy2:  #1e293b;
    --clr-green:  #4ade80;
    --clr-green2: #22c55e;
    --clr-bg:     #f8fafc;
    --clr-card:   #ffffff;
    --clr-border: #e2e8f0;
    --clr-text:   #1e293b;
    --clr-muted:  #64748b;
    --clr-faint:  #94a3b8;
    --clr-danger: #ef4444;
    --clr-warn:   #f59e0b;
    --clr-info:   #3b82f6;
    --r:          10px;
    --r-sm:       6px;
    --shadow:     0 1px 4px rgba(0,0,0,.08);
    --shadow-md:  0 4px 16px rgba(0,0,0,.10);
    --font:       'Inter', system-ui, sans-serif;
    --font-head:  'Space Grotesk', 'Inter', sans-serif;
    --t:          180ms ease;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { font-size: 16px; }

body {
    font-family: var(--font);
    background: var(--clr-bg);
    color: var(--clr-text);
    line-height: 1.5;
    min-height: 100vh;
}

a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }
button, input, select, textarea { font: inherit; }


/* ── Login Page ─────────────────────────────────────────── */

body.login-page {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--clr-navy);
    min-height: 100vh;
    padding: 1rem;
}

.login-wrap {
    width: 100%;
    max-width: 400px;
}

.login-card {
    background: var(--clr-card);
    border-radius: var(--r);
    padding: 2.5rem 2rem;
    box-shadow: var(--shadow-md);
}

.login-logo {
    display: flex;
    justify-content: center;
    margin-bottom: 1.5rem;
}

.login-title {
    font-family: var(--font-head);
    font-size: 1.5rem;
    font-weight: 700;
    text-align: center;
    color: var(--clr-navy);
    margin-bottom: .25rem;
}

.login-sub {
    text-align: center;
    color: var(--clr-muted);
    font-size: .875rem;
    margin-bottom: 1.75rem;
}

.login-form { display: flex; flex-direction: column; gap: 1rem; }

.field-group-checkbox label {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-weight: 400;
    cursor: pointer;
}
.field-group-checkbox input[type="checkbox"] {
    width: auto;
    accent-color: var(--clr-green2);
}


/* ── Layout Shell ───────────────────────────────────────── */

.admin-shell {
    display: flex;
    min-height: 100vh;
}

/* Sidebar */
.sidebar {
    position: fixed;
    top: 0; left: 0;
    width: var(--nav-w);
    height: 100vh;
    background: var(--clr-navy);
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    z-index: 100;
    transition: transform var(--t);
}

.sidebar-header {
    padding: 1.25rem 1.5rem;
    border-bottom: 1px solid rgba(255,255,255,.07);
}

.sidebar-header img { height: 36px; }

.sidebar-header .sidebar-tagline {
    font-size: .7rem;
    color: var(--clr-faint);
    margin-top: .25rem;
    text-transform: uppercase;
    letter-spacing: .08em;
}

.sidebar-nav {
    flex: 1;
    padding: 1rem 0;
}

.nav-section-label {
    font-size: .65rem;
    text-transform: uppercase;
    letter-spacing: .1em;
    color: rgba(148,163,184,.5);
    padding: 1rem 1.5rem .4rem;
}

.nav-link {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .625rem 1.5rem;
    color: var(--clr-faint);
    font-size: .875rem;
    font-weight: 500;
    border-left: 3px solid transparent;
    transition: color var(--t), background var(--t), border-color var(--t);
}

.nav-link:hover {
    color: #fff;
    background: rgba(255,255,255,.05);
}

.nav-link.active {
    color: var(--clr-green);
    border-left-color: var(--clr-green);
    background: rgba(74,222,128,.07);
}

.nav-link svg {
    width: 18px; height: 18px;
    flex-shrink: 0;
    opacity: .7;
}

.nav-link.active svg, .nav-link:hover svg { opacity: 1; }

.sidebar-footer {
    padding: 1rem 1.5rem;
    border-top: 1px solid rgba(255,255,255,.07);
}

.sidebar-footer .nav-link { padding-left: 0; border: none; }

/* Main content */
/* min-width:0 matters: as a flex child its automatic minimum size is the
   min-content width of whatever it holds, so a wide table would stretch the
   column and push the whole page sideways instead of letting .table-wrap
   scroll. */
.main-content {
    margin-left: var(--nav-w);
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.topbar {
    height: 60px;
    background: var(--clr-card);
    border-bottom: 1px solid var(--clr-border);
    display: flex;
    align-items: center;
    padding: 0 1.75rem;
    gap: 1rem;
    position: sticky;
    top: 0;
    z-index: 50;
}

.topbar-title {
    font-family: var(--font-head);
    font-size: 1rem;
    font-weight: 600;
    flex: 1;
}

.topbar-actions { display: flex; align-items: center; gap: .75rem; }

.hamburger {
    display: none;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--clr-text);
    padding: .25rem;
}

.page-body {
    padding: 1.75rem;
    flex: 1;
}

.page-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 1.5rem;
    flex-wrap: wrap;
    gap: .75rem;
}

.page-header h1 {
    font-family: var(--font-head);
    font-size: 1.375rem;
    font-weight: 700;
}


/* ── Cards ──────────────────────────────────────────────── */

.card {
    background: var(--clr-card);
    border-radius: var(--r);
    border: 1px solid var(--clr-border);
    box-shadow: var(--shadow);
}

.card-header {
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--clr-border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    flex-wrap: wrap;
}

.card-title {
    font-weight: 600;
    font-size: .9375rem;
}

.card-body { padding: 1.25rem; }


/* ── Stats Row ──────────────────────────────────────────── */

.stats-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.stat-card {
    background: var(--clr-card);
    border: 1px solid var(--clr-border);
    border-radius: var(--r);
    padding: 1.25rem;
    box-shadow: var(--shadow);
}

.stat-label {
    font-size: .75rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--clr-muted);
    margin-bottom: .4rem;
}

.stat-value {
    font-family: var(--font-head);
    font-size: 1.625rem;
    font-weight: 700;
    color: var(--clr-navy);
    line-height: 1;
}

.stat-card.accent .stat-value { color: var(--clr-green2); }


/* ── Tables ─────────────────────────────────────────────── */

.table-wrap {
    overflow-x: auto;
    max-width: 100%;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;

    /* Scroll affordance. The two white panes are anchored to the content
       (background-attachment: local) and the two shadows to the frame, so a
       shadow only shows on a side that still has content hidden past it.
       Nothing appears at all when the table already fits. */
    background:
        linear-gradient(to right, var(--clr-card) 30%, rgba(255,255,255,0)) left center,
        linear-gradient(to left,  var(--clr-card) 30%, rgba(255,255,255,0)) right center,
        radial-gradient(farthest-side at 0 50%,   rgba(15,23,42,.14), rgba(15,23,42,0)) left center,
        radial-gradient(farthest-side at 100% 50%, rgba(15,23,42,.14), rgba(15,23,42,0)) right center;
    background-repeat: no-repeat;
    background-size: 32px 100%, 32px 100%, 13px 100%, 13px 100%;
    background-attachment: local, local, scroll, scroll;
}

/* A phone cannot show eight columns at a readable width. Giving the wider
   tables a floor turns the wrap's overflow into a real sideways scroll
   instead of crushing every cell into a two-word stack. */
.table-scroll-md > table { min-width: 700px; }
.table-scroll-lg > table { min-width: 940px; }

table {
    width: 100%;
    border-collapse: collapse;
    font-size: .875rem;
}

thead th {
    text-align: left;
    padding: .625rem 1rem;
    background: var(--clr-bg);
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--clr-muted);
    border-bottom: 1px solid var(--clr-border);
    white-space: nowrap;
}

tbody tr {
    border-bottom: 1px solid var(--clr-border);
    transition: background var(--t);
}

tbody tr:last-child { border-bottom: none; }
tbody tr:hover { background: #f8fafc; }

tbody td {
    padding: .75rem 1rem;
    vertical-align: middle;
}

/* Totals rows. Without this they inherit the global padding reset and sit
   flush against the card border, reading as if the row escaped the card. */
tfoot td {
    padding: .75rem 1rem;
    vertical-align: middle;
}

.td-num { font-variant-numeric: tabular-nums; }
.td-right { text-align: right; }
.td-actions { white-space: nowrap; }


/* ── Sortable column headers ────────────────────────────── */

/* Two kinds of sortable header share this: an <a> where the sort lives in the
   URL (All Bills), and a <button> that admin.js adds where the sort is done in
   the page. They have to look identical. */
th.th-sort { padding: 0; }

th.th-sort > a,
th.th-sort > button {
    display: flex;
    align-items: center;
    gap: .3rem;
    width: 100%;
    padding: .625rem 1rem;
    color: inherit;
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    text-decoration: none;
    text-align: inherit;
    white-space: nowrap;
    background: none;
    border: 0;
    cursor: pointer;
}
th.th-sort.td-right > a,
th.th-sort.td-right > button { justify-content: flex-end; }
th.th-sort > a:hover,
th.th-sort > button:hover { color: var(--clr-text); background: #eef2f7; }
th.th-sort > button:focus-visible {
    outline: 2px solid var(--clr-green2);
    outline-offset: -2px;
}

/* The caret holds its space when idle, so a header does not jump on sort. */
th.th-sort .sort-caret {
    font-size: .6rem;
    line-height: 1;
    opacity: 0;
    transition: opacity var(--t);
}
th.th-sort > a:hover .sort-caret,
th.th-sort > button:hover .sort-caret { opacity: .45; }
th.th-sort.is-sorted { color: var(--clr-text); }
th.th-sort.is-sorted .sort-caret { opacity: 1; color: var(--clr-green2); }


/* ── Filter / sort bar ──────────────────────────────────── */

.filter-bar {
    display: flex;
    flex-direction: column;
    gap: .6rem;
    padding: .85rem 1.25rem;
    border-bottom: 1px solid var(--clr-border);
    background: #fcfdff;
}

.filter-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .45rem;
}

.filter-label {
    font-size: .7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--clr-faint);
    margin-right: .1rem;
}

.filter-bar input[type="search"],
.filter-bar select {
    width: auto;
    padding: .35rem .7rem;
    border: 1px solid var(--clr-border);
    border-radius: var(--r-sm);
    /* background-color, not the shorthand: the shorthand would wipe the
       chevron background-image the global select rule sets. */
    background-color: #fff;
    color: var(--clr-text);
    font-size: .82rem;
    -webkit-appearance: none;
    appearance: none;
}
.filter-bar select { padding-right: 1.9rem; background-position: right .55rem center; }
.filter-bar input[type="search"] { flex: 1 1 14rem; min-width: 0; max-width: 22rem; }
.filter-bar input[type="search"]:focus,
.filter-bar select:focus {
    outline: none;
    border-color: var(--clr-green);
    box-shadow: 0 0 0 3px rgba(74,222,128,.15);
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .28rem .7rem;
    border: 1px solid var(--clr-border);
    border-radius: 999px;
    background: #fff;
    color: var(--clr-text);
    font-size: .8rem;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    transition: background var(--t), border-color var(--t), color var(--t);
}
.chip:hover { background: var(--clr-bg); border-color: var(--clr-faint); }

.chip.is-active {
    background: var(--clr-navy);
    border-color: var(--clr-navy);
    color: #fff;
    font-weight: 600;
}
.chip.is-active:hover { background: var(--clr-navy2); border-color: var(--clr-navy2); }

/* A zero count still shows, greyed, so the absence is information too. */
.chip.is-empty { color: var(--clr-faint); }

.chip-count {
    padding: 0 .4rem;
    border-radius: 999px;
    background: #eef2f7;
    color: #475569;
    font-size: .72rem;
    font-weight: 600;
    line-height: 1.55;
}
.chip.is-active .chip-count { background: rgba(255,255,255,.22); color: #fff; }

/* The sort controls sit hard right while the row has spare width, and fall
   back into the normal flow once it wraps, so the label never strands itself
   on a line of its own. */
.filter-sort {
    display: flex;
    align-items: center;
    gap: .45rem;
    margin-left: auto;
}

.filter-summary {
    font-size: .8rem;
    color: var(--clr-muted);
}


/* ── Badges ─────────────────────────────────────────────── */

.badge {
    display: inline-flex;
    align-items: center;
    padding: .2rem .6rem;
    border-radius: var(--r-sm);
    font-size: .7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    white-space: nowrap;
}

.badge-draft    { background: #f1f5f9; color: #64748b; }
.badge-sent     { background: #eff6ff; color: #2563eb; }
.badge-paid     { background: #f0fdf4; color: #16a34a; }
.badge-usage    { background: #fffbeb; color: #b45309; }
.badge-target   { background: #fff1f2; color: #be123c; text-decoration: none; }
.badge-cancelled{ background: #fff1f2; color: #e11d48; }
.badge-overdue  { background: #fff7ed; color: #ea580c; }

/* Requisition statuses. Approved reads like Paid (the request is settled),
   Declined like Cancelled, and Invoiced gets its own indigo so a requisition
   that already became an invoice is obvious at a glance. */
.badge-approved { background: #f0fdf4; color: #16a34a; }
.badge-declined { background: #fff1f2; color: #e11d48; }
.badge-converted{ background: #eef2ff; color: #4338ca; }


/* ── Forms ──────────────────────────────────────────────── */

.field-group {
    display: flex;
    flex-direction: column;
    gap: .375rem;
    min-width: 0;
}
.field-group input,
.field-group select,
.field-group textarea { max-width: 100%; min-width: 0; }
input[type="file"] { max-width: 100%; }

label {
    font-size: .8125rem;
    font-weight: 500;
    color: var(--clr-text);
}

input[type="text"],
input[type="email"],
input[type="number"],
input[type="date"],
input[type="url"],
input[type="password"],
select,
textarea {
    width: 100%;
    padding: .5625rem .75rem;
    border: 1px solid var(--clr-border);
    border-radius: var(--r-sm);
    background: #fff;
    color: var(--clr-text);
    font-size: .875rem;
    transition: border-color var(--t), box-shadow var(--t);
    -webkit-appearance: none;
    appearance: none;
}

input:focus,
select:focus,
textarea:focus {
    outline: none;
    border-color: var(--clr-green);
    box-shadow: 0 0 0 3px rgba(74,222,128,.15);
}

textarea { resize: vertical; min-height: 80px; }

select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%2364748b' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right .75rem center;
    padding-right: 2rem;
}

.field-hint {
    font-size: .75rem;
    color: var(--clr-muted);
}

.field-error {
    font-size: .75rem;
    color: var(--clr-danger);
}

.form-row {
    display: grid;
    /* min(200px, 100%) so a track never asks for more than the container has,
       and minmax(0, ...) so a text input's intrinsic ~20ch width cannot prop a
       track open past the card edge on a phone. */
    grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
    gap: 1rem;
}
.form-row > * { min-width: 0; }

.form-section {
    margin-bottom: 1.5rem;
}

.form-section-title {
    font-family: var(--font-head);
    font-size: .8125rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--clr-muted);
    margin-bottom: .875rem;
    padding-bottom: .5rem;
    border-bottom: 1px solid var(--clr-border);
}

.form-actions {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
    padding-top: 1rem;
    border-top: 1px solid var(--clr-border);
    margin-top: 1.5rem;
}


/* ── Buttons ────────────────────────────────────────────── */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .375rem;
    padding: .5625rem 1.125rem;
    border-radius: var(--r-sm);
    font-size: .875rem;
    font-weight: 600;
    cursor: pointer;
    border: 1px solid transparent;
    transition: background var(--t), color var(--t), border-color var(--t), opacity var(--t);
    white-space: nowrap;
    text-decoration: none;
}

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

.btn-primary {
    background: var(--clr-green);
    color: var(--clr-navy);
    border-color: var(--clr-green);
}
.btn-primary:hover { background: var(--clr-green2); border-color: var(--clr-green2); }

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

.btn-danger {
    background: var(--clr-danger);
    color: #fff;
    border-color: var(--clr-danger);
}
.btn-danger:hover { background: #dc2626; }

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

.btn-sm {
    padding: .3125rem .75rem;
    font-size: .8125rem;
}

.btn-full { width: 100%; }

.btn svg { width: 16px; height: 16px; }


/* ── Alerts ─────────────────────────────────────────────── */

.alert {
    padding: .75rem 1rem;
    border-radius: var(--r-sm);
    font-size: .875rem;
    margin-bottom: 1rem;
    border: 1px solid transparent;
}

.alert-error   { background: #fff1f2; color: #be123c; border-color: #fecdd3; }
.alert-success { background: #f0fdf4; color: #15803d; border-color: #bbf7d0; }
.alert-warning { background: #fffbeb; color: #b45309; border-color: #fde68a; }
.alert-info    { background: #eff6ff; color: #1d4ed8; border-color: #bfdbfe; }


/* ── Two-column page layouts ────────────────────────────── */

/* Builder (form + sidebar) and detail (document + actions) pages. These were
   inline grid styles on six pages with no mobile rule, so a phone got the
   desktop 1fr + 340px grid squeezed into 390px and the page panned sideways. */
.split-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: 1.25rem;
    align-items: start;
}
.split-layout--narrow { grid-template-columns: minmax(0, 1fr) 300px; }
.split-layout > * { min-width: 0; }

/* Bill-to / details pair inside the document card. */
.two-col {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 1.5rem;
}

@media (max-width: 900px) {
    .split-layout,
    .split-layout--narrow { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 480px) {
    .two-col { grid-template-columns: minmax(0, 1fr); gap: 1rem; }
}

/* ── Line Items Table (Invoice Builder) ─────────────────── */

.items-table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: .75rem;
}

.items-table th {
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--clr-muted);
    padding: .5rem .625rem;
    text-align: left;
    border-bottom: 2px solid var(--clr-border);
    background: none;
}

.items-table th.td-right { text-align: right; }

.items-table td {
    padding: .5rem .625rem;
    vertical-align: top;
    border-bottom: 1px solid var(--clr-border);
}

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

.items-table input[type="text"],
.items-table input[type="number"],
.items-table textarea {
    padding: .4rem .5rem;
    font-size: .8125rem;
}

/* The Friends & Family type picker sits in an inline-flex group; the global
   select { width: 100% } collapsed it to a sliver there. */
.items-table .item-discount-type { width: auto; }

.items-table .item-desc-row td {
    padding-top: 0;
    border-bottom: none;
}

.item-subtotal {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    text-align: right;
    white-space: nowrap;
    padding-top: .625rem;
}

.add-item-btn {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    font-size: .8125rem;
    color: var(--clr-green2);
    font-weight: 600;
    cursor: pointer;
    background: none;
    border: none;
    padding: .25rem 0;
}

.add-item-btn:hover { color: var(--clr-green); }

.totals-block {
    margin-top: 1rem;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: .375rem;
}

.totals-row {
    display: flex;
    align-items: center;
    gap: 2rem;
    font-size: .875rem;
}

.totals-row .t-label { color: var(--clr-muted); min-width: 100px; text-align: right; }
.totals-row .t-val   { min-width: 90px; text-align: right; font-variant-numeric: tabular-nums; }
.totals-row.t-total  { font-weight: 700; font-size: 1rem; border-top: 2px solid var(--clr-border); padding-top: .5rem; margin-top: .25rem; }


/* ── Recurring Badge ────────────────────────────────────── */

.badge-recurring {
    background: #fdf4ff;
    color: #7e22ce;
}


/* ── Empty State ────────────────────────────────────────── */

.empty-state {
    text-align: center;
    padding: 3rem 1.5rem;
    color: var(--clr-muted);
}

.empty-state svg {
    width: 48px; height: 48px;
    margin: 0 auto 1rem;
    opacity: .3;
}

.empty-state p { margin-bottom: 1rem; }


/* ── Confirm Dialog ─────────────────────────────────────── */

.overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(15,23,42,.55);
    z-index: 200;
    align-items: center;
    justify-content: center;
    padding: 1rem;
}

.overlay.open { display: flex; }

.dialog {
    background: var(--clr-card);
    border-radius: var(--r);
    padding: 1.75rem;
    max-width: 400px;
    width: 100%;
    box-shadow: var(--shadow-md);
}

.dialog h2 {
    font-family: var(--font-head);
    font-size: 1.125rem;
    margin-bottom: .5rem;
}

.dialog p {
    font-size: .875rem;
    color: var(--clr-muted);
    margin-bottom: 1.25rem;
}

.dialog-actions { display: flex; gap: .75rem; justify-content: flex-end; }


/* ── Progress / Sending Overlay ─────────────────────────── */

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

.progress-dialog {
    text-align: center;
    padding: 2.25rem 2rem;
}

.progress-dialog .pd-logo {
    height: 36px;
    margin: 0 auto 1.25rem;
    display: block;
}

.progress-spinner {
    width: 40px;
    height: 40px;
    border: 3px solid var(--clr-border);
    border-top-color: var(--clr-green2);
    border-radius: 50%;
    animation: ces-spin .7s linear infinite;
    margin: 0 auto 1rem;
}

.progress-dialog .pd-title {
    font-family: var(--font-head);
    font-size: 1rem;
    font-weight: 600;
    color: var(--clr-text);
    margin-bottom: .3rem;
}

.progress-dialog .pd-msg {
    font-size: .8125rem;
    color: var(--clr-muted);
}


/* ── Mobile / Responsive ────────────────────────────────── */

@media (max-width: 768px) {
    .sidebar {
        transform: translateX(-100%);
        box-shadow: var(--shadow-md);
    }

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

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

    .hamburger { display: flex; }

    .page-body { padding: 1rem; }

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

    .form-row { grid-template-columns: minmax(0, 1fr); }

    /* Stacked-card tables (class table-stack, labels set by admin.js). An
       eight-column trips or expenses table read poorly as a sideways scroll
       on a phone; as cards each row reads top to bottom with the column name
       beside each value. */
    .table-wrap:has(> .table-stack) { overflow: visible; background: none; box-shadow: none; }
    .table-scroll-md > .table-stack,
    .table-scroll-lg > .table-stack { min-width: 0; }
    .table-stack thead { display: none; }
    .table-stack,
    .table-stack tbody,
    .table-stack tfoot,
    .table-stack tr,
    .table-stack td { display: block; width: 100%; }
    .table-stack tbody tr {
        background: var(--clr-card);
        border: 1px solid var(--clr-border);
        border-radius: var(--r);
        padding: .5rem .875rem;
        margin-bottom: .6rem;
    }
    /* Label in a fixed column on the left, value content flowing beside it,
       so a cell that holds a name plus a muted sub-line keeps that stacking. */
    .table-stack td {
        position: relative;
        padding: .3rem 0 .3rem 7rem !important;
        border-bottom: none !important;
        text-align: left !important;
        white-space: normal !important;
        overflow-wrap: anywhere;
        min-height: 1.6rem;
    }
    .table-stack td[data-label]::before {
        content: attr(data-label);
        position: absolute;
        left: 0;
        top: .45rem;
        width: 6.5rem;
        font-size: .65rem;
        font-weight: 600;
        letter-spacing: .06em;
        text-transform: uppercase;
        color: var(--clr-muted);
        line-height: 1.2;
    }
    .table-stack td:not([data-label]) { padding-left: 0 !important; }
    .table-stack td.td-actions {
        padding: .6rem 0 .2rem !important;
        display: flex;
        flex-wrap: wrap;
        gap: .4rem;
        align-items: center;
    }
    .table-stack td.td-actions::before { position: static; width: 100%; flex-basis: 100%; }
    .table-stack tfoot tr { padding: .25rem .875rem; }
    .table-stack tfoot td { justify-content: flex-start; gap: .5rem; }
    /* A card that holds nothing but a stacked table (Tools Hub client
       workspace) drops its own frame, or each row card sits inside a second
       border. */
    .card-stack-only { background: none; border: none; box-shadow: none; }
    /* Inside a stacked card the value column is narrow on a small phone, so
       an inline form (date plus Save) and long badges wrap rather than poke
       out of the card. */
    .table-stack td form { flex-wrap: wrap; }
    .table-stack td input[type="date"] { max-width: 100%; }
    .table-stack .badge { white-space: normal; max-width: 100%; }

    /* A requisition chip carries number, total and status; let a long one
       wrap inside the card instead of running off a 375px screen. */
    .chip { white-space: normal; max-width: 100%; border-radius: 1rem; }

    /* Safety net for anything still wider than the phone: clip it at the
       content column instead of letting iOS pan the whole page sideways.
       overflow: clip does not create a scroll container, so the sticky
       topbar keeps working. Genuine fixes above; this only catches strays. */
    .main-content { overflow-x: clip; }
    .card { min-width: 0; }

    /* Line-item builder as stacked cards. The desktop six-column row with
       fixed-width inputs measured 667px on a 375px phone. (The old rule here
       hid nth-child(3), which is Qty, not Tax; nothing is hidden now.) */
    .items-table thead { display: none; }
    .items-table,
    .items-table tbody,
    .items-table tr,
    .items-table td { display: block; }
    .items-table tr[data-row] {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
        gap: .4rem .5rem;
        align-items: end;
        padding-top: .75rem;
    }
    .items-table tr[data-row] td { padding: 0; border-bottom: none; }
    .items-table tr[data-row] td:first-child { grid-column: 1 / -1; }
    .items-table tr[data-row] td:nth-child(2)::before,
    .items-table tr[data-row] td:nth-child(3)::before,
    .items-table tr[data-row] td:nth-child(4)::before {
        display: block;
        font-size: .65rem;
        text-transform: uppercase;
        letter-spacing: .06em;
        color: var(--clr-muted);
        margin-bottom: .2rem;
    }
    .items-table tr[data-row] td:nth-child(2)::before { content: 'Price'; }
    .items-table tr[data-row] td:nth-child(3)::before { content: 'Qty'; }
    .items-table tr[data-row] td:nth-child(4)::before { content: 'Tax %'; }
    .items-table tr[data-row] input { width: 100% !important; }
    .items-table tr[data-row] td.item-subtotal {
        grid-column: 1 / 4;
        text-align: left;
        font-weight: 600;
        padding-top: .25rem;
    }
    .items-table tr[data-row] td.item-subtotal::before {
        content: 'Subtotal ';
        font-weight: 400;
        color: var(--clr-muted);
    }
    .items-table tr[data-row] td:last-child { grid-column: 4; grid-row: 2; }
    .items-table tr[data-desc-row] td {
        padding: .25rem 0 0 !important;
        border-bottom: none;
        text-align: left !important;
    }
    .items-table tr[data-desc-row] td:last-child {
        padding-bottom: .75rem !important;
        border-bottom: 1px solid var(--clr-border);
    }
    .items-table tr[data-desc-row] td > div {
        display: flex !important;
        flex-wrap: wrap;
        white-space: normal !important;
    }

    .filter-sort { margin-left: 0; flex-wrap: wrap; }

    /* A long page title plus the topbar actions cannot fit on one 60px line on
       a phone, and a fixed height left the title spilling out of the bar. */
    .topbar {
        height: auto;
        min-height: 60px;
        padding: .55rem 1rem;
        flex-wrap: wrap;
        gap: .5rem .75rem;
    }
    .topbar-title { font-size: .9375rem; min-width: 0; }
}

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

    /* Read-only line items on the invoice and requisition pages: the Tax
       column is never totaled, so drop it on a phone to give the Item and
       Subtotal columns the room instead. */
    .doc-items th:nth-child(4),
    .doc-items td:nth-child(4) { display: none; }
    /* The four columns left still ran a few px past a 390px phone on the
       inline .75rem cell padding; half a rem each side keeps them on screen. */
    .doc-items th,
    .doc-items td:not([colspan]) { padding-left: .5rem !important; padding-right: .5rem !important; }
    /* Recipient checkboxes: a long address drops under the name on a small
       phone instead of pushing past the edge. */
    .recipient-option { flex-wrap: wrap; }
    .login-card { padding: 1.75rem 1.25rem; }
}

/* A page that wants its whole tile row on one line asks for it here rather
   than hard-coding repeat(N,1fr) inline. A fixed fraction count cannot shrink,
   so inline versions of this pushed the entire page sideways on a phone and
   beat the mobile rules above on specificity. Scoped to desktop widths so the
   1fr/2fr fallbacks stay in charge on a narrow screen. */
@media (min-width: 769px) {
    .stats-row.stats-tight { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
}

/* ── Fleet health (fed by status.compedgesolutions.us) ─── */
/* Tones: ok green, warn amber (degraded), stale orange (runner silent),
   bad red (monitors down), muted grey (feed unreachable). */

.health { --health: var(--clr-faint); --health-ring: #f1f5f9; }
.health.ok    { --health: #16a34a; --health-ring: #dcfce7; }
.health.warn  { --health: #d97706; --health-ring: #fef3c7; }
.health.stale { --health: #ea580c; --health-ring: #ffedd5; }
.health.bad   { --health: #dc2626; --health-ring: #fee2e2; }

.health-dot {
    display: inline-block;
    width: .7rem;
    height: .7rem;
    border-radius: 50%;
    background: var(--health);
    box-shadow: 0 0 0 3px var(--health-ring);
    flex: none;
    vertical-align: middle;
}

.stat-card.health {
    display: block;
    text-decoration: none;
    color: inherit;
    border-left: 4px solid var(--health);
    transition: box-shadow var(--t);
}
.stat-card.health:hover { box-shadow: var(--shadow-md); }
.stat-card.health .stat-value {
    font-size: 1.25rem;
    color: var(--health);
    display: flex;
    align-items: center;
    gap: .5rem;
}
.stat-card.health .stat-sub { font-size: .72rem; color: var(--clr-muted); margin-top: .4rem; }

.health-card { border-left: 4px solid var(--health); }
.health-status {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-family: var(--font-head);
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--health);
    line-height: 1.2;
}
.health-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 1rem;
    font-size: .9rem;
}
.health-disk { display: flex; align-items: center; gap: .5rem; font-size: .85rem; margin-top: .3rem; }
.health-disk-host { min-width: 0; flex: 0 1 12rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.health-disk-pct { flex: none; min-width: 2.5rem; text-align: right; }
.health-bar { flex: 1 1 4rem; min-width: 3rem; height: 6px; background: #f1f5f9; border-radius: 3px; overflow: hidden; }
.health-bar span { display: block; height: 100%; background: #16a34a; }
.health-bar.amber span { background: #d97706; }
.health-bar.red   span { background: #dc2626; }
.health-incidents { list-style: none; padding: 0; margin: .4rem 0 0; font-size: .875rem; }
.health-incidents li { padding: .35rem 0; border-top: 1px solid var(--clr-border); }

/* In the Tools Hub grid the card takes two columns while the grid has two to
   give. The grid is auto-fit at 240px, so below two columns' worth of width
   (2 x 240 + 1rem gap) it drops back to one. */
.stats-row { container-type: inline-size; }
.health-card { grid-column: span 2; }
@container (max-width: 495px) {
    .health-card { grid-column: auto; }
}

/* ── Bills: CES project tags ───────────────────────────────────────────────
   A bill can serve several projects at once (a shared image-generation credit
   sits on three), so the picker is a checkbox field and the tables show chips
   rather than a single value. */
.project-picker {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem .9rem;
    padding: .6rem .75rem;
    border: 1px solid var(--clr-border);
    border-radius: 6px;
    background: #f8fafc;
}
.project-picker { max-height: 15rem; overflow-y: auto; }
.project-filter {
    width: 100%;
    margin-bottom: .4rem;
    padding: .5625rem .75rem;
    border: 1px solid var(--clr-border);
    border-radius: var(--r-sm);
    background: #fff;
    color: var(--clr-text);
    font-size: .875rem;
}
.project-picker-count { font-weight: 400; color: var(--clr-muted); font-size: .8rem; }
.project-check {
    display: flex;
    align-items: center;
    gap: .4rem;
    font-size: .85rem;
    font-weight: 500;
    cursor: pointer;
    white-space: nowrap;
}
.project-check input { width: auto; margin: 0; }
.project-check.is-archived { color: var(--clr-muted); font-weight: 400; }
.project-chips { display: flex; flex-wrap: wrap; gap: .25rem; }
.project-chip {
    display: inline-block;
    padding: .1rem .45rem;
    border-radius: 999px;
    border: 1px solid #c7d2fe;
    background: #eef2ff;
    color: #3730a3;
    font-size: .7rem;
    font-weight: 600;
    line-height: 1.5;
    text-decoration: none;
    white-space: nowrap;
}
a.project-chip:hover { background: #e0e7ff; }
.project-chip.is-suite {
    border-color: var(--clr-border);
    background: #f1f5f9;
    color: var(--clr-muted);
    font-weight: 500;
}
/* A long tag list collapses into one chip that opens on click. */
.project-chips-more > summary { list-style: none; cursor: pointer; }
.project-chips-more > summary::-webkit-details-marker { display: none; }
.project-chip.is-count { font-weight: 600; }
.project-chip.is-count::after { content: ' \25BE'; font-size: .7em; }
.project-chips-more[open] > summary.is-count::after { content: ' \25B4'; }
.project-chips-more > .project-chips { margin-top: .3rem; }

/* Picker toolbar: filter box plus Select all / Clear all. */
.project-picker-tools { display: flex; gap: .4rem; align-items: center; margin-bottom: .4rem; }
.project-picker-tools .project-filter { flex: 1; margin-bottom: 0; min-width: 0; }
.project-picker-tools .btn { white-space: nowrap; }

/* ── Pass-through (client ad money) on invoice lines ────────────────────── */
.item-pt {
    display: flex;
    align-items: center;
    gap: .35rem;
    margin-top: .3rem;
    font-size: .75rem;
    font-weight: 500;
    color: var(--clr-muted);
    cursor: pointer;
}
.item-pt input { width: auto; margin: 0; }
.pt-badge {
    display: inline-block;
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .03em;
    padding: .05rem .4rem;
    border-radius: 4px;
    background: #fef3c7;
    color: #92400e;
}
.pt-badge.pt-deposited { background: #dcfce7; color: #166534; }
.pt-badge.pt-fronted   { background: #e0e7ff; color: #3730a3; }

/* Link out to a vendor's own account page. Underlined rather than coloured on
   its own, so it reads as a link inside a muted line without shouting. */
.account-link {
    color: var(--clr-info);
    text-decoration: none;
    border-bottom: 1px solid rgba(59,130,246,.35);
    white-space: nowrap;
}
.account-link:hover { border-bottom-color: var(--clr-info); }

/* ── Receipt chips on a trip expense row ────────────────── */

.receipt-chip {
    display: inline-flex;
    align-items: center;
    gap: .15rem;
    margin-right: .25rem;
    vertical-align: middle;
}
.receipt-chip img {
    width: 34px;
    height: 34px;
    object-fit: cover;
    border-radius: var(--r-sm);
    border: 1px solid var(--clr-border);
    display: block;
}
.receipt-chip .receipt-file {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: var(--r-sm);
    border: 1px solid var(--clr-border);
    background: var(--clr-bg);
    font-size: .6rem;
    font-weight: 700;
    color: var(--clr-muted);
}
.receipt-remove {
    border: 0;
    background: none;
    color: var(--clr-faint);
    cursor: pointer;
    font-size: .9rem;
    line-height: 1;
    padding: 0 .1rem;
}
.receipt-remove:hover { color: var(--clr-danger); }

/* The file input itself is hidden inside its label, so the whole chip is the
   target: one tap on a phone goes straight to the camera. */
.receipt-add {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 34px;
    height: 34px;
    padding: 0 .5rem;
    border: 1px dashed var(--clr-border);
    border-radius: var(--r-sm);
    background: #fff;
    color: var(--clr-muted);
    font-size: .75rem;
    font-weight: 600;
    cursor: pointer;
    vertical-align: middle;
    white-space: nowrap;
}
.receipt-add:hover { border-color: var(--clr-green2); color: var(--clr-green2); }
.receipt-add input[type="file"] { display: none; }

/* Inline actual-amount entry on the usage bills table. */
.usage-actual-form {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: .35rem;
}
.usage-actual-form input { margin: 0; }

/* ── Receipt import review (trip page) ──────────────────── */

[data-import-table] td input,
[data-import-table] td select { font-size: .85rem; padding: .35rem .5rem; }
[data-import-table] tr.import-dup td { background: #fffbeb; }
[data-import-table] tr.import-err td { background: #fef2f2; }
.import-file {
    font-size: .72rem;
    color: var(--clr-muted);
    margin-top: .3rem;
    max-width: 14rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.import-note {
    font-size: .75rem;
    color: var(--clr-muted);
    margin-top: .3rem;
    max-width: 18rem;
    line-height: 1.35;
}
.import-note-warn  { color: #b45309; }
.import-note-error { color: var(--clr-danger); }
.import-note a { color: inherit; text-decoration: underline; }

/* A tip split off a fare sits under it, marked as such. */
.expense-tip-of {
    font-size: .72rem;
    color: var(--clr-muted);
    font-weight: 400;
}
[data-import-table] select[name="category"]          { min-width: 10rem; }
[data-import-table] select[name="funding_source_id"] { min-width: 11rem; }
[data-import-table] select[name="tip_mode"]          { min-width: 13rem; }
[data-import-table] td label { white-space: nowrap; }
@media (max-width: 768px) {
    /* As a stacked card every field takes the row; the desktop min-widths
       would push the longer ones out past the card edge. */
    [data-import-table] td input,
    [data-import-table] td select { min-width: 0 !important; width: 100% !important; max-width: 100%; }
    [data-import-table] td[data-label] { flex-wrap: wrap; }
    .import-note, .import-file { max-width: none; }
}

/* ── Form modals (trip page: add, import, edit) ─────────── */

.overlay-modal { align-items: flex-start; overflow-y: auto; padding: 2rem 1rem; }
.overlay-modal .dialog { margin: auto; max-height: none; }
.dialog-wide  { max-width: 860px; }
.dialog-xwide { max-width: 1320px; }
body.modal-open { overflow: hidden; }

.modal-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.25rem;
    padding-bottom: .9rem;
    border-bottom: 1px solid var(--clr-border);
}
.modal-head h2 { margin-bottom: .25rem; }
.modal-head p  { margin-bottom: 0; }
.modal-sub strong { color: var(--clr-text); font-size: 1rem; }
.modal-close {
    border: 0;
    background: none;
    font-size: 1.6rem;
    line-height: 1;
    color: var(--clr-muted);
    cursor: pointer;
    padding: 0 .25rem;
    flex: 0 0 auto;
}
.modal-close:hover { color: var(--clr-text); }

/* The receipt sits at the top of the edit form, so what is being edited is in view. */
.edit-receipt {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}
.edit-receipt-label { font-size: .75rem; color: var(--clr-muted); font-weight: 600; text-transform: uppercase; letter-spacing: .05em; }
.edit-receipt .receipt-chip img,
.edit-receipt .receipt-chip .receipt-file { width: 56px; height: 56px; }

/* The row behind an open edit modal, so closing it lands you back where you were. */
tr.is-editing td { background: #f0fdf4 !important; }

@media (max-width: 768px) {
    .overlay-modal { padding: .5rem; }
    .overlay-modal .dialog { padding: 1.1rem; }
    .dialog-wide, .dialog-xwide { max-width: none; }
}

/* The hidden attribute wins over any display rule, as it should. */
[hidden] { display: none !important; }

/* ── Paste / drop zone in the expense modals ────────────── */

.paste-zone {
    border: 2px dashed var(--clr-border);
    border-radius: var(--r);
    padding: .75rem;
    margin-bottom: 1rem;
    background: var(--clr-bg);
    transition: border-color .15s, background .15s;
}
.paste-zone.is-over { border-color: var(--clr-green2); background: #f0fdf4; }
.paste-zone textarea {
    width: 100%;
    resize: vertical;
    font-size: .85rem;
    background: var(--clr-card);
}
.paste-zone .field-hint { display: block; margin-top: .35rem; }

/* Bills pull schedule: Confirm / undo sits under the status badge. */
.pull-confirm-form { margin-top: .3rem; }
.btn-link-muted {
    background: none;
    border: 0;
    padding: 0;
    font-size: .72rem;
    color: var(--clr-muted);
    text-decoration: underline;
    cursor: pointer;
}

/* Bills pull schedule: step to the month before or after. */
.period-nav { display: flex; gap: .75rem; font-size: .85rem; white-space: nowrap; }
.period-nav a { color: var(--clr-muted); text-decoration: none; }
.period-nav a:hover { color: var(--clr-text); text-decoration: underline; }

/* Bill form: where the bill's pulls have come from, and what a change does. */
.account-history {
    margin: 0 0 1rem;
    padding: .65rem .85rem;
    border: 1px solid var(--clr-border);
    border-radius: 6px;
    background: var(--clr-bg);
    font-size: .85rem;
}
.account-history-title { font-weight: 600; margin-bottom: .25rem; }
.account-history ul { list-style: none; margin: 0 0 .35rem; padding: 0; }
.account-history li { display: flex; flex-wrap: wrap; gap: .25rem .6rem; align-items: baseline; padding: .15rem 0; }
.account-history-when { color: var(--clr-muted); font-size: .8rem; }
.account-change-hint {
    margin-top: .45rem;
    padding: .5rem .65rem;
    border: 1px solid #bfdbfe;
    border-radius: 6px;
    background: #eff6ff;
    color: #1d4ed8;
    font-size: .8rem;
    line-height: 1.4;
}
.account-change-hint[hidden], .account-change-hint [hidden] { display: none; }
.account-change-now { display: flex; gap: .4rem; align-items: flex-start; margin-top: .4rem; font-weight: 500; cursor: pointer; }
