/* =====================================================================
   FleetMS — application stylesheet
   Plain CSS, no framework. Mobile-first, then widened at 768px/1024px.

   Design system: a fleet/logistics-flavoured palette (deep route-map teal
   as the primary, a warm signal-amber as the sparing accent) paired with
   Sora (headings, nav, labels — geometric, confident) and Inter (body and
   dense tabular data — tuned for small sizes and real numerals). Every
   selector below already existed in the previous stylesheet; this is a
   visual pass only; no PHP file needed a class renamed.
   ===================================================================== */

:root {
    /* Neutrals — cool, hue-biased toward the primary rather than flat grey */
    --color-bg: #eef1f7;
    --color-surface: #ffffff;
    --color-surface-alt: #f6f8fc;
    --color-border: #e1e6f0;
    --color-text: #1a2233;
    --color-text-muted: #667085;

    /* Brand */
    --color-primary: #0e7490;
    --color-primary-dark: #0b5c73;
    --color-primary-light: #e2f2f6;
    --color-accent: #f0862b;
    --color-accent-dark: #d16f1a;

    --color-danger: #dc2626;
    --color-danger-dark: #b91c1c;

    --color-sidebar-bg: #0b1626;
    --color-sidebar-bg-alt: #0f1f36;
    --color-sidebar-text: #aeb9cf;
    --color-sidebar-active: #0e7490;
    --color-sidebar-hover-bg: rgba(255, 255, 255, .07);
    --color-sidebar-hover-text: #fff;
    --color-sidebar-icon-bg: rgba(255, 255, 255, .06);
    --color-sidebar-recess-bg: rgba(0, 0, 0, .16);
    --color-sidebar-recess-bg-2: rgba(0, 0, 0, .14);
    --color-sidebar-border: rgba(255, 255, 255, .06);
    --color-sidebar-border-strong: rgba(255, 255, 255, .08);
    --color-sidebar-brand-text: #fff;

    /* Fixed dark "chrome" — the navy/teal gradient on KPI ring cards and
       dashboard widget headers (.kpi-card/.dash-widget .card-header). This
       is a deliberate accent (like the amber/teal brand pair), not "the
       sidebar's colour" — it stays this same dark navy in both themes, so
       it is its own token pair and NOT overridden by [data-theme="light"]
       the way --color-sidebar-bg is. Sharing the sidebar tokens here was
       the original design (and how these two both got their look) but it
       meant a light sidebar silently turned these headers white-on-white
       too; keeping the values identical, just under a name that says why
       they don't move. */
    --color-header-dark: #0b1626;
    --color-header-dark-alt: #0f1f36;

    /* Login page — kept as full values (not just colour stops) so the two
       themes can shape the gradients themselves, not only recolour them. */
    --login-wrap-bg: radial-gradient(circle at 15% 15%, #12283b 0%, var(--color-sidebar-bg) 45%, #060b14 100%);
    --login-brand-bg:
        radial-gradient(circle at 85% 15%, rgba(240, 134, 43, .35), transparent 55%),
        linear-gradient(160deg, var(--color-sidebar-bg-alt), var(--color-sidebar-bg) 65%, #071019);
    --login-brand-text: #fff;
    --login-dot-color: rgba(255, 255, 255, .14);

    /* Semantic (kept independent from the brand accent so status never
       reads as "a highlighted control") */
    --green: #16a34a;
    --green-soft-bg: #dcfce7;
    --green-soft-text: #15803d;
    --amber: #d97706;
    --amber-soft-bg: #fef3c7;
    --amber-soft-text: #92400e;
    --red: #dc2626;
    --red-soft-bg: #fee2e2;
    --red-soft-text: #991b1b;
    --grey: #6b7280;
    --grey-soft-bg: #eef1f6;
    --grey-soft-text: #475569;

    --radius: 10px;
    --radius-lg: 16px;
    --shadow-sm: 0 1px 2px rgba(15, 23, 42, .06);
    --shadow: 0 6px 16px -4px rgba(15, 42, 65, .12), 0 2px 5px rgba(15, 42, 65, .06);
    --shadow-lg: 0 24px 48px -12px rgba(8, 20, 35, .35);
    --sidebar-width: 256px;
    --topbar-height: 62px;
    --font-display: "Sora", "Segoe UI", -apple-system, BlinkMacSystemFont, sans-serif;
    --font-body: "Inter", "Segoe UI", -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;
}

/* ---------- Light theme ---------- */
/* The content area (cards, tables, forms) is already light in the default
   theme above — what actually reads as "dark" throughout the app is the
   sidebar and the login page, so that's what this overrides. Toggled via
   the sun/moon control in the topbar (see .theme-toggle + app.js) and
   applied as a data-theme attribute on <html>, set before first paint by
   the inline snippet in includes/theme_init.php — see that file for why.
   Everything not listed here (brand teal/amber, status colours, card/table
   surface tokens) is intentionally shared between both themes. */
:root[data-theme="light"] {
    --color-sidebar-bg: #ffffff;
    --color-sidebar-bg-alt: #f7f9fc;
    --color-sidebar-text: #5b6b85;
    --color-sidebar-hover-bg: rgba(14, 116, 144, .09);
    --color-sidebar-hover-text: #0b5c73;
    --color-sidebar-icon-bg: rgba(14, 116, 144, .08);
    --color-sidebar-recess-bg: rgba(15, 23, 42, .035);
    --color-sidebar-recess-bg-2: rgba(15, 23, 42, .028);
    --color-sidebar-border: rgba(15, 23, 42, .08);
    --color-sidebar-border-strong: rgba(15, 23, 42, .09);
    --color-sidebar-brand-text: #101828;

    --login-wrap-bg: radial-gradient(circle at 15% 15%, #eaf5f7 0%, #eef1f7 45%, #f8fafc 100%);
    --login-brand-bg:
        radial-gradient(circle at 85% 15%, rgba(240, 134, 43, .16), transparent 55%),
        linear-gradient(160deg, #eef7f8, #f6fafb 65%, #ffffff);
    --login-brand-text: #16283a;
    --login-dot-color: rgba(15, 23, 42, .1);
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--color-bg);
    color: var(--color-text);
    font-family: var(--font-body);
    font-size: 15px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}

@media (prefers-reduced-motion: reduce) {
    * { transition-duration: 0.001ms !important; animation-duration: 0.001ms !important; }
}

/* ---------- Motion: page-load entrance ---------- */
/* One shared animation system, hooked onto the layout's own structural
   selectors (.content, table.data-grid, .flash, .btn) so every module page
   gets it for free from this one place — nothing per-module to add or keep
   in sync. Dashboard KPI rings/widgets keep their own scroll-triggered
   reveal (dashboard/_widgets.php + initDashboardReveal in app.js); this
   layer only fades in the *container* they sit in, so the two never fight
   over the same element. */

@keyframes fx-fade-up {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: translateY(0); }
}
@keyframes fx-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}
@keyframes fx-pop-in {
    from { opacity: 0; transform: translateY(14px) scale(.98); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

.content > * { animation: fx-fade-up .45s cubic-bezier(.16, .8, .3, 1) both; }
.content > *:nth-child(1) { animation-delay: .01s; }
.content > *:nth-child(2) { animation-delay: .06s; }
.content > *:nth-child(3) { animation-delay: .11s; }
.content > *:nth-child(4) { animation-delay: .16s; }
.content > *:nth-child(5) { animation-delay: .21s; }
.content > *:nth-child(n+6) { animation-delay: .25s; }

/* Table rows cascade in (opacity only — a <tr> in table layout doesn't
   reliably animate `transform` across browsers, so rows fade rather than
   slide). Capped at the first screenful; anything past row 12 still fades,
   just without the staggered wait. */
table.data-grid tbody tr { animation: fx-fade-in .3s ease both; }
table.data-grid tbody tr:nth-child(1) { animation-delay: .02s; }
table.data-grid tbody tr:nth-child(2) { animation-delay: .04s; }
table.data-grid tbody tr:nth-child(3) { animation-delay: .06s; }
table.data-grid tbody tr:nth-child(4) { animation-delay: .08s; }
table.data-grid tbody tr:nth-child(5) { animation-delay: .10s; }
table.data-grid tbody tr:nth-child(6) { animation-delay: .12s; }
table.data-grid tbody tr:nth-child(7) { animation-delay: .14s; }
table.data-grid tbody tr:nth-child(8) { animation-delay: .16s; }
table.data-grid tbody tr:nth-child(9) { animation-delay: .18s; }
table.data-grid tbody tr:nth-child(10) { animation-delay: .20s; }
table.data-grid tbody tr:nth-child(11) { animation-delay: .22s; }
table.data-grid tbody tr:nth-child(n+12) { animation-delay: .24s; }

::selection { background: var(--color-primary); color: #fff; }

::-webkit-scrollbar { width: 11px; height: 11px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #c4cddc; border-radius: 999px; border: 3px solid var(--color-bg); }
::-webkit-scrollbar-thumb:hover { background: #a9b5cc; }

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

h1, h2, h3 { margin: 0 0 12px; font-family: var(--font-display); font-weight: 700; letter-spacing: -.01em; }
h1 { font-size: 1.5rem; }
h2 { font-size: 1.2rem; }
h3 { font-size: .82rem; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: .07em; font-weight: 700; }

:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: 4px;
}

/* ---------- App shell ---------- */

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

.sidebar {
    width: var(--sidebar-width);
    background: linear-gradient(185deg, var(--color-sidebar-bg-alt) 0%, var(--color-sidebar-bg) 55%);
    color: var(--color-sidebar-text);
    flex-shrink: 0;
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    overflow-y: auto;
    overflow-x: hidden;
    z-index: 40;
    transition: transform .22s ease, background .2s ease, color .2s ease;
    border-right: 1px solid var(--color-sidebar-border);
}

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 18px 18px;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.15rem;
    letter-spacing: -.01em;
    color: var(--color-sidebar-brand-text);
    border-bottom: 1px solid var(--color-sidebar-border-strong);
    transition: color .2s ease, border-color .2s ease;
}

.sidebar-brand::before {
    content: "";
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 9px;
    background: linear-gradient(135deg, var(--color-accent), var(--color-primary) 115%);
    box-shadow: 0 3px 10px rgba(240, 134, 43, .35);
    display: inline-block;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 16.5V7a1 1 0 0 1 1-1h9v10.5'/%3E%3Cpath d='M13 9.5h4.2a1 1 0 0 1 .85.47l2.2 3.53a1 1 0 0 1 .15.53V16a.5.5 0 0 1-.5.5H19'/%3E%3Ccircle cx='7' cy='17' r='2'/%3E%3Ccircle cx='17' cy='17' r='2'/%3E%3C/svg%3E") center / 60% no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 16.5V7a1 1 0 0 1 1-1h9v10.5'/%3E%3Cpath d='M13 9.5h4.2a1 1 0 0 1 .85.47l2.2 3.53a1 1 0 0 1 .15.53V16a.5.5 0 0 1-.5.5H19'/%3E%3Ccircle cx='7' cy='17' r='2'/%3E%3Ccircle cx='17' cy='17' r='2'/%3E%3C/svg%3E") center / 60% no-repeat;
}

.sidebar nav { padding: 10px 10px 24px; }

.sidebar nav a {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 10px 12px;
    margin: 1px 0;
    border-radius: 9px;
    color: var(--color-sidebar-text);
    font-size: .89rem;
    font-weight: 500;
    position: relative;
    transition: background .15s ease, color .15s ease, padding-left .15s ease;
}
.sidebar nav a:hover { padding-left: 15px; }

.sidebar nav a:hover { background: var(--color-sidebar-hover-bg); color: var(--color-sidebar-hover-text); text-decoration: none; }
.sidebar nav a.active {
    background: linear-gradient(90deg, var(--color-sidebar-active), rgba(14, 116, 144, .55));
    color: #fff;
    font-weight: 600;
    box-shadow: var(--shadow-sm);
}
.sidebar nav a.active::before {
    content: "";
    position: absolute;
    left: -10px;
    top: 8px;
    bottom: 8px;
    width: 4px;
    border-radius: 0 4px 4px 0;
    background: var(--color-accent);
}
.sidebar nav > a.active::before { left: -10px; }

.sidebar .icon {
    width: 26px;
    height: 26px;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: .92rem;
    border-radius: 7px;
    background: var(--color-sidebar-icon-bg);
    transition: background .15s ease;
}
.sidebar nav a.active .icon { background: rgba(255, 255, 255, .18); }

/* Nested sidebar groups — up to 3 levels (Module -> Direct/Tools/Reports/Settings ->
   individual screen), matching fleetwave_sidebar_structure.md's own tree. Rules below
   are written against the shared `.nav-parent`/`.nav-children`/`.nav-group` classes so
   they apply at any nesting depth; `.nav-parent-sub`/`.nav-group-sub` add the level-2-only
   differences (it's a <button>, not a link — there's no page of its own to open). */
.sidebar nav .nav-parent { justify-content: space-between; }
.sidebar nav .nav-parent > span:first-child { display: flex; align-items: center; gap: 11px; }
.sidebar nav .chevron-toggle {
    opacity: .55;
    font-size: .72rem;
    padding: 4px 6px;
    transition: transform .18s ease;
}
.sidebar nav .nav-group.open > .nav-parent .chevron-toggle { transform: rotate(90deg); opacity: .9; }
.sidebar nav .nav-children {
    display: none;
    flex-direction: column;
    background: var(--color-sidebar-recess-bg);
    border-radius: 8px;
    margin: 2px 0 4px;
    padding: 2px;
}
.sidebar nav .nav-group.open > .nav-children { display: flex; }
.sidebar nav .nav-children a { padding-left: 40px; font-size: .84rem; }
.sidebar nav .nav-children a.active::before { display: none; }
.sidebar nav .nav-children a.active { background: rgba(14, 116, 144, .5); }

/* Level-2 sub-menu header (Direct/Tools/Reports/Settings) — a <button>, so it needs its
   own reset instead of inheriting `.sidebar nav a`'s anchor styling. Kept visually distinct
   from a level-3 leaf link (uppercase, smaller, dimmer until opened) while still reading as
   clickable, since — unlike the old plain-text heading it replaces — it now really toggles. */
.sidebar nav button.nav-parent-sub {
    all: unset;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 9px 12px 9px 24px;
    color: var(--color-sidebar-text);
    font-family: var(--font-display);
    font-size: .72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .07em;
    opacity: .6;
    cursor: pointer;
    border-radius: 7px;
}
.sidebar nav button.nav-parent-sub:hover { background: var(--color-sidebar-hover-bg); opacity: 1; }
.sidebar nav .nav-group-sub.open > button.nav-parent-sub { opacity: 1; }

/* Level-3 leaf links (nested inside a level-2 sub-menu's own .nav-children) sit deeper
   than a level-2 header — this selector is more specific than the plain `.nav-children a`
   rule above, so it wins without needing !important. */
.sidebar nav .nav-children .nav-children a { padding-left: 52px; font-size: .82rem; }
.sidebar nav .nav-children .nav-children { background: var(--color-sidebar-recess-bg-2); margin: 0; }

.main {
    margin-left: var(--sidebar-width);
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.topbar {
    height: var(--topbar-height);
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 22px;
    position: sticky;
    top: 0;
    z-index: 30;
    box-shadow: 0 1px 0 rgba(15, 23, 42, .02);
}

.topbar::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    height: 2px;
    background: linear-gradient(90deg, var(--color-primary), var(--color-accent) 60%, transparent);
    opacity: .5;
}
.topbar { position: sticky; }

.topbar .page-title { font-family: var(--font-display); font-weight: 700; font-size: 1.02rem; letter-spacing: -.01em; }

.menu-toggle {
    display: none;
    background: none;
    border: none;
    font-size: 1.35rem;
    cursor: pointer;
    color: var(--color-text);
    border-radius: 8px;
    padding: 4px 8px;
}
.menu-toggle:hover { background: var(--color-surface-alt); }

/* Dark/Light toggle — sits in the topbar (see includes/layout_start.php)
   and, since it's the same markup + JS, again in the corner of the login
   card (login.php). The icon shown is the theme that's currently active
   (moon while dark, sun once switched to light), matching the same
   show-current-state convention as .password-toggle's eye icon. */
.theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    background: none;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    cursor: pointer;
    color: var(--color-text-muted);
    flex-shrink: 0;
    transition: background .15s ease, color .15s ease, transform .15s ease;
}
.theme-toggle:hover { background: var(--color-surface-alt); color: var(--color-primary); }
.theme-toggle:active { transform: scale(.9); }
.theme-toggle svg { width: 17px; height: 17px; }
.theme-toggle .icon-sun { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .icon-sun { display: block; }

.user-menu { display: flex; align-items: center; gap: 12px; font-size: .87rem; color: var(--color-text-muted); }
.user-avatar {
    width: 32px;
    height: 32px;
    border-radius: 999px;
    background: linear-gradient(135deg, var(--color-primary), var(--color-accent) 130%);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .78rem;
    flex-shrink: 0;
}
.user-menu-text { display: flex; flex-direction: column; line-height: 1.25; }
.user-menu-text strong { color: var(--color-text); font-weight: 600; font-size: .87rem; }
.user-menu-text span { font-size: .74rem; text-transform: uppercase; letter-spacing: .04em; }

.content { padding: 22px; flex: 1; }

.sidebar-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(9, 14, 25, .5);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    z-index: 35;
}

@media (max-width: 900px) {
    .sidebar { transform: translateX(-100%); box-shadow: var(--shadow-lg); }
    .sidebar.open { transform: translateX(0); }
    .main { margin-left: 0; }
    .menu-toggle { display: block; }
    .sidebar-backdrop.open { display: block; }
    .content { padding: 16px; }
}

/* ---------- Flash messages ---------- */

.flash {
    padding: 11px 15px;
    border-radius: var(--radius);
    margin-bottom: 14px;
    font-size: .9rem;
    font-weight: 500;
    border: 1px solid transparent;
    display: flex;
    align-items: center;
    gap: 8px;
}
.flash::before { font-size: 1rem; line-height: 1; }
.flash-success { background: var(--green-soft-bg); color: var(--green-soft-text); border-color: #a7f3d0; }
.flash-success::before { content: "\2713"; }
.flash-error { background: var(--red-soft-bg); color: var(--red-soft-text); border-color: #fecaca; }
.flash-error::before { content: "\26A0"; }
.flash-info { background: var(--color-primary-light); color: var(--color-primary-dark); border-color: #bfe3ea; }
.flash-info::before { content: "\2139"; }

/* ---------- Cards / panels ---------- */

.card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    margin-bottom: 18px;
}

.card-header {
    padding: 14px 18px;
    border-bottom: 1px solid var(--color-border);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .96rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
}

.card-body { padding: 18px; }

/* ---------- Buttons ---------- */

.btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 9px 16px;
    border-radius: 9px;
    border: 1px solid var(--color-border);
    background: var(--color-surface-alt);
    color: var(--color-text);
    font-size: .88rem;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    font-family: var(--font-body);
    transition: transform .12s ease, box-shadow .12s ease, background .12s ease, filter .12s ease;
}
.btn:hover { text-decoration: none; background: #eef1f7; transform: translateY(-1px); }
.btn:active { transform: translateY(0) scale(.97); }
.btn-primary {
    background: linear-gradient(135deg, var(--color-primary), var(--color-primary-dark));
    color: #fff;
    border-color: transparent;
    box-shadow: 0 4px 12px -3px rgba(14, 116, 144, .5);
}
.btn-primary:hover { filter: brightness(1.06); box-shadow: 0 6px 16px -3px rgba(14, 116, 144, .6); }
.btn-danger {
    background: linear-gradient(135deg, var(--color-danger), var(--color-danger-dark));
    color: #fff;
    border-color: transparent;
    box-shadow: 0 4px 12px -3px rgba(220, 38, 38, .4);
}
.btn-danger:hover { filter: brightness(1.06); }
.btn-sm { padding: 6px 11px; font-size: .8rem; border-radius: 7px; }
.btn[disabled] { opacity: .5; cursor: not-allowed; transform: none; }

/* ---------- Badges (status pills) ---------- */
/* Soft "chip" treatment: tinted background + matching text colour, rather than a solid
   fill — easier on the eye across a dense grid of them and reads as more considered than
   a flat colour block. badge-success/badge-danger are aliases some modules already use
   for the same green/red semantics. */

.badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 11px;
    border-radius: 999px;
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .01em;
}
.badge-green, .badge-success { background: var(--green-soft-bg); color: var(--green-soft-text); }
.badge-amber { background: var(--amber-soft-bg); color: var(--amber-soft-text); }
.badge-red, .badge-danger { background: var(--red-soft-bg); color: var(--red-soft-text); }
.badge-grey { background: var(--grey-soft-bg); color: var(--grey-soft-text); }

/* ---------- Data grid (list views) ---------- */

.grid-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
    margin-bottom: 14px;
}

.grid-toolbar input[type="text"],
.grid-toolbar select {
    padding: 8px 12px;
    border: 1px solid var(--color-border);
    border-radius: 9px;
    font-size: .87rem;
    background: var(--color-surface);
    font-family: inherit;
}
.grid-toolbar input[type="text"] { flex: 1; min-width: 160px; }
.grid-toolbar input[type="text"]:focus, .grid-toolbar select:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-primary-light);
}

.table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    /* Standard 4-layer "scroll shadow" trick: two edge shadows that scroll
       WITH the content (so each only shows once there's actually more
       table off that edge) plus two solid covers that mask them right at
       the border. Without this, a table wider than its box on a touch
       device — which hides its scrollbar by default — just looks cut off
       with no hint there's more to see; this makes "swipe for more"
       visible on both edges, correctly, without any JS. */
    background:
        linear-gradient(to right, var(--color-surface) 50%, rgba(255, 255, 255, 0) 100%) 0 0,
        linear-gradient(to left, var(--color-surface) 50%, rgba(255, 255, 255, 0) 100%) 100% 0,
        radial-gradient(farthest-side at 0 50%, rgba(15, 23, 42, .14), rgba(0, 0, 0, 0)) 0 0,
        radial-gradient(farthest-side at 100% 50%, rgba(15, 23, 42, .14), rgba(0, 0, 0, 0)) 100% 0;
    background-repeat: no-repeat;
    background-color: var(--color-surface);
    background-size: 24px 100%, 24px 100%, 10px 100%, 10px 100%;
    background-attachment: local, local, scroll, scroll;
}

table.data-grid { width: 100%; border-collapse: collapse; font-size: .87rem; white-space: nowrap; }
table.data-grid th {
    text-align: left;
    background: var(--color-surface-alt);
    color: var(--color-text-muted);
    padding: 11px 14px;
    border-bottom: 1px solid var(--color-border);
    position: sticky;
    top: 0;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .74rem;
    text-transform: uppercase;
    letter-spacing: .05em;
}
table.data-grid th a { color: var(--color-text-muted); }
table.data-grid td { padding: 10px 14px; border-bottom: 1px solid var(--color-border); font-variant-numeric: tabular-nums; }
table.data-grid tbody tr { transition: background .1s ease; }
table.data-grid tbody tr:nth-child(even) { background: rgba(246, 248, 252, .55); }
table.data-grid tbody tr:hover { background: var(--color-primary-light); box-shadow: inset 3px 0 0 var(--color-primary); }
table.data-grid .empty-row td { text-align: center; color: var(--color-text-muted); padding: 30px; }
table.data-grid .empty-row:hover { background: transparent; box-shadow: none; }

table.wall-planner { table-layout: fixed; white-space: normal; }
table.wall-planner th { text-align: center; }
table.wall-planner td.wall-planner-day, table.wall-planner td.wall-planner-blank {
    vertical-align: top; height: 100px; width: 14.28%; padding: 6px;
}
table.wall-planner td.wall-planner-blank { background: var(--color-surface-alt); }
table.wall-planner td.wall-planner-today { background: var(--color-primary-light); }
.wall-planner-date { font-weight: 700; font-size: .82rem; margin-bottom: 4px; }
.wall-planner-chip {
    display: block; font-size: .72rem; padding: 3px 6px; margin-bottom: 3px;
    border-radius: 5px; background: var(--color-primary); color: #fff;
    text-decoration: none; white-space: normal; overflow-wrap: anywhere;
}
.wall-planner-chip:hover { opacity: .85; }
.wall-planner-chip .badge, .wall-planner-chip span[class*="badge"] { display: block; margin-top: 2px; }

.pagination { display: flex; align-items: center; gap: 6px; margin-top: 14px; flex-wrap: wrap; }
.pagination a, .pagination span {
    padding: 7px 12px;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    font-size: .83rem;
    font-weight: 600;
    color: var(--color-text);
    background: var(--color-surface);
}
.pagination a:hover { text-decoration: none; border-color: var(--color-primary); color: var(--color-primary); }
.pagination .current { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }

/* ---------- Detail / tabbed form ---------- */

.record-header {
    background: linear-gradient(135deg, var(--color-surface-alt), #eef4f6);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: 18px;
    margin-bottom: 18px;
}

.field-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 14px 24px;
}

.field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.field label { font-size: .75rem; color: var(--color-text-muted); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; }
.btn-link {
    background: none; border: none; padding: 0; margin-left: 4px;
    color: var(--color-primary); font-size: .78rem; font-weight: 700; cursor: pointer;
    text-decoration: underline;
}
.btn-link:hover { opacity: .8; color: var(--color-primary-dark); }
.field .value { padding: 7px 0; word-break: break-word; }
.field input[type="text"],
.field input[type="password"],
.field input[type="date"],
.field input[type="month"],
.field input[type="number"],
.field input[type="time"],
.field input[type="email"],
.field select,
.field textarea {
    padding: 8px 11px;
    border: 1px solid var(--color-border);
    border-radius: 9px;
    font-size: .89rem;
    font-family: inherit;
    width: 100%;
    background: var(--color-surface);
    transition: border-color .12s ease, box-shadow .12s ease;
}
.field input:focus, .field select:focus, .field textarea:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-primary-light);
}
/* Password masking glyphs are drawn from the input's own font — a display
   webfont like Sora/Inter (only loaded at a few weights) can substitute an
   odd fallback glyph for the bullet character, so the dots come out an
   uneven size with ragged spacing. A plain system font keeps every dot the
   same round shape at a predictable size, and a touch of letter-spacing
   gives them even, deliberate breathing room instead of huddling together. */
.field input[type="password"] {
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    letter-spacing: 2px;
}
.field input[type="password"]::placeholder { letter-spacing: normal; }

/* Password field with a show/hide toggle — wraps the input so the eye button
   can sit inside its right edge without disturbing the field's own height,
   border or padding, so it lines up exactly with every other .field input
   (username included) rather than looking like a different control. */
.password-field { position: relative; }
.password-field input[type="password"],
.password-field input[type="text"] { padding-right: 42px; }
.password-toggle {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 42px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    cursor: pointer;
    color: var(--color-text-muted);
    border-radius: 0 9px 9px 0;
}
.password-toggle:hover { color: var(--color-primary); }
.password-toggle:active svg { transform: scale(.85); }
.password-toggle svg { width: 19px; height: 19px; transition: transform .1s ease; }
.password-toggle .icon-eye-off { display: none; }
.password-field.is-visible .icon-eye { display: none; }
.password-field.is-visible .icon-eye-off { display: block; }
.field input[readonly], .field .calculated {
    background: var(--color-surface-alt);
    color: var(--color-text-muted);
}
.field .value-bold { font-weight: 700; color: var(--color-text); }
.field .value-highlight {
    background: var(--green-soft-bg);
    color: var(--green-soft-text);
    font-weight: 700;
    padding: 8px 11px;
    border-radius: 9px;
    border: 1px solid #6ee7b7;
}
.field textarea { resize: vertical; min-height: 60px; }

.section-title {
    grid-column: 1 / -1;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .95rem;
    color: var(--color-primary-dark);
    border-bottom: 2px solid var(--color-primary-light);
    padding-bottom: 7px;
    margin: 20px 0 4px;
}
.field-grid:first-child .section-title:first-child { margin-top: 0; }

/* Tabs — a segmented-control look rather than flat rectangular file-folder tabs */

.tab-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    background: var(--color-surface-alt);
    border: 1px solid var(--color-border);
    border-radius: 11px;
    padding: 4px;
    margin-bottom: 18px;
}
.tab-bar button {
    padding: 9px 16px;
    background: transparent;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    font-size: .85rem;
    font-weight: 600;
    color: var(--color-text-muted);
    font-family: var(--font-body);
    transition: background .12s ease, color .12s ease;
}
.tab-bar button:hover { color: var(--color-text); }
.tab-bar button.active { background: var(--color-surface); color: var(--color-primary-dark); box-shadow: var(--shadow-sm); }
.tab-panel { display: none; }
.tab-panel.active { display: block; }

.form-actions {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 22px;
    padding-top: 18px;
    border-top: 1px solid var(--color-border);
    flex-wrap: wrap;
}

/* Child grids embedded inside a tab */

.child-grid-header {
    background: var(--color-header-dark);
    color: #fff;
    padding: 10px 15px;
    border-radius: var(--radius) var(--radius) 0 0;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .85rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.child-grid-wrap table.data-grid { border-radius: 0 0 var(--radius) var(--radius); }
.child-grid-wrap { margin-top: 12px; }

.inline-add-form {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 12px;
    background: var(--color-surface-alt);
    border-top: 1px solid var(--color-border);
    align-items: flex-end;
}
.inline-add-form .field { flex: 1; min-width: 130px; }

/* Upload dropzone */

.dropzone {
    border: 2px dashed var(--color-border);
    border-radius: var(--radius);
    padding: 22px;
    text-align: center;
    color: var(--color-text-muted);
    background: var(--color-surface-alt);
    transition: background .12s ease, border-color .12s ease;
}
.dropzone.dragover { background: var(--color-primary-light); border-color: var(--color-primary); }

/* ---------- Dashboard KPI cards ---------- */

/* 1 card per row up to and including tablet width; 2 per row from desktop
   (>=1024px) up — an explicit breakpoint rather than auto-fit, so this
   doesn't quietly drift to 3+ per row on a wider desktop. */
.kpi-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
}
@media (min-width: 1024px) {
    .kpi-grid { grid-template-columns: repeat(2, 1fr); }
}

/* Reports page: category blocks flow in a masonry column layout — matches
   the reference system's Reports page, where each category is a heading plus
   a boxed stack of report links, and categories fill 3 columns left-to-right
   rather than 1-per-row cards. Mobile-first: 1 column, then 2 at tablet
   width, then 3 from desktop (>=1024px) up. break-inside: avoid keeps a
   single category's heading and links from splitting across two columns. */
.report-columns {
    columns: 1;
    column-gap: 22px;
}
@media (min-width: 640px) {
    .report-columns { columns: 2; }
}
@media (min-width: 1024px) {
    .report-columns { columns: 3; }
}
.report-category {
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
    margin-bottom: 26px;
}
.report-category-title {
    font-family: var(--font-display);
    font-size: 1.02rem;
    font-weight: 700;
    color: var(--color-text);
    margin: 0 0 10px;
    padding-left: 12px;
    border-left: 3px solid var(--color-accent);
}
.report-links-box {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    padding: 10px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.report-link-btn {
    width: 100%;
    text-align: left;
    white-space: normal;
    border-radius: 8px;
    background: transparent;
    border-color: transparent;
    box-shadow: none;
    color: var(--color-text);
    font-weight: 500;
}
.report-link-btn:hover { background: var(--color-primary-light); transform: none; color: var(--color-primary-dark); }
.report-link-btn .report-link-icon { color: var(--color-primary); }
.report-link-icon { flex-shrink: 0; opacity: .85; }
.kpi-card .card-header {
    background: linear-gradient(120deg, var(--color-header-dark-alt), var(--color-header-dark));
    color: #fff;
    border-bottom: none;
    position: relative;
}
.kpi-card .card-header::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 3px;
    background: linear-gradient(90deg, var(--color-accent), var(--color-primary));
}
.kpi-rings { display: flex; justify-content: space-around; flex-wrap: wrap; gap: 14px; padding: 12px 0; }
.kpi-ring { text-align: center; }
.kpi-ring svg { display: block; margin: 0 auto; overflow: visible; }
.kpi-ring-track { stroke: var(--color-surface-alt); }
.kpi-ring-progress {
    transition: stroke-dashoffset 1.1s cubic-bezier(.22, .9, .3, 1);
    filter: drop-shadow(0 0 5px color-mix(in srgb, currentColor 55%, transparent));
}
.kpi-ring-value {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 800;
    fill: var(--color-text);
    font-variant-numeric: tabular-nums;
}
.kpi-ring .kpi-label { font-size: .77rem; color: var(--color-text-muted); margin-top: 4px; max-width: 110px; }

/* ---------- Reveal-on-scroll + hover lift (dashboard) ---------- */
/* Rings draw in and bars grow as each widget scrolls into view (see
   initDashboardReveal() in app.js), rather than dumping every animation on
   page load where most of a long dashboard is still off-screen. Cards get
   a small hover lift so the page reads as tactile, not flat. */

.kpi-card, .dash-widget {
    transition: transform .18s ease, box-shadow .18s ease;
}
.kpi-card:hover, .dash-widget:hover {
    transform: translateY(-3px);
    box-shadow: 0 14px 30px -10px rgba(15, 42, 65, .22), 0 2px 6px rgba(15, 42, 65, .08);
}

.kpi-grid > .card, .dash-widgets > .dash-widget, .dash-widget-row > .dash-widget {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity .5s ease, transform .5s ease;
}
.kpi-grid > .card.is-revealed, .dash-widgets > .dash-widget.is-revealed, .dash-widget-row > .dash-widget.is-revealed {
    opacity: 1;
    transform: translateY(0);
}

.bar-chart-fill { transition: width 1s cubic-bezier(.22, .9, .3, 1); }

.bar-chart-row { border-radius: 8px; transition: background .12s ease; }
.bar-chart-row:hover { background: var(--color-surface-alt); }
.bar-chart-row:hover .bar-chart-label { color: var(--color-text); font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
    .kpi-grid > .card, .dash-widgets > .dash-widget, .dash-widget-row > .dash-widget { opacity: 1; transform: none; }
    .kpi-ring-progress, .bar-chart-fill { transition: none; }
    .kpi-card:hover, .dash-widget:hover { transform: none; }
}

/* ---------- Dashboard: wide widgets (tables, pivots, bar charts) ---------- */

.dash-widgets { display: flex; flex-direction: column; gap: 16px; margin-top: 4px; }
.dash-widget .card-header {
    background: linear-gradient(120deg, var(--color-header-dark-alt), var(--color-header-dark));
    color: #fff;
    border-bottom: none;
    position: relative;
}
.dash-widget .card-header::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 3px;
    background: linear-gradient(90deg, var(--color-accent), var(--color-primary));
}
.dash-widget-row { display: grid; grid-template-columns: 1fr; gap: 16px; }
@media (min-width: 1024px) {
    .dash-widget-row { grid-template-columns: repeat(2, 1fr); }
}
.dash-widget-row .dash-widget { margin-bottom: 0; }

/* ---------- Dashboard: collapsible lazy-load widgets ---------- */
/* Table/pivot widgets render collapsed (header only); assets/js/app.js
   fetches and injects the widget's data into .widget-body only the first
   time its header is opened — see initDashboardWidgets(). */

.widget-toggle {
    cursor: pointer;
    user-select: none;
    transition: filter .12s ease;
}
/* Lighten in place with a filter rather than painting a new background —
   .dash-widget .card-header carries its own navy/teal gradient (and white
   text on top of it); a hover background would either paint over the
   gradient or, if translucent, wash out to near-white against the page
   behind it and leave the white heading text unreadable. brightness()
   keeps the gradient (and the text sitting on it) exactly as they are,
   just a touch lighter, so the header never goes white-on-white. */
.widget-toggle:hover,
.widget-toggle:focus-visible {
    filter: brightness(1.16);
}
.widget-toggle:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: -2px;
}

.widget-chevron {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: .8rem;
    line-height: 1;
    flex: 0 0 auto;
    transition: transform .22s ease;
}
.widget-toggle[aria-expanded="true"] .widget-chevron {
    transform: rotate(90deg);
}

.widget-body {
    overflow: hidden;
}
.widget-body[hidden] { display: none; }

.widget-loading {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 30px 4px;
    color: var(--color-text-muted);
    font-size: .88rem;
}
.widget-spinner {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: 2.5px solid var(--color-border);
    border-top-color: var(--color-primary);
    animation: widget-spin .7s linear infinite;
    flex: 0 0 auto;
}
@keyframes widget-spin {
    to { transform: rotate(360deg); }
}
.widget-error {
    color: var(--color-danger, #dc2626);
    padding: 16px 4px;
    font-size: .88rem;
}

@media (prefers-reduced-motion: reduce) {
    .widget-chevron { transition: none; }
    .widget-spinner { animation-duration: 1.4s; }
}

.dash-empty { text-align: center; color: var(--color-text-muted); padding: 38px 16px; }
.dash-empty-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 42px; height: 42px; border-radius: 999px; background: var(--color-surface-alt);
    color: #9ca3af; font-size: 1.1rem; margin-bottom: 10px;
}
.dash-empty-text { text-transform: uppercase; letter-spacing: .04em; font-size: .8rem; font-weight: 600; }

.bar-chart-rows { display: flex; flex-direction: column; gap: 11px; }
.bar-chart-row { display: grid; grid-template-columns: 160px 1fr auto; align-items: center; gap: 10px; font-size: .85rem; }
.bar-chart-label { color: var(--color-text-muted); text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bar-chart-track { background: var(--color-surface-alt); border-radius: 999px; height: 15px; overflow: hidden; }
.bar-chart-fill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--color-primary), var(--color-accent)); }
.bar-chart-value { font-weight: 700; font-variant-numeric: tabular-nums; min-width: 70px; }
.bar-chart-legend { margin-top: 12px; font-size: .8rem; color: var(--color-text-muted); display: flex; align-items: center; gap: 6px; }
.bar-chart-swatch { display: inline-block; width: 12px; height: 12px; border-radius: 3px; background: linear-gradient(90deg, var(--color-primary), var(--color-accent)); }

table.data-grid tfoot td { font-weight: 700; background: var(--color-surface-alt); border-top: 2px solid var(--color-border); }

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

.login-wrap {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    position: relative;
    overflow: hidden;
    background: var(--login-wrap-bg);
    transition: background .25s ease;
}
/* Two slow-drifting glow orbs behind the card — an ambient, living
   background without any extra markup in login.php. Pure decoration, so
   they sit behind everything and never intercept clicks. */
.login-wrap::before,
.login-wrap::after {
    content: "";
    position: absolute;
    width: 46vw;
    height: 46vw;
    max-width: 620px;
    max-height: 620px;
    border-radius: 50%;
    filter: blur(70px);
    opacity: .28;
    pointer-events: none;
    z-index: 0;
}
.login-wrap::before {
    top: -14%;
    left: -10%;
    background: radial-gradient(circle, var(--color-primary), transparent 70%);
    animation: fx-drift-a 16s ease-in-out infinite;
}
.login-wrap::after {
    bottom: -18%;
    right: -8%;
    background: radial-gradient(circle, var(--color-accent), transparent 70%);
    animation: fx-drift-b 19s ease-in-out infinite;
}
@keyframes fx-drift-a {
    0%, 100% { transform: translate(0, 0) scale(1); }
    50% { transform: translate(4%, 5%) scale(1.08); }
}
@keyframes fx-drift-b {
    0%, 100% { transform: translate(0, 0) scale(1); }
    50% { transform: translate(-5%, -4%) scale(1.1); }
}

.login-shell {
    width: 100%;
    max-width: 840px;
    display: grid;
    grid-template-columns: 1fr;
    background: var(--color-surface);
    border-radius: 20px;
    overflow: hidden;
    box-shadow: var(--shadow-lg);
    position: relative;
    z-index: 1;
    animation: fx-pop-in .6s cubic-bezier(.16, .8, .3, 1) both;
}
.login-shell > .theme-toggle {
    position: absolute;
    top: 14px;
    right: 14px;
    z-index: 2;
    background: var(--color-surface);
}
@keyframes fx-shake {
    10%, 90% { transform: translateX(-1px); }
    20%, 80% { transform: translateX(2px); }
    30%, 50%, 70% { transform: translateX(-5px); }
    40%, 60% { transform: translateX(5px); }
}
/* Wrong-password nudge — only the half of the shell holding the form
   shakes, scoped with :has() so it needs no JS and degrades silently
   (shell just sits still) on a browser that lacks it. */
.login-card:has(.flash-error) { animation: fx-shake .5s ease-in-out .1s both; }
@media (min-width: 760px) {
    .login-shell { grid-template-columns: 1.05fr 1fr; }
}

.login-brand-panel {
    display: none;
    position: relative;
    padding: 40px 36px;
    background: var(--login-brand-bg);
    color: var(--login-brand-text);
    flex-direction: column;
    justify-content: space-between;
    overflow: hidden;
    transition: background .25s ease, color .25s ease;
}
@media (min-width: 760px) {
    .login-brand-panel { display: flex; }
}
.login-brand-panel::before {
    /* Faint dotted route/waypoint pattern — evokes a tracked route without
       needing an image asset. Drifts very slowly, like a map panning. */
    content: "";
    position: absolute;
    inset: -22px;
    background-image: radial-gradient(var(--login-dot-color) 1.4px, transparent 1.4px);
    background-size: 22px 22px;
    -webkit-mask-image: radial-gradient(circle at 70% 30%, black, transparent 70%);
    mask-image: radial-gradient(circle at 70% 30%, black, transparent 70%);
    animation: fx-pan-dots 30s linear infinite;
}
@keyframes fx-pan-dots {
    from { background-position: 0 0; }
    to { background-position: 22px 22px; }
}
.login-brand-mark {
    position: relative;
    display: flex;
    align-items: center;
    gap: 12px;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.3rem;
}
.login-brand-mark .mark {
    width: 40px; height: 40px; border-radius: 11px;
    background: linear-gradient(135deg, var(--color-accent), var(--color-primary) 130%);
    box-shadow: 0 6px 18px rgba(240, 134, 43, .4);
    animation: fx-glow-pulse 3.2s ease-in-out infinite;
    display: inline-block;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 16.5V7a1 1 0 0 1 1-1h9v10.5'/%3E%3Cpath d='M13 9.5h4.2a1 1 0 0 1 .85.47l2.2 3.53a1 1 0 0 1 .15.53V16a.5.5 0 0 1-.5.5H19'/%3E%3Ccircle cx='7' cy='17' r='2'/%3E%3Ccircle cx='17' cy='17' r='2'/%3E%3C/svg%3E") center / 58% no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2.1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 16.5V7a1 1 0 0 1 1-1h9v10.5'/%3E%3Cpath d='M13 9.5h4.2a1 1 0 0 1 .85.47l2.2 3.53a1 1 0 0 1 .15.53V16a.5.5 0 0 1-.5.5H19'/%3E%3Ccircle cx='7' cy='17' r='2'/%3E%3Ccircle cx='17' cy='17' r='2'/%3E%3C/svg%3E") center / 58% no-repeat;
}
@keyframes fx-glow-pulse {
    0%, 100% { box-shadow: 0 6px 18px rgba(240, 134, 43, .4); }
    50% { box-shadow: 0 6px 26px rgba(240, 134, 43, .7); }
}
.login-brand-tagline {
    position: relative;
    margin-top: 16px;
    font-size: .92rem;
    line-height: 1.6;
    color: var(--color-sidebar-text);
    max-width: 30ch;
}
.login-brand-stats {
    position: relative;
    display: flex;
    gap: 26px;
    margin-top: auto;
    padding-top: 30px;
}
.login-brand-stats div {
    display: flex;
    flex-direction: column;
    animation: fx-fade-up .5s cubic-bezier(.16, .8, .3, 1) both;
}
.login-brand-stats div:nth-child(1) { animation-delay: .35s; }
.login-brand-stats div:nth-child(2) { animation-delay: .43s; }
.login-brand-stats div:nth-child(3) { animation-delay: .51s; }
.login-brand-stats strong { font-family: var(--font-display); font-size: 1.3rem; font-weight: 800; }
.login-brand-stats span { font-size: .72rem; color: var(--color-sidebar-text); text-transform: uppercase; letter-spacing: .05em; margin-top: 2px; }

.login-card {
    background: var(--color-surface);
    padding: 40px 36px;
    width: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
}
.login-card h1 { text-align: left; margin-bottom: 4px; font-size: 1.4rem; }
.login-card p.sub { text-align: left; color: var(--color-text-muted); margin: 0 0 26px; font-size: .89rem; }
.login-card .field { margin-bottom: 16px; }
.login-card .btn-primary { width: 100%; justify-content: center; padding: 11px; font-size: .92rem; }

/* ---------- Misc ---------- */

.text-muted { color: var(--color-text-muted); }
.mb-0 { margin-bottom: 0; }
.help-text { font-size: .78rem; color: var(--color-text-muted); }
.required::after { content: " *"; color: var(--color-danger); }

/* ---------- Print ---------- */
/* Shared by every module's "Print" button (window.print()) — one place
   this lives instead of a per-module print stylesheet. Hides navigation
   chrome and action buttons, leaving just the record itself. */
@media print {
    .sidebar, .sidebar-backdrop, .topbar, .flash, .form-actions, .grid-toolbar, .pagination { display: none !important; }
    .content { margin: 0 !important; padding: 0 !important; }
    body { background: #fff !important; }
    a[href]::after { content: none !important; }
}
