: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 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);
}

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);
}

.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);
}

.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;
}

/* --- 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:
 * <div class="perm-tree">
 *     <details class="perm-category" open>
 *         <summary class="perm-category-title">General</summary>
 *         <ul class="perm-page-list">
 *             <li class="perm-page-item">
 *                 <label><input type="checkbox" name="pages[]" value="3" checked> Timeclock</label>
 *                 <span class="perm-page-note">Custom for this user</span>
 *             </li>
 *         </ul>
 *     </details>
 * </div>
 * Native HTML5 <details>/<summary> per category — expand/collapse works
 * with zero JavaScript. .perm-page-note 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. 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.
 *
 * Three visual indent levels, each stepping further right than the last:
 * 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 larger left padding indents
 * every page a further step in from its category. 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 {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.2rem 0;
}

.perm-page-item 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-item input[type="checkbox"] {
    width: 1rem;
    height: 1rem;
}

.perm-page-note {
    flex: none;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--color-accent-dark);
}

/* --- 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;
}

.topbar-company {
    margin-right: 20px;
    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;
}

.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;
}

.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;
}

.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;
}

/* 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. */
.data-table th,
.data-table td {
    text-align: left;
    vertical-align: middle;
    padding: 0.22rem 0.65rem;
    border-bottom: 1px solid var(--color-border);
    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;
}

.data-table tbody tr:hover {
    background: var(--color-surface-muted);
}

/* 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; overflow/ellipsis
   below 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%;
}

#glhead-table td:not(.data-table-actions) {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* 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;
    }
}

/* --- 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;
    align-items: center;
    justify-content: center;
    background: rgba(15, 23, 42, 0.5);
    padding: 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%;
    max-width: 480px;
    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);
}

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

.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;
}
