:root {
    --color-bg: #0f172a;
    --color-surface: #ffffff;
    --color-surface-muted: #f1f5f9;
    --color-page-bg: #f1f5f9;
    --color-text: #1e293b;
    --color-muted: #64748b;
    --color-accent: #0ea5e9;
    --color-accent-dark: #0284c7;
    --color-error-bg: #fef2f2;
    --color-error-text: #b91c1c;
    --color-border: #e2e8f0;
    --color-border-strong: #94a3b8;
    --radius: 10px;
    --topbar-height: 60px;
    --sidebar-width: 240px;
}

/* --- Dark theme ---
 *
 * Toggled by adding data-theme="dark" to <html> (see theme.js and the
 * anti-flash inline script in header.php's <head>, which sets this
 * attribute before first paint so there's no flash of the light theme on
 * load). Persisted in localStorage, so it's remembered per-device across
 * sessions, same pattern as the sidebar-collapsed state in shell.js.
 *
 * --color-bg (the topbar/sidebar's own background) is deliberately left
 * unchanged here — it's already a dark navy in the light theme, so the
 * shell's top/side chrome looks the same in both themes; only the page
 * body and cards actually flip. This is why colors chosen specifically to
 * read against --color-bg (the topbar clock-status colors, sidebar link
 * colors, etc. — see their own comments elsewhere in this file) don't need
 * a dark-theme override: their background never changes.
 *
 * A handful of colors elsewhere in this file are literal hex values
 * rather than variables — chosen deliberately where they're printed on a
 * solid, non-theme-dependent fill (white text on an accent/green/red
 * button reads fine regardless of theme) and given explicit dark-theme
 * overrides below where they're printed directly on a card/page
 * background instead (the GL Accounts delete-X red, the Employee
 * Verification active/inactive status text).
 */
html[data-theme="dark"] {
    --color-surface: #1e293b;
    --color-surface-muted: #334155;
    --color-page-bg: #0b1220;
    --color-text: #e2e8f0;
    --color-muted: #94a3b8;
    --color-accent: #38bdf8;
    --color-accent-dark: #0ea5e9;
    --color-error-bg: rgba(185, 28, 28, 0.25);
    --color-error-text: #fca5a5;
    --color-border: #334155;
    --color-border-strong: #64748b;
}

html[data-theme="dark"] .icon-btn-delete {
    color: #f87171;
}

html[data-theme="dark"] .icon-btn-delete:hover,
html[data-theme="dark"] .icon-btn-delete:focus-visible {
    color: #fca5a5;
}

html[data-theme="dark"] .empverify-status-active {
    color: #4ade80;
}

html[data-theme="dark"] .empverify-status-inactive {
    color: #f87171;
}

* {
    box-sizing: border-box;
}

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

/* --- Login page --- */

body.auth-page {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(160deg, var(--color-bg) 0%, #1e293b 100%);
    padding: 1.5rem;
}

.auth-card {
    background: var(--color-surface);
    border-radius: var(--radius);
    padding: 2.5rem 2rem;
    width: 100%;
    max-width: 360px;
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.25);
}

/* Stacked cards on the shell (not the standalone login page) get breathing
   room between them — e.g. Roles' role list above its page-tree editor, or
   Permissions' search above its selected-user editor. */
body.shell .auth-card + .auth-card {
    margin-top: 1.5rem;
}

/* Desktop-first: most heavy-duty work happens on office desktops, and a
   360px-wide card on a wide monitor reads as anemic. On screens wide enough
   that the sidebar stays permanently open (same breakpoint as the sidebar
   itself, see the media query near the bottom of this file), shell cards
   grow to about half the content area instead of staying pinned narrow.
   The standalone login page is untouched — body.auth-page, not body.shell. */
@media (min-width: 861px) {
    body.shell .auth-card {
        max-width: 50%;
    }
}

.auth-title {
    margin: 0 0 0.25rem;
    font-size: 1.5rem;
    font-weight: 700;
}

.auth-subtitle {
    margin: 0 0 1.5rem;
    color: var(--color-muted);
    font-size: 0.9rem;
}

.auth-error {
    background: var(--color-error-bg);
    color: var(--color-error-text);
    padding: 0.65rem 0.85rem;
    border-radius: 8px;
    font-size: 0.85rem;
    margin: 0 0 1.25rem;
}

.auth-notice {
    background: #fffbeb;
    color: #92400e;
    padding: 0.65rem 0.85rem;
    border-radius: 8px;
    font-size: 0.85rem;
}

form label {
    display: block;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--color-muted);
    margin: 1rem 0 0.35rem;
}

form input[type="text"],
form input[type="password"],
form input[type="email"],
form textarea,
form select {
    width: 100%;
    padding: 0.65rem 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    font-size: 1rem;
    font-family: inherit;
    background: var(--color-surface);
    /* Without this, every one of these fields falls back to the browser's
       own default text color (effectively black) instead of following the
       theme — invisible-looking against dark mode's dark --color-surface,
       since nothing here was ever setting it explicitly. custom-select's
       own native select already sets this correctly (see
       .custom-select-native above); this is the same fix for every plain
       text input, password, email, textarea, and un-enhanced select in the
       app — Job Maintenance, Customer Maintenance, GL Accounts, login,
       admin pages, all of it, not just one page's fields. */
    color: var(--color-text);
}

form textarea {
    resize: vertical;
    min-height: 4.5rem;
}

form input:focus,
form textarea:focus,
form select:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.15);
}

/* Generic "this field isn't wired up yet" treatment — muted fill, muted
   text, not-allowed cursor — rather than a page-specific class. First real
   use is Customer Maintenance's Short Notes/Department/Sales Rep fields
   (section 50), each blocked on something this build can't safely guess
   at, but any future "coming soon" field anywhere else in the app gets
   this for free by just adding the disabled attribute. */
form input:disabled,
form select:disabled,
form textarea:disabled {
    background: var(--color-surface-muted);
    color: var(--color-muted);
    cursor: not-allowed;
}

.form-check {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 1.25rem;
}

.form-check input[type="checkbox"] {
    width: 1rem;
    height: 1rem;
}

.form-check label {
    margin: 0;
    font-size: 0.9rem;
    font-weight: 400;
    color: var(--color-text);
}

/* Groups 2-3 short related fields onto one line (city/state/zip,
   phone/fax) instead of each taking a full-width row on its own — first
   used by admin/company.php's address block. Each item keeps its own
   label directly above its input, so this is purely a layout change, not
   a different label/input pattern from the rest of the form. */
.form-row {
    display: flex;
    gap: 1rem;
}

.form-row .form-row-item {
    flex: 1;
    min-width: 0;
}

.form-row .form-row-item-narrow {
    flex: 0 0 5.5rem;
}

.password-field {
    position: relative;
    display: flex;
}

.password-field input {
    flex: 1;
}

.toggle-password {
    margin-left: 0.5rem;
    padding: 0 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-surface-muted);
    color: var(--color-muted);
    font-size: 0.8rem;
    cursor: pointer;
}

form button[type="submit"] {
    width: 100%;
    margin-top: 1.5rem;
    padding: 0.7rem;
    border: none;
    border-radius: 8px;
    background: var(--color-accent);
    color: #fff;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s ease;
}

form button[type="submit"]:hover {
    background: var(--color-accent-dark);
}

form button[type="submit"]:disabled {
    opacity: 0.7;
    cursor: default;
}

/* Additive sign-in option on login.php — sits below the existing password
   form, inside the same <form> (a second submit button with its own
   formaction, not a separate form), so it shares the company dropdown and
   csrf_token without duplicating either. Only rendered at all when
   GoogleAuthService::isConfigured() is true — see login.php. */
.auth-divider {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin: 1.25rem 0;
    color: var(--color-muted);
    font-size: 0.8rem;
}

.auth-divider::before,
.auth-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--color-border);
}

.google-signin-btn {
    width: 100%;
    margin-top: 0;
    padding: 0.65rem;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-surface);
    color: var(--color-text);
    font-size: 0.95rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
}

.google-signin-btn:hover {
    background: var(--color-surface-muted);
}

/* --- Placeholder shell (post-login) --- */

.shell-placeholder {
    max-width: 640px;
    margin: 3rem auto;
    padding: 0 1.5rem;
}

.placeholder-note {
    color: var(--color-muted);
    font-size: 0.9rem;
    line-height: 1.5;
}

.logout-link {
    display: inline-block;
    margin-top: 1.5rem;
    color: var(--color-accent-dark);
    font-weight: 600;
    text-decoration: none;
}

.logout-link:hover {
    text-decoration: underline;
}

/* --- Dashboard (index.php) --- */

.dashboard-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 1.25rem;
    margin-top: 1.5rem;
}

/* --color-border-strong instead of --color-border: the default border is
   deliberately subtle (barely-there hairline), which disappears entirely
   on washed-out or low-contrast screens. Cards specifically need to read
   as distinct, clickable regions at a glance, so they get the more visible
   border variant plus a slightly stronger shadow — everything else that
   uses --color-border for a quieter division (table rows, input fields)
   keeps the subtler default. */
.dashboard-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    padding: 1.5rem;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12);
}

.dashboard-card-title {
    margin: 0 0 0.75rem;
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--color-text);
}

.dashboard-card-body {
    margin: 0 0 0.75rem;
    font-size: 0.9rem;
    color: var(--color-text);
}

.dashboard-card-link {
    display: inline-block;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-accent-dark);
    text-decoration: none;
}

.dashboard-card-link:hover {
    text-decoration: underline;
}

.dashboard-card-disabled {
    background: var(--color-page-bg);
    box-shadow: none;
}

.dashboard-card-disabled .dashboard-card-title {
    color: var(--color-muted);
}

.dashboard-link-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.dashboard-link-list li + li {
    margin-top: 0.5rem;
}

.dashboard-link-list a {
    font-size: 0.9rem;
    color: var(--color-accent-dark);
    text-decoration: none;
}

.dashboard-link-list a:hover {
    text-decoration: underline;
}

/* Used on the Roles page to mark which role in the list is currently being
   edited below — semantic aria-current rather than a one-off class. */
.dashboard-link-list a[aria-current="page"] {
    font-weight: 700;
    color: var(--color-text);
}

.todo-list {
    list-style: none;
    margin: 0 0 0.5rem;
    padding: 0;
}

.todo-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--color-border);
}

.todo-item form {
    display: contents;
}

.todo-text {
    flex: 1;
    font-size: 0.95rem;
    color: var(--color-text);
}

.todo-check {
    flex: none;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    border: 1.5px solid var(--color-border);
    background: var(--color-surface);
    color: transparent;
    font-size: 0.8rem;
    line-height: 1;
    cursor: pointer;
    transition: all 0.15s ease;
}

.todo-check:hover {
    border-color: #16a34a;
    color: #16a34a;
}

.todo-delete {
    flex: none;
    width: 1.5rem;
    height: 1.5rem;
    border: none;
    background: none;
    color: var(--color-muted);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
}

.todo-delete:hover {
    color: var(--color-error-text);
}

.todo-add-form {
    display: flex;
    gap: 0.5rem;
    margin-top: 0.75rem;
}

.todo-add-form input[type="text"] {
    flex: 1;
    margin: 0;
}

.todo-add-form button[type="submit"] {
    width: auto;
    margin-top: 0;
    padding: 0.65rem 1rem;
}

/* --- Timeclock --- */

.timeclock-status {
    margin: 0 0 1.25rem;
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--color-text);
}

.timeclock-status-muted {
    font-weight: 400;
    color: var(--color-muted);
}

.timeclock-actions {
    display: flex;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
}

.timeclock-actions .btn-clock {
    flex: 1;
    width: auto;
    margin-top: 0;
    padding: 1rem;
    border: none;
    border-radius: 8px;
    font-size: 1.05rem;
    font-weight: 700;
    color: #fff;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    transition: background 0.15s ease, opacity 0.15s ease;
}

.timeclock-actions .btn-clock-in {
    background: #16a34a;
}

.timeclock-actions .btn-clock-in:hover:not(:disabled) {
    background: #15803d;
}

.timeclock-actions .btn-clock-out {
    background: #dc2626;
}

.timeclock-actions .btn-clock-out:hover:not(:disabled) {
    background: #b91c1c;
}

.timeclock-actions .btn-clock:disabled {
    background: #cbd5e1;
    color: #94a3b8;
    cursor: default;
}

/* Matches .custom-select-native's look (same border/radius/padding/focus
   ring) so the notes field reads as part of the same design language as
   the login page's company dropdown. Width matches .timeclock-actions
   above it since both are full-width within .auth-card. */
.timeclock-notes {
    display: block;
    width: 100%;
    padding: 0.65rem 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    font-size: 1rem;
    font-family: inherit;
    color: var(--color-text);
    background: var(--color-surface);
    resize: vertical;
}

.timeclock-notes:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.15);
}

/* --- Search-and-select (e.g. admin password reset, permissions) --- */

.search-results-list {
    list-style: none;
    margin: 0.75rem 0 0;
    padding: 0;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    overflow: hidden;
}

.search-results-list li + li {
    border-top: 1px solid var(--color-border);
}

/* Shared by <button> results (password reset, which needs a POST) and <a>
   results (permissions, which just navigates) — the text-decoration/color
   reset only matters for the <a> case, harmless on a button. */
.search-result-item {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    width: 100%;
    padding: 0.65rem 0.85rem;
    border: none;
    background: var(--color-surface);
    text-align: left;
    text-decoration: none;
    color: inherit;
    cursor: pointer;
    font: inherit;
}

.search-result-item:hover,
.search-result-item:focus-visible {
    background: #f1f5f9;
}

.search-result-item strong {
    font-size: 0.95rem;
}

.search-result-item span {
    font-size: 0.8rem;
    color: var(--color-muted);
}

/* --- Custom select (reusable dropdown component) --- */
/*
 * Markup: <div class="custom-select" data-custom-select>
 *             <select class="custom-select-native">...options...</select>
 *         </div>
 * Unenhanced, the native select above is fully styled on its own (custom
 * arrow, matching border/padding/focus ring) and works with zero JS.
 * custom-select.js progressively enhances it on page load into a themed
 * trigger + option list; the native select stays in the DOM as the real
 * form field, so posted values and server-side validation are unaffected.
 * Use this pattern for every dropdown going forward, not just this one.
 */

.custom-select {
    position: relative;
}

.custom-select-native {
    width: 100%;
    padding: 0.65rem 2.25rem 0.65rem 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    font-size: 1rem;
    font-family: inherit;
    color: var(--color-text);
    background-color: var(--color-surface);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%2364748b'%3E%3Cpath fill-rule='evenodd' d='M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z' clip-rule='evenodd'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.65rem center;
    background-size: 1rem;
    appearance: none;
    -webkit-appearance: none;
    cursor: pointer;
}

.custom-select-native:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.15);
}

/* Once JS enhances the control, the native select becomes an invisible
   overlay driving the real form value — the trigger/list below do the
   visible work, but keyboard users landing on the native select directly
   (e.g. via label click) still get full native behavior. */
.custom-select.is-enhanced .custom-select-native {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    pointer-events: none;
}

.custom-select-trigger {
    display: none;
    width: 100%;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.65rem 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-surface);
    color: var(--color-text);
    font-size: 1rem;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}

.custom-select.is-enhanced .custom-select-trigger {
    display: flex;
}

.custom-select-trigger:focus-visible,
.custom-select.open .custom-select-trigger {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.15);
}

.custom-select-arrow {
    flex: none;
    width: 10px;
    height: 10px;
    border-right: 2px solid var(--color-muted);
    border-bottom: 2px solid var(--color-muted);
    transform: rotate(45deg);
    margin-top: -4px;
    transition: transform 0.15s ease;
}

.custom-select.open .custom-select-arrow {
    transform: rotate(-135deg);
    margin-top: 2px;
}

.custom-select-list {
    display: none;
    position: absolute;
    left: 0;
    right: 0;
    top: calc(100% + 4px);
    margin: 0;
    padding: 0.35rem 0;
    list-style: none;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
    max-height: 260px;
    overflow-y: auto;
    z-index: 120;
}

.custom-select.open .custom-select-list {
    display: block;
}

.custom-select-option {
    padding: 0.55rem 0.85rem;
    font-size: 0.95rem;
    color: var(--color-text);
    cursor: pointer;
}

.custom-select-option:hover,
.custom-select-option.is-active {
    background: #f1f5f9;
}

.custom-select-option.is-selected {
    font-weight: 600;
    color: var(--color-accent-dark);
}

/* --- Permission treeview (admin Roles / Permissions pages) --- */
/*
 * Markup (App\Permissions\PermissionTreeView renders everything from
 * <li class="perm-page-item"> down, recursively):
 * <div class="perm-tree">
 *     <details class="perm-category" open>
 *         <summary class="perm-category-title">General Ledger</summary>
 *         <ul class="perm-page-list">
 *             <li class="perm-page-item">
 *                 <div class="perm-page-row">
 *                     <label><input type="checkbox" name="pages[]" value="3" checked> GL Accounts</label>
 *                 </div>
 *             </li>
 *             <li class="perm-page-item perm-page-item-parent">
 *                 <div class="perm-page-row">
 *                     <label><input type="checkbox" name="pages[]" value="9"> GL Reports</label>
 *                     <span class="perm-override-icon" title="Custom for this user">(icon)</span>
 *                 </div>
 *                 <ul class="perm-page-list perm-page-sublist">
 *                     <li class="perm-page-item">
 *                         <div class="perm-page-row">
 *                             <label><input type="checkbox" name="pages[]" value="10"> Chart of Accounts Report</label>
 *                         </div>
 *                     </li>
 *                 </ul>
 *             </li>
 *         </ul>
 *     </details>
 * </div>
 * Native HTML5 <details>/<summary> per category — expand/collapse works
 * with zero JavaScript. .perm-override-icon is optional, used on the
 * permissions (not roles) page to flag a page whose checked state differs
 * from what the assigned role alone would grant — a small icon rather than
 * a repeated text label, with a one-time .perm-legend above the tree
 * spelling out what it means (see permissions.php). Every <details> renders
 * with the open attribute already set in both roles.php and permissions.php
 * (hardcoded, not JS-driven), so the full tree is expanded on page load by
 * default — there's no collapsed state to click through.
 *
 * A page can itself have children (.perm-page-item-parent, e.g. a
 * category's Reports landing page with individual reports nested under
 * it — see PermissionService::categoryTree()'s hparent handling) — its own
 * checkbox then behaves exactly like a category checkbox does over its
 * pages: tri-state (checked / unchecked / indeterminate, reflecting
 * none/some/all of its own children — see permission-tree.js) and
 * cascades down when toggled. Nesting is currently only one level deep in
 * practice (a page's children are leaves), but permission-tree.js's
 * cascade logic itself has no depth limit.
 *
 * Visual indent steps further right at each level: the "Role" field/
 * heading above this component (permissions.php's Role dropdown, roles.php's
 * "Editing: {name}" heading) sits at the card's normal left edge;
 * .perm-tree's own margin-left indents every category one step in from
 * that; .perm-page-list's left padding indents every page a further step
 * in from its category; .perm-page-sublist adds one MORE step for a page's
 * own nested children, so "Chart of Accounts Report" reads as visibly
 * subordinate to "GL Reports" rather than a same-level sibling. Shared by
 * both pages since both use these same classes.
 */

.perm-tree {
    margin: 1rem 0 1.5rem;
    margin-left: 1.25rem;
}

.perm-category {
    border: 1px solid var(--color-border);
    border-radius: 8px;
    margin-bottom: 0.4rem;
    overflow: hidden;
}

.perm-category-title {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.85rem;
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--color-text);
    background: var(--color-surface-muted);
    cursor: pointer;
    list-style: none;
}

/* <summary> gets a native disclosure-triangle marker in every browser,
   independent of the display:flex above — Chrome/Firefox via list-style
   (suppressed by list-style: none on the rule above), older WebKit via its
   own pseudo-element (suppressed below). Without both, that marker eats
   extra width before the checkbox, so .perm-category-checkbox lands to the
   right of where .perm-page-item's checkbox lands one level down — the
   category row reads as "pushed right" / the page rows as "pushed left"
   relative to each other, even though both sides have the same intended
   padding. Suppressing the marker entirely (rather than resizing it) is
   the fix, since there's no design need to keep it — the whole category
   title is already a click target for expand/collapse. */
.perm-category-title::-webkit-details-marker {
    display: none;
}

.perm-category-title::marker {
    content: '';
}

.perm-category-checkbox {
    flex: none;
    width: 1rem;
    height: 1rem;
    cursor: pointer;
}

.perm-category-checkbox:disabled {
    cursor: default;
    opacity: 0.4;
}

.perm-page-list {
    list-style: none;
    margin: 0;
    padding: 0.25rem 0.85rem 0.4rem 2.1rem;
}

.perm-page-item {
    padding: 0.2rem 0;
}

/* The row content (checkbox/label + optional "Custom for this user" note)
   is its own flex row, separate from .perm-page-item itself, so a page
   with a nested .perm-page-sublist underneath can stack that list below
   the row instead of fighting it for space in the same flex line. */
.perm-page-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.perm-page-row label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
    font-size: 0.9rem;
    font-weight: 400;
    color: var(--color-text);
    cursor: pointer;
}

.perm-page-row input[type="checkbox"] {
    width: 1rem;
    height: 1rem;
}

/* Small person-in-circle icon replacing what used to be a literal "Custom
   for this user" text label repeated on every overridden row — same
   meaning, far less visual noise on a tree that can now run several rows
   deep. .perm-legend (permissions.php only — roles.php has no per-user
   override concept, so it never renders this icon at all) spells out the
   meaning once, near the top of the tree, rather than on every row. */
.perm-override-icon {
    flex: none;
    display: inline-flex;
    color: var(--color-accent-dark);
    cursor: default;
}

.perm-legend {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0 0 0.75rem;
    color: var(--color-muted);
    font-size: 0.8rem;
}

/* A page acting as its own group (e.g. a Reports landing page) reads as
   subordinate-but-parental: its label is bold, like a mini category
   title, and its children sit in their own indented sublist below. */
.perm-page-item-parent > .perm-page-row label {
    font-weight: 600;
}

.perm-page-sublist {
    list-style: none;
    margin: 0.2rem 0 0;
    padding: 0 0 0 1.6rem;
}

/* --- Employee Verification --- */

/* Search-icon input (e.g. Employee Verification's search box): an icon
   button sits inside the right edge of the text input instead of a
   separate "Search" button next to it. The button stays a real
   type="submit" so the no-JS fallback (typing + pressing it) still works
   — it's only visually an icon, the form still submits normally. With JS,
   results already update live as you type (2+ characters, debounced), so
   in practice this button is rarely clicked; it's there for no-JS and for
   anyone who prefers clicking it.

   .search-field-btn is scoped under .search-field (".search-field
   .search-field-btn", two classes) rather than styled as a bare class —
   "form button[type=\"submit\"]" above (the generic full-width/accent/
   margined button rule every other form uses) carries a type+type+
   attribute selector, which out-specifies a single class. Without the
   extra .search-field scope, that generic rule silently won on every
   overlapping property (width, margin, background, color), so the icon
   button rendered as the old full-width blue "Search" button again with
   the icon washed out against it — same markup, only the CSS lost. */
.search-field {
    position: relative;
}

.search-field input[type="text"] {
    padding-right: 2.75rem;
}

.search-field .search-field-btn {
    position: absolute;
    top: 50%;
    right: 0.4rem;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.1rem;
    height: 2.1rem;
    margin: 0;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: none;
    color: var(--color-muted);
    font-size: 1rem;
    font-weight: 400;
    cursor: pointer;
}

.search-field .search-field-btn:hover,
.search-field .search-field-btn:focus-visible {
    color: var(--color-accent-dark);
    background: rgba(14, 165, 233, 0.12);
    outline: none;
}

.empverify-photo-wrap {
    margin: 0 0 1.25rem;
}

.empverify-photo {
    display: block;
    width: 220px;
    max-width: 100%;
    height: auto;
    border-radius: 8px;
    border: 1px solid var(--color-border);
}

.empverify-photo-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 220px;
    max-width: 100%;
    height: 220px;
    border-radius: 8px;
    border: 1px dashed var(--color-border);
    background: var(--color-surface-muted);
    color: var(--color-muted);
    font-size: 0.85rem;
    text-align: center;
    padding: 0.5rem;
}

.empverify-status {
    margin: 1rem 0 0;
    font-weight: 700;
    font-size: 1.1rem;
}

.empverify-status-active {
    color: #16a34a;
}

/* Deliberately louder than the active state — uppercase and larger, not
   just red text — since a missed "not active" reading here is the one
   mistake this whole page exists to prevent. */
.empverify-status-inactive {
    color: #dc2626;
    font-size: 1.35rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* ===== App shell: top bar + sidebar + main content ===== */

body.shell {
    margin: 0;
    background: var(--color-page-bg);
}

.topbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: var(--topbar-height);
    background: var(--color-bg);
    color: #fff;
    display: flex;
    align-items: center;
    padding: 0 1rem;
    z-index: 100;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}

.topbar-toggle {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0.5rem;
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-right: 0.75rem;
}

.topbar-toggle span {
    display: block;
    width: 20px;
    height: 2px;
    background: #fff;
}

.topbar-brand {
    color: #fff;
    text-decoration: none;
    font-weight: 700;
    font-size: 1.1rem;
    white-space: nowrap;
}

.topbar-clock-status {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-right: 1rem;
    font-size: 0.85rem;
    font-weight: 600;
    white-space: nowrap;
    text-decoration: none;
}

a.topbar-clock-status:hover {
    text-decoration: underline;
}

.topbar-clock-icon {
    flex: none;
}

/* Lighter tones than the buttons on the Timeclock page itself (#dc2626 /
   #16a34a) — those sit on white cards, these sit on the dark top bar, so
   they need to read clearly against var(--color-bg) instead. */
.topbar-clock-status-out {
    color: #f87171;
}

.topbar-clock-status-in {
    color: #4ade80;
}

/* Company switcher — was a plain read-only badge; now a button that opens
   a list of every company the user can switch into, same open/close
   interaction pattern as .topbar-user beside it. Clicking an option
   navigates the current tab; middle-click/Ctrl-click opens it in a new
   tab, for free, since these are plain <a> elements (see docs/SETUP.md
   section 34) — no JS needed for that part. */
.topbar-company {
    position: relative;
    margin-right: 20px;
}

.topbar-company-button {
    padding: 0.3rem 0.75rem;
    background: rgba(14, 165, 233, 0.18);
    border: 1px solid rgba(14, 165, 233, 0.4);
    border-radius: 999px;
    font-size: 0.85rem;
    font-weight: 700;
    color: #7dd3fc;
    letter-spacing: 0.01em;
    white-space: nowrap;
    cursor: pointer;
}

.topbar-company-button:hover {
    background: rgba(14, 165, 233, 0.28);
}

.topbar-company-menu {
    display: none;
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    background: var(--color-surface);
    color: var(--color-text);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
    min-width: 220px;
    max-height: 320px;
    overflow-y: auto;
    z-index: 110;
}

.topbar-company-menu.open {
    display: block;
}

.topbar-company-option {
    display: block;
    padding: 0.6rem 1rem;
    color: var(--color-text);
    text-decoration: none;
    font-size: 0.9rem;
}

.topbar-company-option:hover {
    background: var(--color-surface-muted);
}

.topbar-company-option.active {
    font-weight: 700;
    color: #0ea5e9;
}

.topbar-spacer {
    flex: 1;
}

/* Sun/moon toggle: both icons always render, CSS picks which one shows
   based on the current data-theme attribute — the icon shown is the mode
   a click switches TO (moon visible in light mode = click for dark; sun
   visible in dark mode = click for light), matching the convention most
   people already know from other apps. Same translucent-on-dark-topbar
   treatment as .topbar-user-button beside it, since the topbar itself
   stays the same dark navy in both themes (see the dark-theme block near
   the top of this file). */
.theme-toggle-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.1rem;
    height: 2.1rem;
    margin-right: 0.75rem;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.1);
    color: #fff;
    cursor: pointer;
}

.theme-toggle-btn:hover {
    background: rgba(255, 255, 255, 0.18);
}

.theme-icon-moon {
    display: none;
}

html[data-theme="dark"] .theme-icon-sun {
    display: none;
}

html[data-theme="dark"] .theme-icon-moon {
    display: block;
}

.topbar-user {
    position: relative;
}

.topbar-user-button {
    background: rgba(255, 255, 255, 0.1);
    border: none;
    color: #fff;
    padding: 0.4rem 0.9rem;
    border-radius: 8px;
    cursor: pointer;
    font-size: 0.9rem;
}

.topbar-user-button:hover {
    background: rgba(255, 255, 255, 0.18);
}

.topbar-user-menu {
    display: none;
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    background: var(--color-surface);
    color: var(--color-text);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
    min-width: 170px;
    overflow: hidden;
    z-index: 110;
}

.topbar-user-menu.open {
    display: block;
}

.topbar-user-menu a {
    display: block;
    padding: 0.6rem 1rem;
    color: var(--color-text);
    text-decoration: none;
    font-size: 0.9rem;
}

.topbar-user-menu a:hover {
    background: var(--color-surface-muted);
}

.shell-body {
    display: flex;
    padding-top: var(--topbar-height);
    min-height: 100vh;
}

.sidebar {
    position: fixed;
    top: var(--topbar-height);
    bottom: 0;
    left: 0;
    width: var(--sidebar-width);
    background: #1e293b;
    overflow-y: auto;
    transform: translateX(0);
    transition: transform 0.2s ease;
    z-index: 90;
}

body.sidebar-collapsed .sidebar {
    transform: translateX(-100%);
}

.sidebar-menu {
    list-style: none;
    margin: 0;
    padding: 0.75rem 0;
}

.sidebar-link,
.sidebar-group-toggle {
    display: flex;
    align-items: center;
    width: 100%;
    box-sizing: border-box;
    padding: 0.7rem 1.25rem;
    color: #cbd5e1;
    text-decoration: none;
    background: none;
    border: none;
    font-size: 0.9rem;
    text-align: left;
    cursor: pointer;
}

.sidebar-link:hover,
.sidebar-group-toggle:hover {
    background: rgba(255, 255, 255, 0.06);
    color: #fff;
}

.sidebar-link.active {
    background: var(--color-accent);
    color: #fff;
}

/* Category toggle: pushes the chevron to the right of the label whether
   the toggle is a full-width button on its own (a category with no landing
   page yet) or narrowed down to just the arrow next to a link (see
   .sidebar-row below, for a category that has one). */
.sidebar-group-toggle {
    justify-content: space-between;
}

.sidebar-group-arrow {
    flex: none;
    width: 8px;
    height: 8px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg);
    margin-top: -3px;
    transition: transform 0.15s ease;
}

.sidebar-item.open .sidebar-group-arrow {
    transform: rotate(-135deg);
    margin-top: 3px;
}

/* A category that has both a landing page and a submenu (e.g. Admin) renders
   as a link plus a separate small toggle button side by side, instead of
   the label itself doing double duty as both "navigate" and "expand." */
.sidebar-row {
    display: flex;
    align-items: stretch;
}

.sidebar-row .sidebar-link {
    flex: 1;
}

.sidebar-row .sidebar-group-toggle {
    width: auto;
    flex: none;
    padding: 0.7rem 0.9rem;
    justify-content: center;
}

/* "Open in a new tab" icon — a third flex sibling in .sidebar-row (after
   the link, before the group-toggle button if there is one) and, for
   submenu children, the sole sibling in .sidebar-subrow below. Quiet by
   default (dimmer than the link text itself) so it doesn't compete with
   the label for attention, brightening to match the link's own hover
   treatment on hover/focus so it still reads as clickable. Built once in
   header.php ($newTabIcon) and reused at all three call sites — see that
   file's own comment for why this exists and how the target name it
   carries is computed (App\Menu\WindowTarget). */
.sidebar-newtab-icon {
    display: flex;
    flex: none;
    align-items: center;
    justify-content: center;
    padding: 0.7rem 0.85rem;
    color: #64748b;
    text-decoration: none;
}

.sidebar-newtab-icon:hover,
.sidebar-newtab-icon:focus-visible {
    color: #fff;
    background: rgba(255, 255, 255, 0.06);
    outline: none;
}

.sidebar-link-disabled {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.7rem 1.25rem;
    color: #64748b;
    font-size: 0.9rem;
    cursor: default;
}

.sidebar-link-disabled em {
    font-style: normal;
    font-size: 0.7rem;
    background: rgba(255, 255, 255, 0.08);
    padding: 0.15rem 0.4rem;
    border-radius: 4px;
}

.sidebar-submenu {
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.2s ease;
}

.sidebar-item.open .sidebar-submenu {
    max-height: 400px;
}

/* Wraps a child link plus its "open in a new tab" icon side by side —
   same purpose as .sidebar-row above, one level further in. .sidebar-sublink
   keeps its own full padding/font-size below; flex: 1 here just lets it
   share the row with the icon instead of also owning the row's full width
   itself, the same width-vs-flex-basis relationship .sidebar-row .sidebar-link
   already relies on. */
.sidebar-subrow {
    display: flex;
    align-items: stretch;
}

.sidebar-subrow .sidebar-sublink {
    flex: 1;
}

.sidebar-subrow .sidebar-newtab-icon {
    padding: 0.55rem 0.9rem;
}

.sidebar-sublink {
    display: block;
    padding: 0.55rem 1.25rem 0.55rem 2.25rem;
    color: #94a3b8;
    text-decoration: none;
    font-size: 0.85rem;
}

.sidebar-sublink:hover {
    color: #fff;
}

.sidebar-sublink.active {
    background: var(--color-accent);
    color: #fff;
}

.sidebar-sublink.sidebar-link-disabled {
    padding: 0.55rem 1.25rem 0.55rem 2.25rem;
}

.sidebar-backdrop {
    display: none;
    position: fixed;
    inset: var(--topbar-height) 0 0 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 80;
}

.app-main {
    margin-left: var(--sidebar-width);
    padding: 1.5rem;
    flex: 1;
    min-width: 0;
    transition: margin-left 0.2s ease;
    max-width: 960px;
}

body.sidebar-collapsed .app-main {
    margin-left: 0;
}

/* .app-main's own 960px cap above is fine for a form or a treeview, but
   leaves a lot of dead space next to a genuine multi-column table on a wide
   desktop monitor — this app is mostly used on desktop (Jim's own framing),
   so a page that's really just a table should be allowed more of that
   width. Opt-in per page via $bodyClass = 'wide-content' (see header.php's
   doc comment on that variable) rather than raising the cap globally, so
   forms/treeviews keep their current, already-comfortable width and only
   pages that ask for it get more. GL Accounts and Job Maintenance are the
   first two to opt in. Higher specificity than the bare .app-main rule
   above (a body class plus the element, vs. the element alone), so this
   wins regardless of source order once both are in play. */
@media (min-width: 861px) {
    body.wide-content .app-main {
        max-width: 1600px;
    }
}

/* External sidebar links (currently just User Tools — see 'external' =>
   true in app/config/menu.php) open in a new tab rather than navigating
   within the app, so they get a small trailing icon to signal that before
   the user clicks, instead of surprising them with a new tab. Sized and
   dimmed to sit quietly next to the label rather than compete with it. */
.sidebar-link-external {
    justify-content: space-between;
}

.sidebar-external-icon {
    flex: none;
    margin-left: 0.5rem;
    opacity: 0.6;
}

@media (max-width: 860px) {
    .sidebar {
        transform: translateX(-100%);
    }

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

    body.sidebar-open .sidebar-backdrop {
        display: block;
    }

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

/* --- Data tables (e.g. GL Accounts) --- */

/*
 * First real "list of records with per-row actions" pattern in the app —
 * everything before this (Roles, dashboard to-do) was either a simple link
 * list or a couple of fields per row, not a genuine multi-column table.
 *
 * .auth-card-wide is a modifier on .auth-card: the standard card caps at
 * 360px on mobile and 50% of the content area on desktop (see the
 * body.shell .auth-card rule near the top of this file), which is fine for
 * a login form but cramped for a multi-column table. Cards using this
 * modifier grow to the full content-area width on desktop instead, leaving
 * the standard cap untouched for every other card (forms, treeviews, etc.).
 */
@media (min-width: 861px) {
    body.shell .auth-card.auth-card-wide {
        max-width: 100%;
    }
}

.data-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 1rem;
    font-size: 0.85rem;
}

/* Row height cut roughly 60% from the original 0.55rem/0.9rem pass — tight
   enough to fit meaningfully more rows in the same viewport height (the
   whole point of computing pagination from screen height in glhead.js),
   while staying tall enough for the icon buttons in the actions column to
   stay comfortably clickable. vertical-align: middle keeps text and the
   action icons centered on the row now that padding is thin enough for
   baseline alignment to look visibly off otherwise.

   border-bottom uses --color-border-strong, not the lighter --color-border
   most other dividers in this file use — Jim's own monitor(s) washed the
   lighter divider out to invisible in light mode, same complaint the
   report-table striping (below) already solved the same way; using the
   same stronger variable here keeps every row divider in the app
   consistent instead of data tables and printed reports disagreeing. */
.data-table th,
.data-table td {
    text-align: left;
    vertical-align: middle;
    padding: 0.22rem 0.65rem;
    border-bottom: 1px solid var(--color-border-strong);
    white-space: nowrap;
}

.data-table th {
    color: var(--color-text);
    font-size: 0.78rem;
    font-weight: 700;
    padding-top: 0.4rem;
    padding-bottom: 0.4rem;
}

/* Truncate any cell whose fixed column width (set per-table below) is
   narrower than its content, instead of wrapping to a second line or
   silently overflowing into the next column. Harmless on a table that
   never sets table-layout: fixed / explicit widths — auto layout just
   grows the column to fit, so overflow never actually triggers — but every
   list/table page going forward should pair this with its own #id-scoped
   width rules the way #glhead-table and #jchead-table do below, not rely
   on the browser's natural column sizing, which visibly reflows every
   column's width from whatever happens to be showing on the current page
   (distracting during pagination/search/sort — see those tables' own
   comments). Excludes the actions column, which holds icons, not text. */
.data-table td:not(.data-table-actions) {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The muted-gray hover background this used to be (var(--color-surface-muted)
   over var(--color-surface)) was too close in brightness to read reliably
   across different monitors — barely visible in light mode on some
   screens, only slightly better in dark mode. Switched to an
   accent-tinted, semi-transparent background instead: percentage opacity
   over whatever theme is active reads as a clear, deliberate highlight
   rather than a near-invisible shade shift, on both themes and across
   monitor variance. Dark theme gets its own override below using the
   lighter dark-theme accent — the light theme's accent-dark, used as-is,
   would read too dim against the dark surface. */
.data-table tbody tr:hover {
    background: rgba(2, 132, 199, 0.12);
}

html[data-theme="dark"] .data-table tbody tr:hover {
    background: rgba(56, 189, 248, 0.16);
}

/* Standardized column widths for GL Accounts specifically (scoped to
   #glhead-table, not the shared .data-table class other pages also use —
   Roles/Permissions tables have different columns and shouldn't inherit
   this). Without table-layout: fixed, column widths are recalculated from
   whatever text happens to be visible on the current page, so sorting by
   a column full of short values (e.g. "Asset") after one full of long
   values (e.g. "Accumulated Depreciation") visibly reflows every column,
   not just the one being sorted. Fixed widths make every page look the
   same regardless of which values are currently showing; the shared
   overflow/ellipsis rule above keeps a long value from breaking the layout
   instead of wrapping or bleeding into the next column. */
#glhead-table {
    table-layout: fixed;
}

#glhead-table th:nth-child(1),
#glhead-table td:nth-child(1) {
    width: 16%;
}

#glhead-table th:nth-child(2),
#glhead-table td:nth-child(2) {
    width: 34%;
}

#glhead-table th:nth-child(3),
#glhead-table td:nth-child(3) {
    width: 18%;
}

#glhead-table th:nth-child(4),
#glhead-table td:nth-child(4) {
    width: 18%;
}

#glhead-table th:nth-child(5),
#glhead-table td:nth-child(5) {
    width: 14%;
}

/* Same fixed-width treatment for Job Maintenance, same reasoning as
   #glhead-table above — paging/searching/filtering jchead.php was visibly
   reflowing every column's width depending on which jobs happened to be
   showing, which is exactly what fixed percentages + ellipsis truncation
   fixes. Seven columns (six data columns plus the trailing actions
   column), percentages sum to 100: Job # and Customer (the two short, id-
   like columns) get the least room; Name, Address, and Customer Name (the
   three genuinely free-text columns) get the most. */
#jchead-table {
    table-layout: fixed;
}

#jchead-table th:nth-child(1),
#jchead-table td:nth-child(1) {
    width: 9%;
}

#jchead-table th:nth-child(2),
#jchead-table td:nth-child(2) {
    width: 18%;
}

#jchead-table th:nth-child(3),
#jchead-table td:nth-child(3) {
    width: 19%;
}

#jchead-table th:nth-child(4),
#jchead-table td:nth-child(4) {
    width: 16%;
}

#jchead-table th:nth-child(5),
#jchead-table td:nth-child(5) {
    width: 10%;
}

#jchead-table th:nth-child(6),
#jchead-table td:nth-child(6) {
    width: 20%;
}

#jchead-table th:nth-child(7),
#jchead-table td:nth-child(7) {
    width: 8%;
}

/* Same fixed-width treatment for Customer Maintenance, same reasoning as
   #glhead-table/#jchead-table above. Seven columns (six data columns plus
   the trailing actions column), percentages sum to 100: State and ZIP (the
   two short, fixed-format columns) get the least room; Name and Address
   (the two genuinely free-text columns) get the most. */
#cusmaint-table {
    table-layout: fixed;
}

#cusmaint-table th:nth-child(1),
#cusmaint-table td:nth-child(1) {
    width: 10%;
}

#cusmaint-table th:nth-child(2),
#cusmaint-table td:nth-child(2) {
    width: 22%;
}

#cusmaint-table th:nth-child(3),
#cusmaint-table td:nth-child(3) {
    width: 26%;
}

#cusmaint-table th:nth-child(4),
#cusmaint-table td:nth-child(4) {
    width: 16%;
}

#cusmaint-table th:nth-child(5),
#cusmaint-table td:nth-child(5) {
    width: 6%;
}

#cusmaint-table th:nth-child(6),
#cusmaint-table td:nth-child(6) {
    width: 10%;
}

#cusmaint-table th:nth-child(7),
#cusmaint-table td:nth-child(7) {
    width: 10%;
}

/* Column headers double as sort toggles — click to sort ascending, click
   again to reverse. .data-table-sort-indicator holds the ▲/▼ glyph, kept
   as its own span so glhead.js can update just that text on click instead
   of re-rendering the whole header. */
.data-table-sort-link {
    display: inline-flex;
    align-items: center;
    color: inherit;
    font: inherit;
    text-decoration: none;
    cursor: pointer;
}

.data-table-sort-link:hover {
    color: var(--color-accent-dark);
}

.data-table-sort-indicator {
    color: var(--color-accent-dark);
    font-size: 0.7rem;
}

.data-table-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    white-space: nowrap;
}

/* Edit and delete are both plain icon links now (no per-row <form>s —
   delete opens a confirmation modal instead of submitting immediately, see
   glhead.php / glhead.js), so neither needs the "outrank the generic form
   button[type=submit] rule" specificity workaround documented elsewhere in
   this file for actual <button> elements — there's no form here to fight
   with. Sized down to match the shorter row height above. */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.3rem;
    height: 1.3rem;
    border: none;
    border-radius: 4px;
    background: none;
    color: var(--color-muted);
    cursor: pointer;
    text-decoration: none;
    line-height: 1;
}

.icon-btn-edit:hover,
.icon-btn-edit:focus-visible {
    color: var(--color-accent-dark);
    background: rgba(14, 165, 233, 0.12);
    outline: none;
}

/* Dark red at rest, not just on hover — delete is destructive and should
   read that way at a glance in a dense list. "Do away with the button": no
   rounded hover-background box the way Edit has, just the glyph itself
   darkening slightly on hover/focus, so it doesn't read as a UI button at
   all, just a colored X sitting in the row. Sized up beyond the shared
   .icon-btn box (and given its own larger click target) so it reads
   clearly at a glance even in the shorter rows above. */
.icon-btn-delete {
    width: 1.6rem;
    height: 1.6rem;
    color: #7f1d1d;
    font-size: 1.6rem;
    font-weight: 700;
}

.icon-btn-delete:hover,
.icon-btn-delete:focus-visible {
    color: #5c1010;
    background: none;
    outline: none;
}

/* --- GL Accounts toolbar: search box (left) + "Add" button (right), in
   place of the plain descriptive subtitle this page used to have. Reuses
   .search-field/.search-field-btn from Employee Verification's search box
   rather than introducing a second search-input pattern. */
.gl-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin: 1rem 0;
}

.gl-toolbar .search-field {
    flex: 1;
    min-width: 220px;
    max-width: 360px;
}

/* A real button, not a text link — green (matching the "+" this replaced),
   not the app's usual accent-blue, so it stands out from Save/Search as
   its own distinct "create new" action. flex: none keeps it from being the
   item that shrinks/wraps first if the toolbar gets tight. */
.gl-add-btn {
    display: inline-flex;
    flex: none;
    align-items: center;
    gap: 0.45rem;
    padding: 0.55rem 1rem;
    border-radius: 8px;
    background: #16a34a;
    color: #fff;
    font-weight: 600;
    font-size: 0.9rem;
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.15s ease;
}

.gl-add-btn:hover,
.gl-add-btn:focus-visible {
    background: #15803d;
    outline: none;
}

.gl-add-btn-plus {
    font-size: 1.2rem;
    font-weight: 700;
    line-height: 1;
}

/* --- Pagination: rows-per-page is computed by glhead.js from available
   viewport height, not fixed — this bar just shows/hides itself and its
   Prev/Next state based on whatever glhead.js decides. Visible default
   background (not white-on-white against the card) so the buttons read as
   clearly clickable even before hovering. */
.data-table-pager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    margin-top: 1rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--color-border);
    font-size: 0.85rem;
    color: var(--color-muted);
}

/* Same "author display: flex beats the hidden attribute" issue fixed on
   .modal-overlay above — this bar starts hidden in the markup (no
   pagination needed until glhead.js knows the row count) and glhead.js
   toggles that same hidden attribute once maxPage is known. Without this
   rule the bar would render on every load regardless. */
.data-table-pager[hidden] {
    display: none;
}

.data-table-pager button {
    padding: 0.4rem 0.85rem;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    background: var(--color-surface-muted);
    color: var(--color-text);
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
}

.data-table-pager button:hover:not(:disabled) {
    border-color: var(--color-accent);
    background: #e0f2fe;
    color: var(--color-accent-dark);
}

.data-table-pager button:disabled {
    opacity: 0.5;
    cursor: default;
}

@media (max-width: 700px) {
    .data-table-wrap {
        overflow-x: auto;
    }
}

/* --- Print-friendly report pages ---
 *
 * Used by app/views/partials/report-header.php / report-footer.php, NOT
 * body.shell — no topbar, no sidebar, no dark theme (that pair never sets
 * html[data-theme], so these rules only ever see the :root light-theme
 * values above, regardless of the viewer's saved preference). First used
 * by General Ledger's Chart of Accounts report; meant to be reused by
 * every future report across every category, so keep additions here
 * generic rather than GL-specific. See docs/SETUP.md's Reports write-up.
 */
body.report-page {
    margin: 0;
    background: var(--color-page-bg);
    color: var(--color-text);
}

.report-container {
    max-width: 900px;
    margin: 0 auto;
    padding: 1.5rem;
}

.report-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.5rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--color-border);
}

.report-toolbar-back {
    color: var(--color-muted);
    font-size: 0.85rem;
    text-decoration: none;
}

.report-toolbar-back:hover {
    color: var(--color-accent-dark);
}

.report-toolbar-actions {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

.report-print-btn,
.report-csv-btn {
    padding: 0.5rem 1rem;
    border-radius: 8px;
    font-size: 0.85rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    text-decoration: none;
    display: inline-block;
}

.report-print-btn {
    border: 1px solid var(--color-border);
    background: var(--color-accent);
    color: #fff;
}

.report-print-btn:hover {
    background: var(--color-accent-dark);
}

/* Secondary action next to Print — same size/shape, outline instead of a
   solid fill, so Print (the more common action) still reads as primary. */
.report-csv-btn {
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text);
}

.report-csv-btn:hover {
    border-color: var(--color-accent);
    color: var(--color-accent-dark);
}

/* Screen-only nudge toward the browser's own page-number feature — see
   report-header.php's doc comment for why this app doesn't render its own
   "Page X of Y" (no PDF-generation library in this stack, and browsers
   don't expose a total-page-count to page CSS/JS during print). Hidden in
   print like the rest of the toolbar area; it would be a strange thing to
   see on the printout itself. */
.report-print-tip {
    margin: 0 0 1.25rem;
    color: var(--color-muted);
    font-size: 0.78rem;
    font-style: italic;
}

.report-heading {
    margin-bottom: 1.5rem;
}

.report-title {
    margin: 0 0 0.25rem;
    font-size: 1.4rem;
    font-weight: 700;
}

.report-meta {
    margin: 0;
    color: var(--color-muted);
    font-size: 0.85rem;
}

/* Repeating company/report banner (thead) and "printed by" line (tfoot) —
   see report-header.php's doc comment for why these live inside the
   table rather than as page elements: thead/tfoot are the one thing every
   major browser reliably repeats once per printed page on its own.
   Screen-only by default (.report-heading above already covers this on
   screen); shown only under @media print below. */
.report-table-banner-row,
.report-table-footer-row {
    display: none;
}

.report-table-banner-row th {
    text-align: left;
    font-size: 0.95rem;
}

.report-table-footer-row td {
    color: var(--color-muted);
    font-size: 0.78rem;
    font-weight: 400;
    white-space: normal;
}

/* Alternating row shading plus a slightly stronger row-separator line than
   .data-table's default — readability requested specifically for reports,
   where a page of dense rows (unlike GL Accounts' shorter working list)
   is the normal case. Scoped to .report-table, not .data-table itself, so
   this doesn't change the look of GL Accounts' existing editable list.
   print-color-adjust forces the shading to actually come out of the
   printer even if the browser's own "print backgrounds" option is off —
   without it, most browsers strip background colors from print output by
   default and the striping would silently disappear on paper. */
.report-table {
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
}

.report-table tbody tr:nth-child(even) {
    background: var(--color-surface-muted);
}

.report-table td,
.report-table th {
    border-bottom: 1px solid var(--color-border-strong);
}

/* On-screen chrome (back link, Print/CSV buttons, print tip, generated-at
   meta line) has no business on a printed page — only the report title
   and its table should come out of the printer. thead/tfoot repeating on
   every printed page and avoiding a mid-row page break are both standard
   "long table" print behavior most browsers don't apply by default
   without an explicit nudge. */
@media print {
    .report-toolbar,
    .report-print-tip,
    .report-heading {
        display: none;
    }

    .report-table-banner-row,
    .report-table-footer-row {
        display: table-row;
    }

    body.report-page {
        background: #fff;
    }

    .report-container {
        max-width: none;
        padding: 0;
    }

    .data-table thead {
        display: table-header-group;
    }

    .report-table tfoot {
        display: table-footer-group;
    }

    .data-table tr {
        page-break-inside: avoid;
    }
}

/* --- Modal overlay (GL Accounts add/edit) ---
 *
 * The "modal" is the same add/edit card this page always had, now shown as
 * an overlay instead of a permanently-visible card at the bottom of the
 * page. It works with zero JavaScript: app/general-ledger/glhead.php
 * renders this element WITHOUT the `hidden` attribute whenever the server
 * already knows it should be open (?add=1, ?hid=N, or a failed
 * create/update submission) — CSS alone is enough to show it that way.
 * glhead.js layers instant open/close on top for JS-enabled browsers (see
 * that file's openModal()/closeModal()), but never has to be the thing
 * that first decides whether this markup renders open or closed.
 */
.modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    /* Top-aligned rather than vertically centered — centering means the
       card's vertical position depends on its own height, so switching
       from a short tab (Account Info) to a much taller one (Budgets/
       Balances, with their two-column month grids) visibly shifts the
       whole box up or down as its center point moves. Pinning it to the
       top instead keeps that top edge in the same place regardless of
       which tab is showing; only the bottom edge (and the modal's own
       internal scrollbar, via .modal-card's max-height) moves. Applies to
       every modal in the app, not just glhead.php's — currently the only
       two that exist, but this is the shared class, not a page override. */
    align-items: flex-start;
    justify-content: center;
    background: rgba(15, 23, 42, 0.5);
    padding: 3.5rem 1.5rem 1.5rem;
}

/* Without this, the hidden attribute does nothing on this element: the
   browser's default "[hidden] { display: none }" rule is a normal-priority
   user-agent rule, and the unconditional "display: flex" above is a
   normal-priority AUTHOR rule for the same element — author beats
   user-agent regardless of specificity, so display: flex silently won
   every time, on every page load and every JS open/close toggle alike
   (JS only ever sets .hidden, same attribute PHP sets — neither one was
   ever actually respected without this rule). This is the root cause of
   the Shift+F5 bug: both modal-overlay divs are always present in the
   markup, PHP correctly marks the closed one(s) hidden, but CSS ignored
   that and showed both anyway, stacked (same z-index, later one in the
   DOM — the delete-confirm modal — paints on top). This rule reasserts
   display: none whenever hidden is actually present, which is what
   should have been guarding the unconditional display: flex above from
   the start. */
.modal-overlay[hidden] {
    display: none;
}

.modal-card {
    background: var(--color-surface);
    border-radius: var(--radius);
    padding: 1.75rem;
    width: 100%;
    /* Started at 480px (fine for the Account Info tab alone), widened to
       560px for the Budgets/Balances tabs' two-column month grids, and
       widened again here to comfortably fit those same two columns once
       their fields grew label-beside-input pairs rather than stacked
       label-above-input — this app is used almost exclusively on desktop,
       so there's no small-screen tradeoff being made by sizing for that.
       Only glhead.php uses this class (the Remove GL Account modal
       overrides it back down via .modal-card-small), so this doesn't
       affect anything else. */
    max-width: 720px;
    max-height: calc(100vh - 3rem);
    overflow-y: auto;
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.25);
}

/* --- Add/edit modal tabs (GL Accounts: Account Info / Budgets / Balances) ---
 *
 * Pure CSS + native radio/label behavior, no JavaScript required to switch
 * tabs — consistent with every other piece of this modal working without
 * JS. Each radio sits before the tab strip and panels in document order
 * (see glhead.php's comment on why) so the ~ general-sibling combinator
 * below can reach forward from ":checked" on the radio to both the
 * matching label (to highlight it) and the matching panel (to show it).
 * glhead.js additionally resets the selection to Account Info every time
 * the modal opens, so switching which account you're editing doesn't
 * carry over whatever tab was left open on the previous one.
 */
.modal-tab-radio {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.modal-tabs {
    display: flex;
    gap: 0.25rem;
    border-bottom: 1px solid var(--color-border);
    margin: 0.75rem 0 1.1rem;
}

/* display + margin set explicitly here (not left to blockify inside the
   .modal-tabs flex row on their own) because "form label" earlier in this
   file sets display: block and a 1rem top margin on every <label> in a
   form — this class needs to win outright on both properties, not rely on
   flex-item blockification to paper over the leaked display value, and
   the leaked margin-top was real and visible regardless. */
.modal-tab-label {
    display: inline-flex;
    padding: 0.5rem 0.9rem;
    margin: 0;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-muted);
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    user-select: none;
}

.modal-tab-label:hover {
    color: var(--color-text);
}

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

#glhead-tab-info:checked ~ .modal-tab-panel[data-panel="info"],
#glhead-tab-budgets:checked ~ .modal-tab-panel[data-panel="budgets"],
#glhead-tab-balances:checked ~ .modal-tab-panel[data-panel="balances"] {
    display: block;
}

#glhead-tab-info:checked ~ .modal-tabs .modal-tab-label[for="glhead-tab-info"],
#glhead-tab-budgets:checked ~ .modal-tabs .modal-tab-label[for="glhead-tab-budgets"],
#glhead-tab-balances:checked ~ .modal-tabs .modal-tab-label[for="glhead-tab-balances"] {
    color: var(--color-accent-dark);
    border-bottom-color: var(--color-accent);
}

/* Customer Maintenance's Add/Edit modal (Main / Billing / Notes) — same
   plain-radio-plus-sibling-selector mechanism as GL Accounts' tabs just
   above, just with this page's own radio ids and panel names. Billing and
   Notes are both real, clickable tabs already (not disabled) even though
   their fields aren't defined yet — each shows its own "Coming soon"
   placeholder until Jim provides that tab's layout, the same way this
   page's own Edit/Add affordances stayed clickable placeholders before
   this round. */
#cusmaint-tab-main:checked ~ .modal-tab-panel[data-panel="main"],
#cusmaint-tab-billing:checked ~ .modal-tab-panel[data-panel="billing"],
#cusmaint-tab-notes:checked ~ .modal-tab-panel[data-panel="notes"] {
    display: block;
}

#cusmaint-tab-main:checked ~ .modal-tabs .modal-tab-label[for="cusmaint-tab-main"],
#cusmaint-tab-billing:checked ~ .modal-tabs .modal-tab-label[for="cusmaint-tab-billing"],
#cusmaint-tab-notes:checked ~ .modal-tabs .modal-tab-label[for="cusmaint-tab-notes"] {
    color: var(--color-accent-dark);
    border-bottom-color: var(--color-accent);
}

/* Main tab fields capped to a readable width in the wider modal card, same
   reasoning as GL Accounts' Account Info tab just below — a phone number
   or ZIP code stretched edge-to-edge looks unintentional. City/State/ZIP
   sit in their own three-column row instead (.form-row-3), so they're
   excluded here and sized by that rule instead. */
.modal-tab-panel[data-panel="main"] > input[type="text"],
.modal-tab-panel[data-panel="main"] > input[type="email"],
.modal-tab-panel[data-panel="main"] > textarea,
.modal-tab-panel[data-panel="main"] > select,
.modal-tab-panel[data-panel="main"] > .custom-select {
    max-width: 420px;
}

/* City / State / ZIP side by side under one "row" — City gets more room
   than the two short, fixed-format fields next to it. */
.form-row-3 {
    display: flex;
    gap: 1rem;
    max-width: 560px;
}

.form-row-3 > div {
    flex: 2;
    min-width: 0;
}

.form-row-3 > div:nth-child(2),
.form-row-3 > div:nth-child(3) {
    flex: 1;
}

.modal-tab-panel .placeholder-note {
    margin-top: 0;
}

/* Budgets/Balances tabs: two side-by-side columns of compact month fields
   (see glhead.php for exactly which months land in which column — the
   split differs between the two tabs), plus a second, separate
   .glyear-columns block below a divider for the "bottom row" (Annual /
   Year). Plain flex columns rather than CSS grid auto-placement, since
   Balances is 6-left/7-right rather than an even split — explicit columns
   in the markup are simpler and more reliable here than fighting
   grid-auto-flow into an uneven layout. Both .glyear-columns blocks share
   the same parent width and the same flex:1 columns, so their columns
   line up with each other automatically without needing to hardcode a
   pixel width anywhere — no coordination required between the month grid
   and the bottom row beyond both using this same markup pattern. */
.glyear-columns {
    display: flex;
    gap: 1.5rem;
}

.glyear-col {
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
    flex: 1;
    min-width: 0;
}

/* Separates the twelve month fields from the Annual/Year row below them —
   a full-width rule (an <hr>, so it spans the whole tab panel, past both
   columns) plus margin on both sides for breathing room, per Jim's request
   for "vertical space, or perhaps a full-width horizontal rule" between
   the two groups. */
.glyear-divider {
    border: none;
    border-top: 1px solid var(--color-border);
    margin: 1rem 0;
}

/* Label beside its input, not stacked above it — label right-aligned and
   flex-grown to fill whatever space the (fixed-width) input doesn't use.
   Because every field in a column shares that same column width, this
   lands every input's left edge at the same x position without hardcoding
   a label width anywhere: the flex-grown label is what does the aligning. */
.glyear-field {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

.glyear-field label {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--color-muted);
    text-align: right;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Narrower than a typical text input, and right-aligned — these are short
   numeric figures, not prose, so a field that's just wide enough for a
   dollar amount (with right-aligned digits, the way spreadsheets and
   accounting software format numbers) reads better than a full-width box. */
.glyear-input {
    flex: none;
    width: 6.5rem;
    box-sizing: border-box;
    padding: 0.4rem 0.55rem;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    font-size: 0.85rem;
    font-family: inherit;
    text-align: right;
    background: var(--color-surface);
    color: var(--color-text);
}

/* The Budgets tab's Annual box — a computed, read-only running total, not
   something the user types into directly. Muted background signals that
   at a glance, the same way disabled/readonly fields usually read. */
.glyear-input-readonly {
    background: var(--color-surface-muted);
    color: var(--color-muted);
    font-weight: 600;
}

/* Firefox always shows a number input's up/down stepper; WebKit/Blink
   (Chrome, Edge, Safari) only reliably shows it while the field is
   hovered or focused otherwise, which reads as "missing" on a field
   that's sitting there unfocused most of the time — Jim wants the Year
   fields' stepper visible at rest, not just on hover. */
#glhead-budget-year::-webkit-inner-spin-button,
#glhead-budget-year::-webkit-outer-spin-button,
#glhead-balance-year::-webkit-inner-spin-button,
#glhead-balance-year::-webkit-outer-spin-button {
    opacity: 1;
}

/* The Account Info tab keeps its original stacked label-above-input
   layout (Jim's widening/realignment request was specifically for the
   Budgets/Balances tabs) — but left unconstrained, its text fields would
   now stretch edge-to-edge across the wider .modal-card, which reads
   oddly for something as short as an account number. Capping them keeps
   that tab looking intentional in the wider box instead of just along
   for the ride. */
.modal-tab-panel[data-panel="info"] input[type="text"],
.modal-tab-panel[data-panel="info"] .custom-select {
    max-width: 380px;
}

.modal-card-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
}

.modal-card-title {
    margin: 0;
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--color-text);
}

.modal-close-btn {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    margin: -0.25rem -0.25rem 0 0;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: none;
    color: var(--color-muted);
    cursor: pointer;
}

.modal-close-btn:hover,
.modal-close-btn:focus-visible {
    color: var(--color-text);
    background: var(--color-surface-muted);
    outline: none;
}

/* Delete-vs-deactivate confirmation is a smaller, simpler card than the
   add/edit form modal — no fields, just a question and two stacked action
   buttons, so it doesn't need the full 480px width. */
.modal-card-small {
    max-width: 380px;
}

/* The account/name line inside the Remove GL Account modal's title (below
   "Remove GL Account:" via a <br>) reads as a subtitle, not a second
   headline — smaller and lighter than the "Remove GL Account:" text above
   it, matching the visual weight of a heading + detail line rather than
   two equally-loud lines. */
#glhead-delete-modal-account {
    display: inline-block;
    margin-top: 0.2rem;
    font-size: 1rem;
    font-weight: 500;
    color: var(--color-muted);
}

.modal-btn {
    display: block;
    width: 100%;
    margin-top: 0.75rem;
    padding: 0.6rem 1rem;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    font-size: 0.9rem;
    font-weight: 600;
    text-align: center;
    cursor: pointer;
}

/* "Set Inactive" is the non-destructive, reversible choice — styled as the
   safer default option next to the red permanent-delete button below it. */
.modal-btn-neutral {
    background: var(--color-surface-muted);
    color: var(--color-text);
}

.modal-btn-neutral:hover,
.modal-btn-neutral:focus-visible {
    background: #e2e8f0;
    outline: none;
}

/* Permanent delete is the irreversible choice — kept visually distinct
   (solid red, not just red text) so it doesn't get clicked by reflex next
   to the neutral "Set Inactive" option above it. */
.modal-btn-danger {
    background: #991b1b;
    border-color: #991b1b;
    color: #fff;
}

.modal-btn-danger:hover,
.modal-btn-danger:focus-visible {
    background: #7f1d1d;
    border-color: #7f1d1d;
    outline: none;
}

/* --- Job Maintenance (jchead.php): same .gl-toolbar/.data-table/.icon-btn
   foundation GL Accounts already uses, plus two things GL Accounts doesn't
   need — a disabled-icon look for the Edit button and Add link (jchead.php
   ships list-only in this first pass, per Jim's call: no add/edit form
   exists yet, so both affordances are visible but inert rather than either
   being left off entirely or wired to a page that doesn't exist), and a
   small two-way Active/All segmented filter. */
.icon-btn-disabled {
    cursor: not-allowed;
    opacity: 0.55;
}

/* No :hover color-shift for a disabled icon — the whole point is it reads
   as inert at a glance, not as a live control that happens to do nothing. */
.icon-btn-disabled:hover,
.icon-btn-disabled:focus-visible {
    color: var(--color-muted);
    background: none;
}

.gl-add-btn-disabled,
.gl-add-btn-disabled:hover,
.gl-add-btn-disabled:focus-visible {
    background: var(--color-surface-muted);
    color: var(--color-muted);
    cursor: not-allowed;
}

.jc-status-filter {
    display: inline-flex;
    flex: none;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    overflow: hidden;
}

.jc-status-filter-option {
    padding: 0.5rem 0.9rem;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--color-muted);
    text-decoration: none;
    white-space: nowrap;
}

.jc-status-filter-option:not(:first-child) {
    border-left: 1px solid var(--color-border);
}

.jc-status-filter-option.is-active {
    background: var(--color-accent-dark);
    color: #fff;
}

.jc-status-filter-option:hover:not(.is-active),
.jc-status-filter-option:focus-visible:not(.is-active) {
    background: var(--color-surface-muted);
    outline: none;
}
