/* ============================================================================
   kmp-ui.css — the Keystone console design system
   ----------------------------------------------------------------------------
   Loaded LAST, after the legacy stylesheets, so it supersedes them without any
   of the forty-odd pages being rewritten.

   DESIGN READ
   -----------
   An internal lending console for cooperative staff who sit in it all day,
   reading dense financial tables. Trust-first, regulated, data-dense. So:
   restrained motion, one accent, real density — and every decision earning its
   place by fixing something, not by looking new.

   WHAT WAS WRONG WITH THE OLD LAYER, AND WHAT REPLACED IT
   -------------------------------------------------------
   · Blue→navy gradient sidebar        -> flat navy. A gradient behind fifteen
                                          nav items fights the active state and
                                          is the most obvious "generated" tell.
   · Six accent colours, no system     -> one accent, desaturated. Status
                                          colours are semantic only.
   · Pure-black shadows on a blue page -> shadows tinted with the page's own
                                          hue, so they read as shade not soot.
   · Border + shadow + white on every  -> elevation only where hierarchy needs
     card                                 it; a hairline otherwise.
   · Four identical KPI tiles          -> a bento: the figure that matters is
                                          bigger than the ones that don't.
   · Proportional digits in money      -> tabular figures. Columns line up.
   · Flat sterile surfaces             -> a barely-there grain, so large fields
                                          of colour are not dead.
   · Sideways scroll under ~1000px     -> the shell sizes against its parent.
   · Colour carrying meaning alone     -> every pill has a word and a shape.
   · No dark mode                      -> both themes, tested independently.

   THE BRAND STAYS. The cooperative's blue and navy are theirs and people
   recognise their own system; what changed is that the blue is now a ramp with
   steps chosen for contrast rather than one hex reused at every weight.
   ========================================================================== */

/* IBM Plex Sans, for one concrete reason: it ships true tabular figures, so a
   column of pesos aligns on the decimal. font-display:swap so a slow line in
   Koronadal never blanks the interface. */
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;450;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap');

/* ==========================================================================
   1. TOKENS
   ========================================================================== */

:root {
    /* --- The accent. One. Built from the cooperative's #3498db, pulled down
           in saturation so it sits with the neutrals instead of shouting. --- */
    --k-a-50:  #eef6fc;
    --k-a-100: #d8eaf7;
    --k-a-200: #b4d6ef;
    --k-a-300: #83bbe2;
    --k-a-400: #519dd1;
    --k-a-500: #3182bd;
    --k-a-600: #2669a0;
    --k-a-700: #1f5482;   /* 4.5:1 on white — text, links, primary buttons */
    --k-a-800: #1c4569;
    --k-a-900: #1a3a58;

    /* --- Navy. The chrome. --- */
    --k-n-600: #2c3e50;
    --k-n-700: #243444;
    --k-n-800: #1c2938;
    --k-n-850: #17222f;
    --k-n-900: #111a24;
    --k-n-950: #0b1119;

    /* --- Greys, all cooled to the same hue as the navy. Mixing a warm grey
           with a cool one is the thing that makes an interface feel muddy. --- */
    --k-g-50:  #f6f8fa;
    --k-g-100: #eef1f5;
    --k-g-200: #e1e6ed;
    --k-g-300: #cbd3dd;
    --k-g-400: #97a3b2;
    --k-g-500: #6b7887;
    --k-g-600: #4d5967;
    --k-g-700: #3a444f;
    --k-g-800: #262e37;
    --k-g-900: #161c23;

    /* --- Status. Desaturated to live beside the accent, never above 72% S. --- */
    --k-ok-50:   #edf7f0;  --k-ok-500:   #3d9c63;  --k-ok-700:   #2b7048;
    --k-warn-50: #fdf5e8;  --k-warn-500: #c98a1e;  --k-warn-700: #96660f;
    --k-bad-50:  #fdf0ef;  --k-bad-500:  #cf5140;  --k-bad-700:  #a33628;

    /* --- Semantic. Pages use these; never the ramps above. --- */
    --k-bg:          var(--k-g-100);
    --k-surface:     #ffffff;
    --k-surface-2:   var(--k-g-50);
    --k-surface-3:   var(--k-g-100);
    --k-hairline:    var(--k-g-200);
    --k-line:        var(--k-g-300);
    --k-ink:         var(--k-g-800);
    --k-ink-strong:  var(--k-g-900);
    /* g-600, not g-500. On white g-500 clears 4.5:1, but almost nothing muted
       sits on white — it sits on a card, a table stripe or a raised panel, and
       there it measured 4.22-4.23:1 across 133 elements. One step darker holds
       everywhere: 6.71:1 on --k-surface-2. */
    --k-ink-muted:   var(--k-g-600);
    --k-ink-invert:  #ffffff;

    --k-accent:      var(--k-a-500);
    --k-accent-ink:  var(--k-a-700);
    --k-accent-wash: var(--k-a-50);

    --k-ok:   var(--k-ok-700);   --k-ok-wash:   var(--k-ok-50);
    --k-warn: var(--k-warn-700); --k-warn-wash: var(--k-warn-50);
    --k-bad:  var(--k-bad-700);  --k-bad-wash:  var(--k-bad-50);
    --k-mute: var(--k-g-600);    --k-mute-wash: var(--k-g-100);

    --k-focus: var(--k-a-500);

    /* --- Chrome (the sidebar) is dark in both themes: it is furniture, and
           inverting it every time the theme changes is disorienting. --- */
    --k-chrome:        var(--k-n-800);
    --k-chrome-edge:   rgba(255, 255, 255, .07);
    --k-chrome-ink:    rgba(255, 255, 255, .74);
    --k-chrome-ink-hi: #ffffff;
    --k-chrome-hover:  rgba(255, 255, 255, .07);
    --k-chrome-active: rgba(255, 255, 255, .11);

    /* --- Shadows carry the page's hue. A pure-black shadow on a blue-grey
           background reads as dirt; a tinted one reads as depth. --- */
    --k-shadow-1: 0 1px 2px rgba(28, 41, 56, .07);
    --k-shadow-2: 0 1px 2px rgba(28, 41, 56, .05), 0 4px 12px rgba(28, 41, 56, .07);
    --k-shadow-3: 0 2px 4px rgba(28, 41, 56, .05), 0 12px 28px rgba(28, 41, 56, .11);
    --k-shadow-4: 0 24px 60px rgba(17, 26, 36, .22);

    /* --- Type --- */
    --k-font: 'IBM Plex Sans', ui-sans-serif, -apple-system, BlinkMacSystemFont,
              'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    --k-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

    --k-t-2xs: .6875rem;  /* 11 */
    --k-t-xs:  .75rem;    /* 12 */
    --k-t-sm:  .8125rem;  /* 13 */
    --k-t-md:  .875rem;   /* 14 — body. This is a console, not an article. */
    --k-t-lg:  1rem;      /* 16 */
    --k-t-xl:  1.25rem;   /* 20 */
    --k-t-2xl: 1.5rem;    /* 24 */
    --k-t-3xl: 1.9375rem; /* 31 */

    /* --- Space. A 4px rhythm, dense end of the scale. --- */
    --k-1: 4px;  --k-2: 8px;  --k-3: 12px; --k-4: 16px;
    --k-5: 20px; --k-6: 24px; --k-8: 32px; --k-10: 40px; --k-12: 48px;

    /* --- Shape. Varied deliberately: containers softer than the things
           inside them, which is how physical nesting actually looks. --- */
    --k-r-xs:   4px;
    --k-r-sm:   6px;
    --k-r:      10px;
    --k-r-lg:   14px;
    --k-r-pill: 999px;

    /* --- Motion. One rhythm for the whole product. --- */
    --k-fast: 110ms;
    --k-mid:  190ms;
    --k-slow: 300ms;
    --k-ease:     cubic-bezier(.2, .8, .3, 1);    /* entering */
    --k-ease-out: cubic-bezier(.5, 0, .75, 0);    /* leaving — faster */

    /* --- Layout --- */
    --k-rail:      252px;
    --k-rail-thin: 64px;
    --k-max:       1720px;
    --k-gutter:    clamp(14px, 2vw, 32px);

    --z-sticky: 20; --z-header: 40; --z-drawer: 60; --z-modal: 100; --z-toast: 1000;

    color-scheme: light;
}

/* --- Dark. Surfaces get LIGHTER as they rise, which is how elevation reads
       in the dark; inverting the light palette does not work. --- */
:root[data-theme="dark"] {
    --k-bg:         var(--k-n-950);
    --k-surface:    var(--k-n-850);
    --k-surface-2:  var(--k-n-900);
    --k-surface-3:  var(--k-n-800);
    --k-hairline:   #24313f;
    --k-line:       #33445608;
    --k-line:       #334456;
    --k-ink:        #dbe3ec;
    --k-ink-strong: #f4f7fa;
    --k-ink-muted:  #8b9aac;

    --k-accent:      var(--k-a-400);
    --k-accent-ink:  var(--k-a-300);
    --k-accent-wash: rgba(81, 157, 209, .13);

    --k-ok:   #5cba7d;  --k-ok-wash:   rgba(61, 156, 99, .14);
    --k-warn: #dda52f;  --k-warn-wash: rgba(201, 138, 30, .14);
    --k-bad:  #e4705f;  --k-bad-wash:  rgba(207, 81, 64, .14);
    --k-mute: #9fadbd;  --k-mute-wash: rgba(107, 120, 135, .14);

    --k-focus: var(--k-a-400);

    --k-chrome: var(--k-n-900);

    --k-shadow-1: 0 1px 2px rgba(0, 0, 0, .45);
    --k-shadow-2: 0 2px 8px rgba(0, 0, 0, .45);
    --k-shadow-3: 0 12px 30px rgba(0, 0, 0, .55);
    --k-shadow-4: 0 28px 70px rgba(0, 0, 0, .65);

    color-scheme: dark;
}

/* Follow the operating system until someone chooses for themselves. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --k-bg: var(--k-n-950);
        --k-surface: var(--k-n-850);
        --k-surface-2: var(--k-n-900);
        --k-surface-3: var(--k-n-800);
        --k-hairline: #24313f;
        --k-line: #334456;
        --k-ink: #dbe3ec;
        --k-ink-strong: #f4f7fa;
        --k-ink-muted: #8b9aac;
        --k-accent: var(--k-a-400);
        --k-accent-ink: var(--k-a-300);
        --k-accent-wash: rgba(81, 157, 209, .13);
        --k-ok: #5cba7d;  --k-ok-wash: rgba(61, 156, 99, .14);
        --k-warn: #dda52f; --k-warn-wash: rgba(201, 138, 30, .14);
        --k-bad: #e4705f; --k-bad-wash: rgba(207, 81, 64, .14);
        --k-mute: #9fadbd; --k-mute-wash: rgba(107, 120, 135, .14);
        --k-focus: var(--k-a-400);
        --k-chrome: var(--k-n-900);
        --k-shadow-1: 0 1px 2px rgba(0, 0, 0, .45);
        --k-shadow-2: 0 2px 8px rgba(0, 0, 0, .45);
        --k-shadow-3: 0 12px 30px rgba(0, 0, 0, .55);
        --k-shadow-4: 0 28px 70px rgba(0, 0, 0, .65);
        color-scheme: dark;
    }
}

/* ==========================================================================
   2. BASE
   ========================================================================== */

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* The legacy sheets set font-family on the universal selector and again on
   individual components, so inheriting from body never reaches them. */
body, button, input, select, textarea, table,
h1, h2, h3, h4, h5, h6, p, span, div, td, th, a, label, li {
    font-family: var(--k-font) !important;
}

body {
    font-family: var(--k-font) !important;
    font-size: var(--k-t-md);
    line-height: 1.55;
    color: var(--k-ink);
    background-color: var(--k-bg) !important;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;   /* wide tables scroll inside their own wrapper */
}

/* A grain so faint you would not name it, but a large field of one colour is
   dead without it. Fixed, so it does not swim when the page scrolls. */
body::after {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    opacity: .022;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
:root[data-theme="dark"] body::after { opacity: .035; }
@media print { body::after { display: none; } }

h1, h2, h3, h4 {
    color: var(--k-ink-strong);
    letter-spacing: -.015em;
    text-wrap: balance;      /* no single word orphaned on the last line */
    font-weight: 600;
}
p { text-wrap: pretty; }

a { color: var(--k-accent-ink); text-underline-offset: 2px; }
a:hover { color: var(--k-a-800); }
:root[data-theme="dark"] a:hover { color: var(--k-a-200); }

/* Money, dates, counts, IDs. Fixed-width digits so columns align and a
   changing value cannot shift the layout. The single highest-value rule here. */
.kmp-num, .kmp-table td.kmp-num, .kmp-table th.kmp-num,
.stat-card .num, .stat-value, .num, .k-money, .k-tabular,
td[class*="num"], .dt-chip {
    font-variant-numeric: tabular-nums lining-nums;
    font-feature-settings: "tnum" 1, "lnum" 1;
}

:where(a, button, input, select, textarea, [tabindex], summary):focus-visible {
    outline: 2px solid var(--k-focus);
    outline-offset: 2px;
    border-radius: var(--k-r-xs);
}

::selection { background: var(--k-a-200); color: var(--k-n-900); }
:root[data-theme="dark"] ::selection { background: var(--k-a-800); color: #fff; }

* { scrollbar-width: thin; scrollbar-color: var(--k-line) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
    background: var(--k-line);
    border-radius: var(--k-r-pill);
    border: 3px solid transparent;
    background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover { background-color: var(--k-g-400); background-clip: content-box; }

/* ==========================================================================
   3. SHELL
   --------------------------------------------------------------------------
   The old rule sized the content box against the VIEWPORT while a 250px
   sidebar sat beside it, so under about 1000px the two together exceeded the
   window and the whole page scrolled sideways. Sizing against the parent fixes
   it at every width.
   ========================================================================== */

.dashboard-container { min-height: 100dvh; }   /* not 100vh: iOS Safari jumps */

/* WIDTH: 100%, NOT AUTO
   ----------------------------------------------------------------------------
   `.main-content` is `display: flex; flex-direction: column`, so everything in
   it is a flex item. In a column flex container the horizontal size of an item
   comes from `align-items: stretch` — EXCEPT that a pair of auto inline margins
   cancels the stretch, and the item falls back to shrink-to-fit.

   `margin-inline: auto` is there to centre the container once it hits its
   max-width. Together with `width: auto` it meant the page never reached the
   max-width at all: on a maximised 1920px window the content sized itself to
   1191px inside a 1657px column, leaving 233px of dead space down each side and
   squeezing four KPI cards into 272px each — narrow enough to clip
   "₱10,950,683.61" to "₱10,950,683.6".

   `width: 100%` restores the stretch. The max-width still caps it and the auto
   margins still centre it on a very wide screen; they just no longer decide the
   width on a normal one. Same 1920px window now gives 1657px of content and
   389px cards. */
:where(body > .shell, body > .container, body > .container-box, body > .cal-shell),
.main-content > :where(.shell, .container, .container-box, .cal-shell),
.dashboard-content {
    width: 100% !important;
    max-width: var(--k-max) !important;
    margin-inline: auto;
    padding-inline: var(--k-gutter);
    box-sizing: border-box;
}

.main-content {
    min-width: 0;                /* lets the flex child actually shrink */
    background: var(--k-bg);
    position: relative;
    z-index: 2;
}
.dashboard-content { padding-block: var(--k-5) var(--k-12); }

/* --- Sidebar ------------------------------------------------------------ */

.sidebar {
    width: var(--k-rail);
    flex: 0 0 var(--k-rail);
    /* Flat. The gradient it replaced fought every active state drawn on it. */
    background: var(--k-chrome) !important;
    border-right: 1px solid var(--k-chrome-edge);
    box-shadow: none;
    padding: var(--k-3) 0 var(--k-6) !important;
    transition: width var(--k-mid) var(--k-ease), flex-basis var(--k-mid) var(--k-ease);
    overflow-x: hidden;
    overflow-y: auto;
    position: relative;
    z-index: 3;
}

.sidebar-KMPLOGO, .sidebar-header {
    display: flex; align-items: center; gap: var(--k-2);
    padding: var(--k-2) var(--k-4) var(--k-4) !important;
    border-bottom: 1px solid var(--k-chrome-edge);
    margin-bottom: var(--k-3) !important;
    min-width: 0;
}
.sidebar-KMPLOGO img { flex: 0 0 auto; border-radius: var(--k-r-sm) !important; margin-right: 0 !important; }
.sidebar-KMPLOGO span {
    font-size: var(--k-t-sm) !important;
    font-weight: 600 !important;
    line-height: 1.25;
    letter-spacing: -.005em;
    /* Was 20px bold and wrapped over the logo at any narrow width. */
    min-width: 0;
}

.user-info {
    display: flex; align-items: center; gap: var(--k-2);
    padding: var(--k-2) var(--k-4) var(--k-4) !important;
    margin-bottom: var(--k-2) !important;
    min-width: 0;
}
.user-avatar {
    flex: 0 0 34px; width: 34px; height: 34px;
    display: grid; place-items: center;
    /* A squircle, not a circle: an avatar ring on every product is a tell. */
    border-radius: var(--k-r-sm);
    background: var(--k-chrome-active);
    color: #fff;
}
.user-details h3 { font-size: var(--k-t-sm); color: #fff; margin: 0; font-weight: 550; }
.user-details p  { font-size: var(--k-t-2xs); color: var(--k-chrome-ink); margin: 0; text-transform: capitalize; }

.sidebar-menu { list-style: none; padding: 0 var(--k-2); margin: 0; }
.sidebar-menu li { margin: 0; }

.sidebar-menu a {
    display: flex; align-items: center; gap: var(--k-3);
    border-radius: var(--k-r-sm);
    margin: 1px 0;
    padding: 8px var(--k-3) !important;
    font-size: var(--k-t-sm);
    font-weight: 450;
    color: var(--k-chrome-ink) !important;
    text-decoration: none;
    white-space: nowrap;
    position: relative;
    border-left: 0 !important;
    transition: background-color var(--k-fast) var(--k-ease), color var(--k-fast) var(--k-ease);
}
.sidebar-menu a i { width: 17px; flex: 0 0 17px; text-align: center; font-size: 14px; opacity: .85; }
.sidebar-menu a span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

.sidebar-menu a:hover {
    background: var(--k-chrome-hover) !important;
    color: var(--k-chrome-ink-hi) !important;
    transform: none;             /* a list that shifts under the pointer feels loose */
}
/* The current page gets a rail and full-strength ink, not just a tint —
   a tint alone disappears against the chrome. */
.sidebar-menu a.active {
    background: var(--k-chrome-active) !important;
    color: var(--k-chrome-ink-hi) !important;
    font-weight: 600;
}
.sidebar-menu a.active::before {
    content: "";
    position: absolute; left: -8px; top: 50%;
    width: 3px; height: 17px;
    background: var(--k-a-400);
    border-radius: 0 3px 3px 0;
    transform: translateY(-50%);
}
.sidebar-menu a.active i { opacity: 1; color: var(--k-a-300); }

/* Collapsed rail: icons with the label as a tooltip, so nothing is a guess. */
body.k-rail .sidebar { width: var(--k-rail-thin); flex-basis: var(--k-rail-thin); }
body.k-rail .sidebar .sidebar-menu a { justify-content: center; padding-inline: 0 !important; gap: 0; }
body.k-rail .sidebar .sidebar-menu a span,
body.k-rail .sidebar .sidebar-menu a .arrow,
body.k-rail .sidebar-KMPLOGO span,
body.k-rail .user-details { display: none; }
body.k-rail .sidebar-KMPLOGO, body.k-rail .user-info { justify-content: center; padding-inline: 0 !important; }

body.k-rail .sidebar-menu a[data-label]:hover::after {
    content: attr(data-label);
    position: absolute; left: calc(100% + 8px); top: 50%;
    transform: translateY(-50%);
    background: var(--k-n-950); color: #fff;
    padding: 6px 10px; border-radius: var(--k-r-sm);
    font-size: var(--k-t-xs); font-weight: 500; white-space: nowrap;
    box-shadow: var(--k-shadow-3); z-index: var(--z-drawer); pointer-events: none;
}

/* --- Header ------------------------------------------------------------- */

.top-header {
    display: flex; align-items: center; gap: var(--k-3);
    justify-content: space-between !important;
    padding: var(--k-2) var(--k-gutter) !important;
    min-height: 56px;
    background: color-mix(in srgb, var(--k-surface) 86%, transparent) !important;
    backdrop-filter: saturate(180%) blur(10px);
    -webkit-backdrop-filter: saturate(180%) blur(10px);
    border-bottom: 1px solid var(--k-hairline);
    border-radius: 0 !important;
    box-shadow: none !important;
    position: sticky; top: 0; z-index: var(--z-header);
}

/* The clock was absolutely positioned and sat on top of the brand at narrow
   widths. It is a header item like any other now. */
.live-clock {
    position: static !important;
    display: inline-flex; align-items: center; gap: var(--k-2);
    padding: 5px var(--k-3);
    background: var(--k-surface-2) !important;
    border: 1px solid var(--k-hairline);
    border-radius: var(--k-r-sm);
    color: var(--k-ink) !important;
    font-size: var(--k-t-xs);
    box-shadow: none !important;
    flex: 0 1 auto; min-width: 0;
}
.live-clock i { color: var(--k-ink-muted); }
.lc-text { display: flex; flex-direction: column; line-height: 1.2; min-width: 0; }
.lc-time { font-weight: 600; font-variant-numeric: tabular-nums; color: var(--k-ink-strong); }
.lc-date { color: var(--k-ink-muted); font-size: var(--k-t-2xs); }

.header-actions { display: flex; align-items: center; gap: var(--k-2); }
.header-actions .calendar, .header-actions .notification-btn {
    width: 34px; height: 34px;
    display: grid; place-items: center;
    border-radius: var(--k-r-sm);
    color: var(--k-ink-muted);
    cursor: pointer;
    transition: background-color var(--k-fast) var(--k-ease), color var(--k-fast) var(--k-ease);
}
.header-actions .calendar:hover, .header-actions .notification-btn:hover {
    background: var(--k-surface-3); color: var(--k-accent-ink);
}
.user-menu { display: flex; align-items: center; gap: var(--k-2); font-size: var(--k-t-sm); font-weight: 500; }
.user-menu img { width: 28px; height: 28px; border-radius: var(--k-r-sm); }

.page-title {
    font-size: var(--k-t-2xl) !important;
    font-weight: 600 !important;
    letter-spacing: -.02em;
    color: var(--k-ink-strong);
    margin: 0 0 var(--k-4) !important;
}

/* ==========================================================================
   4. SURFACES
   --------------------------------------------------------------------------
   Not border + shadow + white on everything. A hairline by default; elevation
   only where something genuinely floats above the page.
   ========================================================================== */

.stat-card, .kmp-card, .card, .panel {
    background: var(--k-surface) !important;
    border: 1px solid var(--k-hairline) !important;
    border-radius: var(--k-r) !important;
    box-shadow: none !important;
    color: var(--k-ink);
    transition: border-color var(--k-mid) var(--k-ease),
                box-shadow var(--k-mid) var(--k-ease),
                transform var(--k-mid) var(--k-ease);
}
.stat-card:hover, .kmp-card:hover {
    border-color: var(--k-line) !important;
    box-shadow: var(--k-shadow-2) !important;
}

/* --- The bento. The figure that matters is bigger than the ones that do not,
       instead of four identical tiles in a row. --------------------------- */
.stats-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(212px, 100%), 1fr));
    gap: var(--k-3) !important;
    margin-bottom: var(--k-4) !important;
    align-items: stretch;
}
/* An even grid. These nine figures are equally important to the officer
   reading them, and a bento that made one of them big would be inventing a
   hierarchy the data does not have. */
@media (min-width: 1240px) {
    .stats-cards { grid-template-columns: repeat(auto-fit, minmax(min(236px, 100%), 1fr)); }
}

.stat-card {
    display: flex; align-items: center; gap: var(--k-3);
    padding: var(--k-4) !important;
    min-width: 0;
    /* The old cards carried a coloured left border in one of six arbitrary
       hues. One hairline, and the meaning lives in the icon tone below. */
    border-left-width: 1px !important;
    border-left-color: var(--k-hairline) !important;
}

/* A long peso figure must be allowed to shrink rather than escape the card.
   Without min-width:0 a flex child refuses to go below its content width and
   "₱1,754,993.34" is simply clipped. */
.stat-card > *:not(.stat-icon):not(i) { min-width: 0; flex: 1 1 auto; }
.stat-details { min-width: 0; }
.stat-card .num, .stat-card h3, .stat-value, .stat-details h3 {
    min-width: 0;
    /* Never break inside a figure: "₱2,376,907.5 / 7" is worse than clipping.
       The size flexes with the viewport instead, so the whole amount fits. */
    white-space: nowrap;
    overflow-wrap: normal;
    font-size: clamp(1rem, .55rem + 1.05vw, 1.5rem) !important;
    letter-spacing: -.025em;
    line-height: 1.2;
}
.stat-card .lbl, .stat-card p, .stat-label { overflow-wrap: anywhere; }

/* --- Icon tones. Four, each meaning something. -------------------------- */
.stat-icon.k-tone-accent { background: var(--k-accent-wash) !important; color: var(--k-accent-ink) !important; }
.stat-icon.k-tone-ok     { background: var(--k-ok-wash) !important;     color: var(--k-ok) !important; }
.stat-icon.k-tone-warn   { background: var(--k-warn-wash) !important;   color: var(--k-warn) !important; }
.stat-icon.k-tone-bad    { background: var(--k-bad-wash) !important;    color: var(--k-bad) !important; }
.stat-icon.k-tone-mute   { background: var(--k-mute-wash) !important;   color: var(--k-mute) !important; }

/* The legacy accent classes painted the card's left edge; neutralised so the
   icon tone is the only colour signal. */
.stat-card[class*="kmp-accent"] { border-left-color: var(--k-hairline) !important; }
.stat-card .stat-icon, .stat-card > i, .stat-card .icon {
    flex: 0 0 38px; width: 38px; height: 38px;
    display: grid; place-items: center;
    border-radius: var(--k-r-sm);
    background: var(--k-accent-wash);
    color: var(--k-accent-ink);
    font-size: 15px;
}
.stat-card .num, .stat-card h3, .stat-value {
    font-size: var(--k-t-2xl);
    font-weight: 600;
    letter-spacing: -.025em;
    color: var(--k-ink-strong);
    line-height: 1.15;
    margin: 0;
}
.stat-card .lbl, .stat-card p, .stat-label {
    font-size: var(--k-t-xs);
    color: var(--k-ink-muted);
    margin: 2px 0 0;
    font-weight: 450;
    /* Sentence case, not SHOUTING CAPS ON EVERY LABEL. */
    text-transform: none;
    letter-spacing: 0;
}

/* --- Due today strip ---------------------------------------------------- */
.due-today-card {
    background: var(--k-surface) !important;
    border: 1px solid var(--k-hairline) !important;
    border-left: 3px solid var(--k-warn-500) !important;
    border-radius: var(--k-r) !important;
    padding: var(--k-3) var(--k-4) !important;
    margin-bottom: var(--k-3) !important;
}
.dt-row { display: flex; align-items: center; gap: var(--k-3); flex-wrap: wrap; }
.dt-head { font-weight: 600; font-size: var(--k-t-sm); color: var(--k-ink-strong); }
.dt-date { color: var(--k-ink-muted); font-weight: 400; }
.due-badge {
    display: inline-grid; place-items: center;
    min-width: 22px; height: 22px; padding: 0 6px;
    border-radius: var(--k-r-pill);
    background: var(--k-warn-wash); color: var(--k-warn);
    font-size: var(--k-t-xs); font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.dt-names { display: flex; gap: var(--k-1); flex-wrap: wrap; min-width: 0; }
.dt-chip {
    display: inline-block;
    padding: 2px 8px;
    border-radius: var(--k-r-xs);
    background: var(--k-surface-3);
    border: 1px solid var(--k-hairline);
    color: var(--k-ink);
    font-size: var(--k-t-xs);
    text-decoration: none;
    transition: background-color var(--k-fast) var(--k-ease), border-color var(--k-fast) var(--k-ease);
}
.dt-chip:hover { background: var(--k-accent-wash); border-color: var(--k-accent); color: var(--k-accent-ink); }

/* ==========================================================================
   5. STATUS
   --------------------------------------------------------------------------
   Square-ish, not pills — a pill badge on every product is a tell — and each
   carries a word. About one man in twelve cannot separate the red from the
   green, so colour is never the only channel.
   ========================================================================== */

.kmp-badge {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 2px 8px;
    border-radius: var(--k-r-xs);
    font-size: var(--k-t-xs);
    font-weight: 550;
    line-height: 1.6;
    white-space: nowrap;
    border: 1px solid transparent;
}
.kmp-badge::before {
    content: ""; width: 5px; height: 5px; flex: 0 0 5px;
    border-radius: 1px; background: currentColor;
}
.kmp-badge-success { color: var(--k-ok);   background: var(--k-ok-wash);   border-color: color-mix(in srgb, var(--k-ok) 24%, transparent); }
.kmp-badge-warning { color: var(--k-warn); background: var(--k-warn-wash); border-color: color-mix(in srgb, var(--k-warn) 24%, transparent); }
.kmp-badge-danger  { color: var(--k-bad);  background: var(--k-bad-wash);  border-color: color-mix(in srgb, var(--k-bad) 24%, transparent); }
.kmp-badge-info    { color: var(--k-accent-ink); background: var(--k-accent-wash); border-color: color-mix(in srgb, var(--k-accent) 24%, transparent); }
.kmp-badge-muted   { color: var(--k-mute); background: var(--k-mute-wash); border-color: var(--k-hairline); }

/* ==========================================================================
   6. TABLES
   ========================================================================== */

.kmp-table-wrap, .table-wrap, .table-responsive {
    overflow-x: auto;            /* the only sanctioned sideways scroll */
    border: 1px solid var(--k-hairline);
    border-radius: var(--k-r);
    background: var(--k-surface);
    -webkit-overflow-scrolling: touch;
}

.kmp-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--k-t-sm);
    background: var(--k-surface);
    color: var(--k-ink);
}

.kmp-table thead th {
    position: sticky; top: 0; z-index: var(--z-sticky);
    background: var(--k-surface-2);
    color: var(--k-ink-muted);
    font-size: var(--k-t-2xs);
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    text-align: left;
    padding: 9px var(--k-3);
    border-bottom: 1px solid var(--k-hairline);
    white-space: nowrap;
}

.kmp-table tbody td {
    padding: 9px var(--k-3);
    border-bottom: 1px solid var(--k-hairline);
    vertical-align: middle;
}
.kmp-table tbody tr:last-child td { border-bottom: 0; }

/* Hover, not zebra: stripes compete with the status colours that carry the
   actual meaning in these tables. */
.kmp-table tbody tr { transition: background-color var(--k-fast) var(--k-ease); }
.kmp-table tbody tr:hover { background: var(--k-accent-wash); }

.kmp-table .kmp-num, .kmp-table td.kmp-num, .kmp-table th.kmp-num {
    text-align: right;
    font-variant-numeric: tabular-nums lining-nums;
    white-space: nowrap;
}

.kmp-table th[data-sort], .kmp-table th.sortable { cursor: pointer; user-select: none; }
.kmp-table th[data-sort]:hover { color: var(--k-ink); }
.kmp-table th[aria-sort="ascending"]::after  { content: " ↑"; color: var(--k-accent-ink); }
.kmp-table th[aria-sort="descending"]::after { content: " ↓"; color: var(--k-accent-ink); }

/* --- Empty state: composed, not a blank cell. --- */
.kmp-empty {
    text-align: center;
    padding: var(--k-12) var(--k-4) !important;
    color: var(--k-ink-muted);
    font-size: var(--k-t-sm);
}
.kmp-empty i {
    display: block; font-size: 22px; margin-bottom: var(--k-2);
    color: var(--k-g-400); opacity: .8;
}

/* ==========================================================================
   7. CONTROLS
   ========================================================================== */

.kmp-btn, .btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    min-height: 34px;
    padding: 6px 13px;
    border: 1px solid transparent;
    border-radius: var(--k-r-sm);
    font-family: inherit;
    font-size: var(--k-t-sm);
    font-weight: 550;
    line-height: 1.4;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
    transition: background-color var(--k-fast) var(--k-ease),
                border-color var(--k-fast) var(--k-ease),
                color var(--k-fast) var(--k-ease),
                transform var(--k-fast) var(--k-ease);
}
@media (pointer: coarse) { .kmp-btn, .btn { min-height: 44px; padding-inline: var(--k-4); } }

.kmp-btn:active:not(:disabled) { transform: translateY(1px); }
.kmp-btn:disabled, .kmp-btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; transform: none; }

.kmp-btn-primary { background: var(--k-accent-ink); border-color: var(--k-accent-ink); color: #fff; }
.kmp-btn-primary:hover:not(:disabled) { background: var(--k-a-800); border-color: var(--k-a-800); color: #fff; }
/* a-600, not a-500: white on #3182bd is 4.15:1, just under. #2669a0 is 5.82:1
   and still reads as the accent against a dark surface. */
:root[data-theme="dark"] .kmp-btn-primary { background: var(--k-a-600); border-color: var(--k-a-600); color: #fff; }
:root[data-theme="dark"] .kmp-btn-primary:hover:not(:disabled) { background: var(--k-a-500); border-color: var(--k-a-500); }

.kmp-btn-ghost { background: var(--k-surface); border-color: var(--k-line); color: var(--k-ink); }
.kmp-btn-ghost:hover:not(:disabled) { background: var(--k-surface-2); border-color: var(--k-g-400); }

/* A third, quieter tier, so a toolbar is not two competing buttons. */
.kmp-btn-quiet { background: transparent; border-color: transparent; color: var(--k-ink-muted); }
.kmp-btn-quiet:hover:not(:disabled) { background: var(--k-surface-3); color: var(--k-ink); }

.kmp-btn-danger { background: var(--k-bad); border-color: var(--k-bad); color: #fff; }
.kmp-btn-danger:hover:not(:disabled) { filter: brightness(.92); }

.kmp-btn-sm { min-height: 28px; padding: 3px 9px; font-size: var(--k-t-xs); }
@media (pointer: coarse) { .kmp-btn-sm { min-height: 40px; } }

/* --- Inputs ------------------------------------------------------------- */

input:where([type="text"], [type="number"], [type="date"], [type="email"],
            [type="password"], [type="search"], [type="tel"], [type="url"]),
select, textarea {
    width: 100%;
    font-family: inherit;
    font-size: var(--k-t-md);
    color: var(--k-ink);
    background: var(--k-surface);
    border: 1px solid var(--k-line);
    border-radius: var(--k-r-sm);
    padding: 7px 10px;
    min-height: 36px;
    transition: border-color var(--k-fast) var(--k-ease), box-shadow var(--k-fast) var(--k-ease);
}
/* 16px on touch, or iOS zooms the page on focus. */
@media (pointer: coarse) {
    input:where([type="text"], [type="number"], [type="date"], [type="email"],
                [type="password"], [type="search"], [type="tel"], [type="url"]),
    select, textarea { font-size: 16px; min-height: 44px; }
}

input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--k-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--k-accent) 20%, transparent);
}
input:disabled, select:disabled, textarea:disabled {
    background: var(--k-surface-3); color: var(--k-ink-muted); cursor: not-allowed; opacity: .7;
}
/* Read-only is not disabled: the value still matters, it just cannot change. */
input[readonly], textarea[readonly] {
    background: var(--k-surface-2); color: var(--k-ink); cursor: text; opacity: 1;
    border-style: dashed;
}
input[aria-invalid="true"], .k-invalid {
    border-color: var(--k-bad);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--k-bad) 18%, transparent);
}
.k-field-error { display: block; margin-top: 4px; font-size: var(--k-t-xs); color: var(--k-bad); }

label { font-size: var(--k-t-sm); font-weight: 550; color: var(--k-ink); }
label.required::after { content: " *"; color: var(--k-bad); }
.k-hint { display: block; margin-top: 3px; font-size: var(--k-t-xs); color: var(--k-ink-muted); }

/* ==========================================================================
   8. FEEDBACK
   ========================================================================== */

.kmp-alert {
    display: flex; align-items: flex-start; gap: var(--k-2);
    padding: var(--k-3) var(--k-4);
    border-radius: var(--k-r-sm);
    border: 1px solid transparent;
    font-size: var(--k-t-sm);
    margin-bottom: var(--k-4);
}
.kmp-alert-success { color: var(--k-ok);   background: var(--k-ok-wash);   border-color: color-mix(in srgb, var(--k-ok) 26%, transparent); }
.kmp-alert-danger  { color: var(--k-bad);  background: var(--k-bad-wash);  border-color: color-mix(in srgb, var(--k-bad) 26%, transparent); }
.kmp-alert-warning { color: var(--k-warn); background: var(--k-warn-wash); border-color: color-mix(in srgb, var(--k-warn) 26%, transparent); }
.kmp-alert-info    { color: var(--k-accent-ink); background: var(--k-accent-wash); border-color: color-mix(in srgb, var(--k-accent) 26%, transparent); }

/* Skeletons, not spinners: they hold the space the content will occupy, so
   nothing jumps when it arrives. */
.k-skeleton {
    background: linear-gradient(90deg,
        var(--k-surface-3) 25%,
        color-mix(in srgb, var(--k-hairline) 65%, var(--k-surface-3)) 37%,
        var(--k-surface-3) 63%);
    background-size: 400% 100%;
    animation: k-shimmer 1.4s ease-in-out infinite;
    border-radius: var(--k-r-xs);
    color: transparent !important;
}
@keyframes k-shimmer { from { background-position: 100% 50%; } to { background-position: 0 50%; } }

/* ==========================================================================
   9. COMMAND PALETTE
   --------------------------------------------------------------------------
   Fifteen modules in a sidebar is a lot of travel. Ctrl/Cmd-K jumps straight
   to any of them, which is how people who use a tool daily actually navigate.
   ========================================================================== */

.k-cmdk {
    position: fixed; inset: 0;
    z-index: var(--z-modal);
    display: grid; place-items: start center;
    padding-top: 12vh;
    background: color-mix(in srgb, var(--k-n-950) 55%, transparent);
    backdrop-filter: blur(3px);
    opacity: 0; pointer-events: none;
    transition: opacity var(--k-mid) var(--k-ease);
}
.k-cmdk[data-open="true"] { opacity: 1; pointer-events: auto; }

.k-cmdk-box {
    width: min(560px, calc(100vw - 32px));
    background: var(--k-surface);
    border: 1px solid var(--k-line);
    border-radius: var(--k-r-lg);
    box-shadow: var(--k-shadow-4);
    overflow: hidden;
    transform: translateY(-8px) scale(.99);
    transition: transform var(--k-mid) var(--k-ease);
}
.k-cmdk[data-open="true"] .k-cmdk-box { transform: none; }

.k-cmdk-input {
    width: 100%; border: 0 !important; border-radius: 0 !important;
    border-bottom: 1px solid var(--k-hairline) !important;
    padding: var(--k-4) !important;
    font-size: var(--k-t-lg) !important;
    background: transparent !important;
    box-shadow: none !important;
}
.k-cmdk-list { max-height: 46vh; overflow-y: auto; padding: var(--k-1); }
.k-cmdk-item {
    display: flex; align-items: center; gap: var(--k-3);
    padding: 9px var(--k-3);
    border-radius: var(--k-r-sm);
    font-size: var(--k-t-sm);
    color: var(--k-ink);
    text-decoration: none;
    cursor: pointer;
}
.k-cmdk-item i { width: 16px; text-align: center; color: var(--k-ink-muted); }
.k-cmdk-item[aria-selected="true"] { background: var(--k-accent-wash); color: var(--k-accent-ink); }
.k-cmdk-item[aria-selected="true"] i { color: var(--k-accent-ink); }
.k-cmdk-foot {
    display: flex; gap: var(--k-3); align-items: center;
    padding: var(--k-2) var(--k-3);
    border-top: 1px solid var(--k-hairline);
    background: var(--k-surface-2);
    font-size: var(--k-t-2xs); color: var(--k-ink-muted);
}
.k-kbd {
    font-family: var(--k-mono); font-size: 10px;
    padding: 1px 5px; border: 1px solid var(--k-line);
    border-bottom-width: 2px; border-radius: var(--k-r-xs);
    background: var(--k-surface); color: var(--k-ink-muted);
}

/* ==========================================================================
   10. MOTION
   --------------------------------------------------------------------------
   Entrances only, and only where they explain something: cards arriving in
   reading order, a panel growing from what opened it. Nothing loops; nothing
   is decorative.
   ========================================================================== */

@keyframes k-rise { from { opacity: 0; transform: translate3d(0, 8px, 0); } to { opacity: 1; transform: none; } }

.k-animate { animation: k-rise var(--k-slow) var(--k-ease) both; }
.k-animate:nth-child(1) { animation-delay: 0ms; }
.k-animate:nth-child(2) { animation-delay: 35ms; }
.k-animate:nth-child(3) { animation-delay: 70ms; }
.k-animate:nth-child(4) { animation-delay: 105ms; }
.k-animate:nth-child(5) { animation-delay: 140ms; }
.k-animate:nth-child(6) { animation-delay: 175ms; }
.k-animate:nth-child(n+7) { animation-delay: 210ms; }

/* The guarantee: asked for less motion, there is none. Not "reduced" — none.
   Every animation resolves instantly to its end state, so nothing is hidden
   and nothing moves. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
    }
    .k-animate { animation: none !important; opacity: 1 !important; transform: none !important; }
}

/* ==========================================================================
   11. RESPONSIVE
   ========================================================================== */

@media (max-width: 1180px) { :root { --k-rail: 224px; } }

/* Below this the sidebar is a drawer rather than half the screen. */
@media (max-width: 900px) {
    .sidebar {
        position: fixed; inset: 0 auto 0 0;
        z-index: var(--z-drawer);
        width: min(276px, 84vw); flex-basis: auto;
        transform: translateX(-100%);
        transition: transform var(--k-mid) var(--k-ease);
        box-shadow: var(--k-shadow-4);
    }
    body.k-drawer-open .sidebar { transform: none; }

    .k-scrim {
        position: fixed; inset: 0;
        background: rgba(11, 17, 25, .55);
        z-index: calc(var(--z-drawer) - 1);
        opacity: 0; pointer-events: none;
        transition: opacity var(--k-mid) var(--k-ease);
    }
    body.k-drawer-open .k-scrim { opacity: 1; pointer-events: auto; }

    .main-content { width: 100%; }
    .page-title { font-size: var(--k-t-xl) !important; }
    .stats-cards { grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr)); }
}

@media (max-width: 560px) {
    :root { --k-gutter: 12px; }
    .stats-cards { grid-template-columns: 1fr 1fr; gap: var(--k-2) !important; }
    .stat-card { flex-direction: column; align-items: flex-start; gap: var(--k-2); padding: var(--k-3) !important; }
    .stat-card .num, .stat-value { font-size: var(--k-t-xl); }
    .top-header { padding-inline: var(--k-3) !important; }
    .lc-date { display: none; }

    /* Dense tables become records, so nothing has to be read through a
       horizontal scroll on a phone. */
    .kmp-table.k-stack thead { display: none; }
    .kmp-table.k-stack tbody tr {
        display: block;
        border: 1px solid var(--k-hairline);
        border-radius: var(--k-r-sm);
        margin-bottom: var(--k-2);
        padding: var(--k-2);
        background: var(--k-surface);
    }
    .kmp-table.k-stack tbody td {
        display: flex; justify-content: space-between; gap: var(--k-4);
        border: 0; padding: 4px 0; text-align: right;
    }
    .kmp-table.k-stack tbody td::before {
        content: attr(data-label);
        font-size: var(--k-t-2xs); font-weight: 600;
        text-transform: uppercase; letter-spacing: .05em;
        color: var(--k-ink-muted); text-align: left;
    }
}

/* ==========================================================================
   12. PRINT
   --------------------------------------------------------------------------
   Statements, agreements and receipts are printed here constantly, so print
   is a real surface, not an afterthought.
   ========================================================================== */

@media print {
    .sidebar, .top-header, .k-scrim, .k-cmdk, .no-print,
    .kmp-btn, .k-rail-toggle, .k-theme-toggle, .k-drawer-toggle { display: none !important; }

    body { background: #fff !important; color: #000; font-size: 10.5pt; }
    .main-content, .dashboard-content, .container, .shell {
        margin: 0 !important; padding: 0 !important; width: auto !important; max-width: none !important;
    }
    .kmp-table-wrap { overflow: visible !important; border: 0; }
    .kmp-table { font-size: 9pt; }
    .kmp-table thead th {
        position: static; background: #eee !important; color: #000;
        -webkit-print-color-adjust: exact; print-color-adjust: exact;
    }
    /* A row must never break across a page mid-figure. */
    .kmp-table tr, .stat-card, .kmp-card { break-inside: avoid; page-break-inside: avoid; }
    .kmp-table thead { display: table-header-group; }   /* repeat on every page */
    .kmp-badge { border: 1px solid #999 !important; color: #000 !important; background: none !important; }
    a[href]::after { content: ""; }   /* no printed URLs in a legal document */
}

/* ==========================================================================
   13. UTILITIES
   ========================================================================== */

.k-icon-btn {
    display: inline-grid; place-items: center;
    width: 34px; height: 34px;
    border: 1px solid var(--k-hairline);
    border-radius: var(--k-r-sm);
    background: var(--k-surface);
    color: var(--k-ink-muted);
    cursor: pointer;
    transition: color var(--k-fast) var(--k-ease),
                border-color var(--k-fast) var(--k-ease),
                background-color var(--k-fast) var(--k-ease);
}
.k-icon-btn:hover { color: var(--k-accent-ink); border-color: var(--k-accent); background: var(--k-accent-wash); }

.k-rail-toggle { display: grid; place-items: center; width: 30px; height: 30px;
    margin: var(--k-2) auto 0; border: 0; cursor: pointer; border-radius: var(--k-r-sm);
    background: var(--k-chrome-hover); color: #fff;
    transition: background-color var(--k-fast) var(--k-ease); }
.k-rail-toggle:hover { background: var(--k-chrome-active); }

.k-sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
/* Visible the instant it takes focus, which is the whole point of a skip link. */
.k-skip {
    position: absolute; left: var(--k-3); top: -60px; z-index: var(--z-toast);
    background: var(--k-accent-ink); color: #fff;
    padding: 10px 16px; border-radius: var(--k-r-sm);
    font-weight: 600; text-decoration: none;
    transition: top var(--k-mid) var(--k-ease);
}
.k-skip:focus { top: var(--k-3); }

.k-muted { color: var(--k-ink-muted); }
.kmp-muted { color: var(--k-ink-muted); }
.k-pos { color: var(--k-ok);  font-variant-numeric: tabular-nums; }
.k-neg { color: var(--k-bad); font-variant-numeric: tabular-nums; }

/* ==========================================================================
   14. LEGACY OVERRIDES
   --------------------------------------------------------------------------
   Things the older stylesheets and inline markup do that the system above
   supersedes. Kept in one block so it is obvious what is being corrected and
   why, rather than scattered through the file.
   ========================================================================== */

/* --- Row actions ---------------------------------------------------------
   Every row carried six filled buttons in six colours — blue, grey, green,
   navy, grey, red — repeated down twenty-eight rows. The colour meant nothing
   (they are all just "open this"), and the wall of it drowned the status
   column, which is the only thing on the row that colour SHOULD be marking.

   They are quiet icon buttons now. The destructive one still reads as
   destructive, but only when the pointer is on it. */
.row-actions { display: flex; gap: 2px; flex-wrap: nowrap; }

.row-actions .kmp-btn {
    min-height: 28px; width: 28px; padding: 0;
    background: transparent !important;
    border-color: transparent !important;
    color: var(--k-ink-muted) !important;
    border-radius: var(--k-r-xs);
}
.row-actions .kmp-btn:hover {
    background: var(--k-surface-3) !important;
    color: var(--k-accent-ink) !important;
}
.row-actions .kmp-btn-danger:hover,
.row-actions .kmp-btn[href*="reject"]:hover,
.row-actions .kmp-btn[href*="delete"]:hover {
    background: var(--k-bad-wash) !important;
    color: var(--k-bad) !important;
}
@media (pointer: coarse) { .row-actions .kmp-btn { min-height: 40px; width: 40px; } }

/* The extra button colours the old sheet defined. Outside a table row they
   still exist, but they answer to the palette rather than to raw hexes. */
.kmp-btn-success { background: var(--k-ok) !important;  border-color: var(--k-ok) !important;  color: #fff !important; }
.kmp-btn-navy    { background: var(--k-n-700) !important; border-color: var(--k-n-700) !important; color: #fff !important; }
.kmp-btn-warning { background: var(--k-warn) !important; border-color: var(--k-warn) !important; color: #fff !important; }

/* --- Page headers --------------------------------------------------------
   Several pages open with a blue→navy gradient band, the same tell the
   sidebar had. Flat, with the figures carried by type instead of by a
   background that competes with them. */
/* `.page-hero` painted itself with a linear-gradient BACKGROUND IMAGE and no
   background colour. White text on it therefore had no reliable backdrop: the
   contrast audit resolved it against the page surface and found 1:1 in light
   mode. Flat colour, so the text has something real to sit on. */
.page-hero, .buyout-head, .page-head, .kmp-pagehead, .module-head {
    background: var(--k-n-800) !important;
    background-image: none !important;
    border: 1px solid var(--k-chrome-edge) !important;
    border-radius: var(--k-r) !important;
    color: #fff !important;
    box-shadow: none !important;
}
/* The hero carries a title on the left and a row of figures on the right.
   The old rule set only a background, so on a narrow column the two collided. */
.page-hero, .buyout-head, .page-head, .kmp-pagehead, .module-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--k-5);
    flex-wrap: wrap;
    padding: var(--k-4) var(--k-5) !important;
    margin-bottom: var(--k-3);
}
.page-hero > *, .buyout-head > * { min-width: 0; }
.page-hero h1, .page-hero h2, .page-hero h3,
.buyout-head h1, .buyout-head h2, .buyout-head h3 {
    font-size: var(--k-t-xl); margin: 0; color: #fff;
}
.page-hero .num, .buyout-head .num {
    font-size: var(--k-t-xl); font-weight: 600; line-height: 1.2;
    font-variant-numeric: tabular-nums; white-space: nowrap;
}
.page-hero .lbl, .buyout-head .lbl {
    font-size: var(--k-t-2xs); text-transform: uppercase; letter-spacing: .05em;
    color: rgba(255,255,255,.7) !important; margin-top: 2px;
}
@media (max-width: 640px) {
    .page-hero, .buyout-head { flex-direction: column; align-items: flex-start; }
}

.page-hero *, .buyout-head *, .page-head *, .kmp-pagehead *, .module-head * { color: inherit !important; }
.page-hero .kmp-muted, .buyout-head .kmp-muted, .page-head .kmp-muted { color: rgba(255,255,255,.74) !important; }
.page-hero .num, .page-hero .lbl { color: #fff !important; }

/* --- Panels the old sheet tinted with a light-blue gradient -------------- */
[style*="linear-gradient(135deg, #eef4fb"],
[style*="linear-gradient(135deg,#eef4fb"] {
    background: var(--k-surface-2) !important;
}

/* --- Toolbars ------------------------------------------------------------ */
.kmp-toolbar, .filters, .filter-bar {
    display: flex; flex-wrap: wrap; gap: var(--k-2); align-items: end;
    background: var(--k-surface) !important;
    border: 1px solid var(--k-hairline);
    border-radius: var(--k-r);
    padding: var(--k-3) !important;
    margin-bottom: var(--k-3);
}

/* --- Charts --------------------------------------------------------------
   Chart.js draws to a canvas and cannot read CSS variables, so the container
   is what gets themed; kmp-ui.js hands the palette to the chart itself. */
canvas { max-width: 100%; }

/* ==========================================================================
   15. THE LEGACY VARIABLE BRIDGE
   --------------------------------------------------------------------------
   `kmp-modern.css` declares its own --kmp-* variables as fixed hex values and
   the older rules reference them everywhere. Those rules are correct; their
   inputs were just frozen to one theme, which is why the first dark-mode pass
   left dark text on dark surfaces.

   Re-pointing the variables at the semantic tokens makes every rule that reads
   them theme-aware at once — without touching the rules themselves. One block
   instead of a few hundred edits, and it cannot drift, because there is now
   only one definition of what "text colour" means.
   ========================================================================== */

:root {
    --kmp-primary:      var(--k-accent);
    --kmp-primary-dark: var(--k-a-700);
    /* The old sheets use --kmp-navy as an INK colour — headings, table
       headers, form labels — far more often than as a surface. Mapping it to
       the chrome navy left dark text on dark surfaces at 1.3:1. It points at
       the ink token, which is dark on light and light on dark. */
    --kmp-navy:         var(--k-ink-strong);
    --kmp-navy-2:       var(--k-ink);
    --kmp-bg:           var(--k-bg);
    --kmp-bg-tint:      var(--k-surface-3);
    --kmp-surface:      var(--k-surface);
    --kmp-line:         var(--k-hairline);
    --kmp-text:         var(--k-ink);
    --kmp-muted:        var(--k-ink-muted);
    --kmp-success:      var(--k-ok);
    --kmp-danger:       var(--k-bad);
    --kmp-warning:      var(--k-warn);
    --kmp-info:         var(--k-accent-ink);
    --kmp-radius:       var(--k-r);
    --kmp-radius-sm:    var(--k-r-sm);
    --kmp-shadow:       var(--k-shadow-2);
    --kmp-shadow-sm:    var(--k-shadow-1);
    --kmp-font:         var(--k-font);
    --kmp-module-max:   var(--k-max);
    --kmp-module-gutter: var(--k-gutter);
}

/* ----------------------------------------------------------------------------
   DARK: the surfaces the old sheets painted by name rather than by token
   ----------------------------------------------------------------------------
   Everything below is written for BOTH dark paths.

   The tokens above already handle both — `[data-theme="dark"]` for an explicit
   choice, and `prefers-color-scheme` for the default "system" setting, which
   stamps no attribute at all. These component overrides were written only for
   the explicit one, so a user who had never touched the toggle and whose OS was
   in dark mode got dark tokens with none of the corrections that make the old
   stylesheets survive them.

   Each rule is therefore stated twice: once for the attribute, once inside the
   media query. Duplication is the price; a selector list cannot span a media
   query boundary, and getting it right in one path only is what caused this.
   -------------------------------------------------------------------------- */

:root[data-theme="dark"] :is(
    .card, .panel, .kmp-card, .stat-card, .modal-content, .kmp-modal,
    .table-wrap, .kmp-table-wrap, .kmp-table, .kmp-table tbody, .filters,
    .container-box, .shell, .cal-shell, .dropdown-menu, .form-section
) {
    background-color: var(--k-surface) !important;
    color: var(--k-ink);
}

/* Table headers.
   ---------------------------------------------------------------------------
   kmp-modern.css sets `table th { background-color: #f2f6fc !important }` — a
   literal light blue — for EVERY table, and the dark override here only named
   `.kmp-table thead th`. The dashboard's tables are plain <table> inside a
   .card, so in dark mode their headers kept the light background while the ink
   went near-white: #f4f7fa on #f2f6fc, a contrast ratio of 1.03:1. The column
   headings were invisible on every such table in the system, not just here. */
:root[data-theme="dark"] :is(table th, .kmp-table thead th, thead th) {
    background-color: var(--k-surface-2) !important;
    color: var(--k-ink-strong) !important;
    border-bottom-color: var(--k-line) !important;
}

/* The row hover was `#f6faff !important` — a near-white flash under the cursor
   on a dark table, which reads as a rendering fault rather than as a hover. */
:root[data-theme="dark"] :is(table tbody tr:hover, .kmp-table tbody tr:hover) {
    background-color: var(--k-surface-2) !important;
}

:root[data-theme="dark"] table td { border-bottom-color: var(--k-line) !important; }

:root[data-theme="dark"] :is(input, select, textarea) {
    background-color: var(--k-surface-2) !important;
    color: var(--k-ink) !important;
    border-color: var(--k-line) !important;
}

:root[data-theme="dark"] ::placeholder { color: var(--k-ink-muted); opacity: 1; }

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) :is(
        .card, .panel, .kmp-card, .stat-card, .modal-content, .kmp-modal,
        .table-wrap, .kmp-table-wrap, .kmp-table, .kmp-table tbody, .filters,
        .container-box, .shell, .cal-shell, .dropdown-menu, .form-section
    ) {
        background-color: var(--k-surface) !important;
        color: var(--k-ink);
    }

    :root:not([data-theme="light"]) :is(table th, .kmp-table thead th, thead th) {
        background-color: var(--k-surface-2) !important;
        color: var(--k-ink-strong) !important;
        border-bottom-color: var(--k-line) !important;
    }

    :root:not([data-theme="light"]) :is(table tbody tr:hover, .kmp-table tbody tr:hover) {
        background-color: var(--k-surface-2) !important;
    }

    :root:not([data-theme="light"]) table td { border-bottom-color: var(--k-line) !important; }

    :root:not([data-theme="light"]) :is(input, select, textarea) {
        background-color: var(--k-surface-2) !important;
        color: var(--k-ink) !important;
        border-color: var(--k-line) !important;
    }

    :root:not([data-theme="light"]) ::placeholder { color: var(--k-ink-muted); opacity: 1; }
}

/* ============================================================================
   DASHBOARD — the card grid, and the charts
   ----------------------------------------------------------------------------
   THE GRID

   `.stats-cards` uses `auto-fit`, which fits as many columns as the width
   allows and leaves whatever does not divide evenly on a row of its own. With
   five cards in a container four wide, the fifth sat alone in a quarter-width
   box with three quarters of the row empty — which reads as a missing card
   rather than a layout rule.

   `.k-cols-4` states the column count instead of deriving it. Four, then two,
   then one: every count divides at every breakpoint, so a row is never orphaned.
   Put four cards in it. Not five.
   ========================================================================= */

.stats-cards.k-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Two below 1180px, all the way down. That is the pair this sheet already used
   below 560px, and eight cards divide evenly by both four and two, so no row is
   ever short.

   There is deliberately no single-column rule. Eight full-width cards is a very
   long scroll before a phone reaches the first chart, and at 320px two columns
   still give each card about 145px — enough for the figure, which is sized
   against the card by the container query further down. */
@media (max-width: 1180px) { .stats-cards.k-cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* The figure, then what it is, then the qualifier. The qualifier is the line
   that stops "25 Active Loans / 19 Overdue Loans" reading as 44 loans. */
.stat-note {
    display: block;
    margin-top: 2px;
    font-size: var(--k-t-2xs);
    line-height: 1.35;
    color: var(--k-ink-muted);
}

/* ---- The chart row --------------------------------------------------------
   Collections needs the width; the panel beside it is a list. Below 1080px
   they stack, because a 300px-wide bar chart of twelve months is unreadable. */
.k-dash-row {
    display: grid;
    grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
    gap: var(--k-3);
    margin-bottom: var(--k-4);
    align-items: start;
}

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

@media (max-width: 1080px) {
    .k-dash-row, .k-dash-row.k-even { grid-template-columns: minmax(0, 1fr); }
}

/* ---- Column chart --------------------------------------------------------- */
.kmp-chart { display: block; width: 100%; height: auto; overflow: visible; }

.kmp-chart-grid { stroke: var(--k-line); stroke-width: 1; shape-rendering: crispEdges; }
.kmp-chart-base { stroke: var(--k-ink-muted); stroke-width: 1; shape-rendering: crispEdges; opacity: .5; }

.kmp-chart-axis {
    fill: var(--k-ink-muted);
    font-family: var(--k-font);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
}

.kmp-chart-bar {
    fill: var(--k-accent);
    transition: fill var(--k-fast) var(--k-ease);
}

/* The largest month, so the eye lands on it without reading every label. */
.kmp-chart-bar.is-peak { fill: var(--k-accent-ink); }
.kmp-chart-bar.is-zero { fill: var(--k-line); }
.kmp-chart-bar:hover   { fill: var(--k-ink-strong); }

/* ---- Fills, shared by every chart ----------------------------------------- */
.k-fill-accent { background: var(--k-accent); }
.k-fill-ok     { background: var(--k-ok-500); }
.k-fill-warn   { background: var(--k-warn-500); }
.k-fill-bad    { background: var(--k-bad-500); }
.k-fill-mute   { background: var(--k-g-400); }

/* ---- Horizontal bars — aging ---------------------------------------------- */
.kmp-hbars { display: flex; flex-direction: column; gap: 10px; }

.kmp-hbar {
    display: grid;
    grid-template-columns: 96px minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--k-2);
}

.kmp-hbar-label { font-size: var(--k-t-xs); color: var(--k-ink-muted); }

.kmp-hbar-track {
    display: block;
    height: 10px;
    border-radius: var(--k-r-pill);
    background: var(--k-surface-3, var(--k-mute-wash));
    overflow: hidden;
}

.kmp-hbar-fill {
    display: block;
    height: 100%;
    border-radius: var(--k-r-pill);
    /* Grows from nothing on load, so the shape of the book registers as a
       change rather than as wallpaper that was always there. */
    animation: kmp-hbar-grow var(--k-slow) var(--k-ease-out) both;
}

.kmp-hbar-value {
    font-size: var(--k-t-xs);
    color: var(--k-ink);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

@keyframes kmp-hbar-grow { from { transform: scaleX(0); transform-origin: left; } }

@media (max-width: 420px) {
    .kmp-hbar { grid-template-columns: 78px minmax(0, 1fr); }
    .kmp-hbar-value { grid-column: 2; text-align: right; }
}

/* ---- The composition bar --------------------------------------------------- */
.kmp-split {
    display: flex;
    height: 34px;
    border-radius: var(--k-r-sm);
    overflow: hidden;
    margin-bottom: var(--k-3);
    background: var(--k-mute-wash);
}

.kmp-split-part {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
    transition: filter var(--k-fast) var(--k-ease);
}

.kmp-split-part:hover { filter: brightness(1.08); }

/* The segments deliberately carry no text. White 11px on these fills measured
   2.96:1, 3.42:1 and 4.28:1 — all below 4.5:1 — and a text-shadow makes that
   look acceptable without making it pass. The legend below is the label. */

.kmp-legend { display: flex; flex-direction: column; gap: 8px; }

.kmp-legend-item {
    display: grid;
    grid-template-columns: 10px minmax(0, 1fr) auto auto;
    align-items: center;
    gap: var(--k-2);
    font-size: var(--k-t-xs);
}

.kmp-legend-dot { width: 10px; height: 10px; border-radius: 3px; }
.kmp-legend-label { color: var(--k-ink-muted); }
.kmp-legend-value { color: var(--k-ink); font-variant-numeric: tabular-nums; }

.kmp-legend-pct {
    color: var(--k-ink-muted);
    font-variant-numeric: tabular-nums;
    min-width: 46px;
    text-align: right;
}

/* ---- Nothing to plot ------------------------------------------------------- */
.kmp-chart-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--k-2);
    min-height: 180px;
    color: var(--k-ink-muted);
    font-size: var(--k-t-sm);
}

.kmp-chart-empty i { font-size: 26px; opacity: .45; }

/* A chart is data. It must survive the printer, and the printer has no theme. */
@media print {
    .kmp-chart-bar         { fill: #444 !important; }
    .kmp-chart-bar.is-peak { fill: #111 !important; }
    .kmp-chart-grid        { stroke: #ccc !important; }
    .kmp-chart-axis        { fill: #333 !important; }
    .k-fill-ok, .k-fill-warn, .k-fill-bad, .k-fill-mute, .k-fill-accent {
        background: #666 !important;
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }
    .kmp-hbar-fill { animation: none !important; }
}

@media (prefers-reduced-motion: reduce) {
    .kmp-hbar-fill { animation: none !important; }
}

/* ============================================================================
   NOTIFICATIONS, AND THE AVATAR
   ----------------------------------------------------------------------------
   The bell used to alert() a hardcoded list. It now reads get_notification.php
   and drops this panel; the alert() is gone, so the panel has to carry its own
   weight — it must be dismissible, scrollable, and legible in both themes.
   ========================================================================= */

.kmp-notif-panel {
    position: fixed;
    top: 64px;
    right: var(--k-3);
    z-index: 1200;
    width: min(380px, calc(100vw - 2 * var(--k-3)));
    max-height: min(520px, calc(100vh - 96px));
    overflow-y: auto;
    background: var(--k-surface);
    border: 1px solid var(--k-line);
    border-radius: var(--k-r);
    box-shadow: var(--k-shadow-3);
    /* Not `display:none`: the panel animates in, and a display swap cannot be
       transitioned. Hidden means unclickable as well as invisible. */
    opacity: 0;
    visibility: hidden;
    transform: translateY(-6px);
    transition: opacity var(--k-fast) var(--k-ease),
                transform var(--k-fast) var(--k-ease-out),
                visibility 0s linear var(--k-fast);
}

.kmp-notif-panel.is-open {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition-delay: 0s;
}

.kmp-notif-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: var(--k-3);
    font-weight: 600;
    font-size: var(--k-t-sm);
    color: var(--k-ink-strong);
    border-bottom: 1px solid var(--k-line);
    position: sticky; top: 0;
    background: var(--k-surface);
}

.kmp-notif-head span {
    font-size: var(--k-t-2xs);
    font-weight: 600;
    padding: 2px 8px;
    border-radius: var(--k-r-pill);
    background: var(--k-accent-wash);
    color: var(--k-accent-ink);
}

.kmp-notif-item {
    display: grid;
    grid-template-columns: 8px minmax(0, 1fr) auto;
    align-items: start;
    gap: var(--k-2);
    padding: var(--k-3);
    border-bottom: 1px solid var(--k-line);
    color: inherit;
    text-decoration: none;
}

a.kmp-notif-item:hover { background: var(--k-surface-2); }

.kmp-notif-dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 6px; }
.kmp-notif-dot.k-tone-ok   { background: var(--k-ok-500); }
.kmp-notif-dot.k-tone-warn { background: var(--k-warn-500); }
.kmp-notif-dot.k-tone-bad  { background: var(--k-bad-500); }

.kmp-notif-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.kmp-notif-text strong { font-size: var(--k-t-sm); color: var(--k-ink-strong); }
.kmp-notif-text span { font-size: var(--k-t-xs); color: var(--k-ink-muted); overflow-wrap: anywhere; }

.kmp-notif-when { font-size: var(--k-t-2xs); color: var(--k-ink-muted); white-space: nowrap; }

.kmp-notif-foot {
    display: block;
    padding: var(--k-3);
    text-align: center;
    font-size: var(--k-t-xs);
    color: var(--k-accent-ink);
    text-decoration: none;
}

.kmp-notif-foot:hover { background: var(--k-surface-2); }

/* The bell and the calendar are controls. They looked like controls before and
   one of them was inert; now both do something, so both say so on hover. */
.header-actions .calendar,
.header-actions .notification-btn { cursor: pointer; }

/* ---- Initials, drawn locally ---------------------------------------------
   Replaces an <img> from ui-avatars.com, which sent the signed-in officer's
   name to a third party on every page load and left an empty square whenever
   that host was slow. */
.kmp-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px; height: 32px;
    flex: 0 0 32px;
    border-radius: 50%;
    background: var(--k-accent);
    color: #fff;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .02em;
    user-select: none;
}

@media (prefers-reduced-motion: reduce) {
    .kmp-notif-panel { transition: opacity var(--k-fast) linear, visibility 0s; transform: none; }
}

/* ============================================================================
   FIGURES THAT FIT THEIR CARD
   ----------------------------------------------------------------------------
   The headline size already flexed, but it flexed with the VIEWPORT — and the
   viewport is not what constrains it. A card in a four-column grid is about a
   quarter of the content area wide however big the window is, so at 1400px the
   clamp resolved to its 1.5rem maximum and "₱11,090,000.00" ran into the card's
   edge. Fourteen characters at 24px need more room than a 260px card has after
   its icon and padding.

   A container query sizes the figure against the card that holds it, which is
   the thing that actually runs out of room.

   The vw clamp above stays as the fallback: where container queries are not
   supported the whole `cqi` declaration is invalid and the earlier rule stands.
   ========================================================================= */

.stat-card { container-type: inline-size; }

@supports (font-size: 1cqi) {
    .stat-card .num, .stat-card h3, .stat-card .stat-value, .stat-details h3 {
        /* ~9.5% of the card's inline size, floored so it never gets tiny and
           capped so a short figure like "19" does not become a headline. */
        font-size: clamp(1rem, 9.5cqi, 1.5rem) !important;
    }
}

/* ---- Due in 30 Days ------------------------------------------------------
   Three columns — name, amount, badge — in a card about 340px wide left the
   name roughly 130px, so "CHRISTIAN DAVE P ARCILLA" broke across three lines
   and the rows lost any common height. Two lines per row instead: who and how
   much, then when and what state. Nothing wraps that should not. */
.k-due-list { display: flex; flex-direction: column; }

.k-due-item {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 2px var(--k-2);
    padding: 10px 0;
    border-bottom: 1px solid var(--k-line);
}

.k-due-item:last-child { border-bottom: 0; }

.k-due-name {
    grid-column: 1;
    min-width: 0;
    font-weight: 600;
    font-size: var(--k-t-sm);
    color: var(--k-ink-strong);
    text-decoration: none;
    /* One line. A borrower's name is an identifier, and half of one on its own
       line reads as a different person. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

a.k-due-name:hover { color: var(--k-accent-ink); text-decoration: underline; }

.k-due-amount {
    grid-column: 2;
    grid-row: 1;
    white-space: nowrap;
    font-size: var(--k-t-sm);
    font-variant-numeric: tabular-nums;
    color: var(--k-ink-strong);
}

.k-due-when {
    grid-column: 1;
    grid-row: 2;
    font-size: var(--k-t-xs);
    color: var(--k-ink-muted);
}

.k-due-state { grid-column: 2; grid-row: 2; justify-self: end; }

/* A reversed receipt in a feed of collections. Struck through and dimmed, with
   a badge beside the name — it stays visible because it happened, but it must
   not read as money received. */
tr.is-reversed td { opacity: .62; }
tr.is-reversed .kmp-num { text-decoration: line-through; }

/* ============================================================================
   DARK: FILLED CONTROLS TAKE DARK TEXT, NOT WHITE
   ----------------------------------------------------------------------------
   --k-ok, --k-warn, --k-bad and --k-accent-ink are INK colours for dark mode:
   light enough to read as text on a dark surface. Several components used them
   as a solid BACKGROUND and kept white on top, which inverts what they are for.
   White measured 2.39:1 on the success button, 3.10:1 on danger, 2.21:1 on
   warning and 2.06:1 on the skip link.

   The fill is right; the text on it was not. Dark ink on the same fills gives
   6.12:1 to 9.18:1, which is also how a filled control is normally coloured in
   a dark interface.
   ========================================================================= */

:root[data-theme="dark"] :is(.kmp-btn-success, .kmp-btn-danger, .kmp-btn-warning, .k-skip) {
    color: var(--k-n-950) !important;
}

:root[data-theme="dark"] .k-skip { background: var(--k-accent-ink); }

/* ---- Aging buckets --------------------------------------------------------
   The aging report gives each bucket a colour and uses it three ways: a solid
   card under text, a bar segment, and badge text on a 13% wash of itself. One
   hue cannot do all three in both themes — a light-mode ink is too dark to read
   on a dark wash, which is why the six badges came back at 1.8-2.4:1 in dark
   after being fixed for light.

   So the colour is a token with a value per theme, and the page uses classes
   rather than inline hex. Every pairing below clears 4.5:1 in both roles and
   both themes; the worst is 4.83:1. */
.k-bucket-current  { --bucket: #2b7048; }
.k-bucket-1-30     { --bucket: #7a5306; }
.k-bucket-31-60    { --bucket: #9c4a10; }
.k-bucket-61-90    { --bucket: #a33628; }
.k-bucket-91-180   { --bucket: #8c2a1e; }
.k-bucket-over-180 { --bucket: #6b2d7a; }

:root[data-theme="dark"] .k-bucket-current  { --bucket: #5cba7d; }
:root[data-theme="dark"] .k-bucket-1-30     { --bucket: #e0b64a; }
:root[data-theme="dark"] .k-bucket-31-60    { --bucket: #e8a068; }
:root[data-theme="dark"] .k-bucket-61-90    { --bucket: #ef8a7a; }
:root[data-theme="dark"] .k-bucket-91-180   { --bucket: #f0847c; }
:root[data-theme="dark"] .k-bucket-over-180 { --bucket: #c894d8; }

/* Badge: the colour as text, on a wash of itself. */
.k-bucket-badge {
    color: var(--bucket);
    background: color-mix(in srgb, var(--bucket) 14%, var(--k-surface));
    border: 1px solid color-mix(in srgb, var(--bucket) 34%, transparent);
}

/* Card and bar: the colour as a fill. The text on a fill is white in light
   mode and the dark ink in dark mode, for the reason at the top of this block. */
.k-bucket-fill { background: var(--bucket); color: #fff; }
:root[data-theme="dark"] .k-bucket-fill { color: var(--k-n-950); }

.k-bucket-bar { background: var(--bucket); }

/* ============================================================================
   THE LAST OF THE CONTRAST FIXES
   ========================================================================= */

/* ---- A heading on a coloured banner keeps the banner's ink ----------------
   `h1, h2, h3, h4 { color: var(--k-ink-strong) }` beats the white a coloured
   header sets on itself, because inheritance loses to any rule that names the
   element. On the borrower and funder profiles that put the person's own name
   in near-black on a dark blue gradient: 1.56:1, the least readable thing on
   the page being the thing the page is about. */
:is(.profile-head, .page-hero, .form-header, .hd, .modal .hd, .bucket-card, .k-bucket-fill)
    :is(h1, h2, h3, h4, h5, h6) {
    color: inherit;
}

/* Headings only, deliberately.
   ---------------------------------------------------------------------------
   This first read `:is(h1..h6, p, span, div, strong, b, small)`, which was too
   wide: a .kmp-badge is a span, so a danger badge sitting in a profile header
   inherited the header's white and landed on its own pale wash at 1.11:1. It
   was fixing a heading and breaking every self-coloured component beside it.

   Only headings need this. Everything else already inherits correctly — the
   fault was the global `h1, h2, h3, h4 { color: var(--k-ink-strong) }`, which
   names the element and so beats inheritance. Nothing else does. */

/* ---- The avatar ----------------------------------------------------------
   White on --k-accent measured 4.15:1 in light and 2.96:1 in dark. The accent
   is a fill colour, not a backdrop for white text. */
.kmp-avatar { background: var(--k-accent-ink); color: #fff; }
:root[data-theme="dark"] .kmp-avatar { background: var(--k-accent); color: var(--k-n-950); }

/* ---- Selected tabs ------------------------------------------------------
   Two different kinds, and they need opposite fixes.

   An UNDERLINE tab colours its own text with var(--kmp-primary) = --k-a-500,
   which is 4.15:1 on white and 2.96:1 on a dark surface. That text moves to
   the ink token.

   A FILLED tab is white on that same blue. Recolouring its text was actively
   harmful — it put dark blue on a blue fill, 1.43:1, worse than what it
   replaced. The fill moves instead, and the white stays. */
:is(.tab-btn.active, .nav-tab.active) { color: var(--k-accent-ink) !important; }

.tabs a.active, .tabs .active[class*="fill"] {
    background: var(--k-accent-ink) !important;
    color: #fff !important;
}

/* ---- Badges in dark ------------------------------------------------------
   A heavier wash makes this WORSE, not better: the wash is a tint of the ink
   itself, so more of it moves the background toward the text. Measured, danger
   goes 4.29 -> 3.79 -> 3.28 as the wash climbs 14% -> 22% -> 30%.

   The wash stays at 14%. Only the danger ink needs to move, and it moves
   lighter — away from its own wash — which is the direction that helps. */
:root[data-theme="dark"] { --k-bad: #ea8272; }

/* ---- Page-level buttons that predate the design system -------------------
   Each was a mid-tone fill under white text: 2.53:1 to 3.98:1. They keep their
   shape and their place; only the fill moves to an ink weight. */
:is(.back-btn, .btn-submit, .action-btn.btn-secondary) {
    background: var(--k-accent-ink) !important;
    color: #fff !important;
    border-color: var(--k-accent-ink) !important;
}

:root[data-theme="dark"] :is(.back-btn, .btn-submit, .action-btn.btn-secondary) {
    background: var(--k-a-600) !important;
    border-color: var(--k-a-600) !important;
    color: #fff !important;
}

/* ---- The unread count on the bell ---------------------------------------- */
.notification-badge { background: var(--k-bad-700) !important; color: #fff !important; }

/* ---- Muted text that named its own grey ---------------------------------- */
.dt-head .dt-date { color: var(--k-ink-muted) !important; }

/* ============================================================================
   DENSITY — fit more on a screen without crowding it
   ----------------------------------------------------------------------------
   The complaint was that everything needs scrolling. Two causes: the content
   column was not using the width available to it (fixed above), and the
   vertical rhythm was built for a marketing page rather than a working screen.

   An officer reading a dashboard wants to see the figures together. The values
   below are one step down the scale, not a squeeze: 16px of card padding rather
   than 20-24, 12px between cards rather than 16, and a page that starts 16px
   below the header rather than 20 and ends 24px above the fold rather than 48.

   Anything a finger has to hit keeps its size. Touch targets are not density.
   ========================================================================= */

.dashboard-content { padding-block: var(--k-4) var(--k-6) !important; }

.page-title {
    margin-bottom: var(--k-3) !important;
    font-size: var(--k-t-xl) !important;
}

/* Cards ---------------------------------------------------------------------
   The stat card holds one figure, one label and one qualifier. 16px of padding
   frames that; 24px was framing the whitespace. */
.stat-card { padding: var(--k-4) var(--k-4) !important; }
.card, .kmp-card, .panel { padding: var(--k-4) !important; }

.stats-cards { gap: var(--k-3) !important; margin-bottom: var(--k-3) !important; }
.k-dash-row  { gap: var(--k-3); margin-bottom: var(--k-3); }

.card-header {
    padding-bottom: var(--k-2) !important;
    margin-bottom: var(--k-3) !important;
}

.card-header h2, .card h2 { font-size: var(--k-t-md) !important; }

/* Tables --------------------------------------------------------------------
   10px/12px rows rather than 14px/16px. Twenty rows in the space that held
   fourteen, and the row is still 38px tall — comfortably above the 24px where
   a dense table starts to misread. */
:is(.card, .kmp-card, .panel, .kmp-table-scroll) :is(table th, table td) {
    padding: 10px 12px !important;
}

/* The chart column was 260 tall in a 300 box. It reads at 210. */
.kmp-chart { max-height: 230px; }

/* ============================================================================
   SCROLLABLE TABLES
   ----------------------------------------------------------------------------
   Ported from the redesign's `.kcc-table-scroll` / `--y`, including the sticky
   header, which is the part that makes a scrolling table usable: the column
   names stay put while the rows move under them.

   A list of 66 receipts or 28 borrowers otherwise makes the whole PAGE scroll,
   so the officer loses the filters, the totals and the header the moment they
   look at row 20. Bounding the table's own height keeps the page still and
   moves only the rows.

   HEIGHT
   ------
   `--kmp-scroll-h` sets it, defaulting to 30rem. The redesign's markup passes a
   per-table height through a custom property but its stylesheet ignored the
   property and hardcoded 30rem; here the property is actually read.

       <div class="kmp-table-scroll kmp-table-scroll--y"
            style="--kmp-scroll-h: 26rem;">

   Use `--y` only where the list is genuinely long. A five-row table in a fixed
   30rem box is a large empty rectangle.
   ========================================================================= */

.kmp-table-scroll,
.kmp-table-wrap,
.table-wrap,
.table-responsive {
    inline-size: 100%;
    overflow-x: auto;
    border: 1px solid var(--k-hairline);
    border-radius: var(--k-r);
    background: var(--k-surface);
    -webkit-overflow-scrolling: touch;

    /*
     * Every list table is capped and scrolls. The three legacy wrapper names
     * are included rather than being replaced page by page, because they are
     * already on the borrowers, funders, payments, payables, activity, penalty
     * and aging tables — the exact lists that were making the page scroll.
     *
     * A CAP IS NOT A HEIGHT. `max-block-size` bounds a tall table and leaves a
     * short one alone, so a three-row table still renders three rows high
     * rather than sitting in a 30rem rectangle of nothing. Nothing needs a
     * per-page decision about which tables are long.
     */
    /*
     * The cap follows the window rather than being a fixed number.
     *
     * A flat 30rem is right on a laptop and wasteful on a 1440p monitor, where
     * it would leave a third of the screen empty below a table that is still
     * scrolling. `100dvh - 21rem` is the space left after the header, the page
     * title and a filter row; the clamp keeps it between 18rem — below which
     * scrolling costs more than it saves — and 46rem, past which the reader is
     * moving their head rather than their eyes.
     *
     * dvh, not vh: on mobile Safari `vh` counts the space behind the address
     * bar, so a 100vh-based box is taller than the screen until you scroll.
     */
    max-block-size: var(--kmp-scroll-h, clamp(18rem, calc(100dvh - 21rem), 46rem));
    overflow-y: auto;

    /* The sticky header needs a scroll container to stick inside; `clip` does
       not create one, which is why this is `auto` rather than `clip`. */
    overscroll-behavior: contain;
}

/* Opt out where a table is meant to print or run its full length in place. */
.kmp-table-scroll--full,
.kmp-table-wrap--full { max-block-size: none; overflow-y: visible; }

/* And the explicit opt-in, for markup that wants a height of its own. */
.kmp-table-scroll--y { max-block-size: var(--kmp-scroll-h, clamp(18rem, calc(100dvh - 21rem), 46rem)); overflow-y: auto; }

/* A table already inside a scroll box draws its own edges, so it does not need
   a second border around it. */
:is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive) > :is(table, .kmp-table) {
    inline-size: 100%;
    margin: 0;
    border: 0;
    border-collapse: separate;   /* `collapse` drops the sticky header's edge */
    border-spacing: 0;
}

:is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive) thead th {
    position: sticky;
    inset-block-start: 0;
    z-index: 2;
    background: var(--k-surface-2);
    border-bottom: 1px solid var(--k-line);
    white-space: nowrap;
}

/* Without this the rows scroll UNDER the header's rounded corner and show
   through it for a pixel or two. */
:is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive) thead th:first-child { border-start-start-radius: var(--k-r); }
:is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive) thead th:last-child { border-start-end-radius: var(--k-r); }

:is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive) tbody td { border-bottom: 1px solid var(--k-hairline); }
:is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive) tbody tr:last-child td { border-bottom: 0; }

/* A totals row belongs at the bottom of the box, not at the bottom of a scroll
   the reader has to reach. */
:is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive) tfoot td {
    position: sticky;
    inset-block-end: 0;
    z-index: 2;
    background: var(--k-surface-2);
    border-top: 1px solid var(--k-line);
    font-weight: 600;
}

/* Enough of a scrollbar to see that there is more, without a rail down every
   table that does not need one. */
:is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive) { scrollbar-width: thin; }
:is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive)::-webkit-scrollbar { width: 10px; height: 10px; }
:is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive)::-webkit-scrollbar-track { background: transparent; }
:is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive)::-webkit-scrollbar-thumb {
    background: var(--k-g-300);
    border: 3px solid var(--k-surface);
    border-radius: 6px;
}
:is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive)::-webkit-scrollbar-thumb:hover { background: var(--k-g-400); }

:root[data-theme="dark"] .kmp-table-scroll::-webkit-scrollbar-thumb {
    background: var(--k-n-700, #334456);
    border-color: var(--k-surface);
}

/* Paper has no scroll. Print the whole table. */
@media print {
    :is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive) {
        max-block-size: none !important;
        overflow: visible !important;
        border: 1px solid #ccc !important;
    }
    :is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive) :is(thead th, tfoot td) { position: static !important; }
}

/* A phone has less room, so the box is shorter — but it must still be taller
   than a couple of rows or the scroll is more work than the page was. */
@media (max-width: 720px) {
    :is(.kmp-table-scroll, .kmp-table-wrap, .table-wrap, .table-responsive) {
        /* A phone screen is short and its chrome takes proportionally more of
           it, so the box is measured against the viewport rather than clamped
           to a desktop figure. */
        max-block-size: min(var(--kmp-scroll-h, 62dvh), 62dvh);
    }
}

/* ---- Collapsible product blocks ------------------------------------------
   `<details>` gives the open/close behaviour; this is only the appearance.
   The default disclosure triangle is replaced by a chevron on the right, so
   the marker sits with the other controls rather than in front of the name. */
details.lt > summary.lt-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--k-3);
    cursor: pointer;
    list-style: none;
    user-select: none;
}

details.lt > summary.lt-head::-webkit-details-marker { display: none; }
details.lt > summary.lt-head::marker { content: ""; }

details.lt > summary.lt-head:hover { background: var(--k-surface-2); }

/* A summary is focusable, and a keyboard user must be able to see where they
   are — the browser's default outline is removed by the reset above. */
details.lt > summary.lt-head:focus-visible {
    outline: 2px solid var(--k-focus);
    outline-offset: -2px;
}

.lt-head-right {
    display: flex;
    align-items: center;
    gap: var(--k-3);
    flex-wrap: wrap;
    justify-content: flex-end;
}

/* The line that makes opening it unnecessary most of the time. */
.lt-glance {
    font-size: var(--k-t-xs);
    color: var(--k-ink-muted);
    white-space: nowrap;
}

.lt-chev {
    color: var(--k-ink-muted);
    font-size: 12px;
    transition: transform var(--k-fast) var(--k-ease);
}

details.lt[open] > summary.lt-head .lt-chev { transform: rotate(180deg); }

/* A closed product is a row in a list; an open one is a panel. */
details.lt[open] { box-shadow: var(--k-shadow-1) !important; }

@media (max-width: 720px) {
    .lt-glance { display: none; }   /* it wraps to three lines and stops helping */
}

@media (prefers-reduced-motion: reduce) {
    .lt-chev { transition: none; }
}

/* Printing a configuration means printing all of it. */
@media print {
    details.lt > .lt-body, details.lt > div { display: block !important; }
    .lt-chev { display: none; }
}

/* ============================================================================
   NOTHING PUSHES THE PAGE SIDEWAYS
   ----------------------------------------------------------------------------
   A grid or flex item defaults to `min-width: auto`, which means it refuses to
   shrink below its own content. A table inside a card inside `.card-row` was
   therefore sized by the widest row rather than by the column — 523px of table
   in a 390px phone — and the `overflow-x: auto` on its wrapper never engaged,
   because the wrapper was not the thing being squeezed.

   `min-width: 0` lets the item shrink, which hands the overflow back to the
   wrapper that knows how to scroll it.
   ========================================================================= */

:is(.card-row, .k-dash-row, .stats-cards, .lt-fields, .ac-grid) > * { min-width: 0; }
:is(.card, .kmp-card, .panel) > * { min-width: 0; }

/* A single unbroken token — a long reference, an email, a pasted URL — is the
   other way a page grows sideways. It wraps rather than pushing. */
:is(td, th, .lbl, .sub, dd, dt) { overflow-wrap: anywhere; }

/* The last line of defence. If something still overflows, the page scrolls the
   element, never the document: a horizontally scrolling PAGE loses the sidebar
   and the header, which is a much worse failure than a scrollbar on one table. */
body { overflow-x: clip; }

/* A title on the left and a row of buttons on the right is the standard page
   header here. On a phone the two do not fit side by side, and a flex row that
   cannot wrap pushes the buttons off the edge instead. They stack. */
@media (max-width: 720px) {
    :is(.card-header, .hd, .page-hero, .profile-head, .lt-head, .toolbar, .filters) {
        flex-wrap: wrap;
    }

    :is(.card-header, .hd, .page-hero, .profile-head, .lt-head, .toolbar, .filters) > * {
        min-width: 0;
    }
}
