/* ==========================================================================
   CGMFPFED Welfare Platform — portal stylesheet
   Enhances the existing Bootstrap 5 / AdminLTE 4 shell. No framework
   replacement — this file only refines spacing, color, typography and
   states on top of the vendor CSS already loaded in the layouts.
   Sections: Tokens, Base, Sidebar, Top nav, Cards & stat cards, Buttons,
   Badges, Tables, Forms, Alerts, Pagination, Empty state, Login,
   Accessibility, Loading states, Application journey, Responsive.
   ========================================================================== */

/* ---------------------------------------------------------------------- */
/* Tokens                                                                  */
/* ---------------------------------------------------------------------- */
/*
   FOREST — the department's own subject, used as its palette.

   This platform serves the Minor Forest Produce Federation: tendupatta collectors, primary societies,
   forest divisions. The previous palette was a generic administrative blue that said nothing about whose
   service this is. Forest green does, and it is also the colour the federation's own printed material and
   the legacy application used, so the change reads as familiarity rather than novelty.

   Deep forest carries structure — the sidebar, headers, primary actions. Leaf green is the accent and is
   used sparingly, for what is active or current. Amber and red keep their meaning, warmed slightly so they
   sit with green instead of vibrating against it. The ground is an off-white with a green cast rather than
   a blue one, which is the difference between a page that looks tinted and one that looks considered.

   ---------------------------------------------------------------------------------------------------
   THERE IS NO PURE BLACK AND NO PURE GREY ON THIS PLATFORM

   Every neutral here is biased green. `--cgm-ink` is a very dark forest, not #000; `--cgm-muted` is a
   grey-green, not #6c757d. A pure mid-grey beside green reads as unconsidered — the eye sees two
   unrelated systems. A neutral carrying a trace of the accent reads as one.

   ---------------------------------------------------------------------------------------------------
   EVERY PAIR BELOW IS MEASURED, NOT ASSUMED

   Contrast ratios against their intended background, computed rather than eyeballed:

     ink on page bg          14.97:1      muted on page bg          5.29:1
     ink on card             16.03:1      muted on card             5.66:1
     heading on card         11.86:1      ink-soft on card          8.76:1
     white on primary         7.72:1      white on leaf-dark        6.10:1
     white on success         5.13:1      white on warning          6.22:1
     white on danger          6.54:1      white on info             6.30:1
     forest on leaf-soft     10.34:1      forest on leaf-tint       9.40:1
     link on card             7.72:1      link on page bg           7.21:1
     sidebar white           15.34:1      sidebar muted             8.19:1

   All twenty clear WCAG 2.1 AA for normal text (4.5:1). `--cgm-border-input` is a separate, darker green
   from `--cgm-border` for exactly one reason: WCAG 1.4.11 requires 3:1 for the boundary of a control a
   person must find and operate, and the soft divider green is 1.64:1. A form outline is not decoration.
*/
:root {
    /* -------- Forest green: structure, primary actions, links -------- */
    --cgm-primary: #1b5e3f;
    --cgm-primary-dark: #123f2a;
    --cgm-primary-darker: #0d2c1d;

    /* -------- Leaf green: the accent. What is active, current, or growing -------- */
    --cgm-leaf: #3f9142;
    /* Leaf is 3.3:1 on white — an accent, never a background for normal text. This is the text-safe leaf. */
    --cgm-leaf-dark: #2f6f33;
    --cgm-leaf-soft: #e8f2e8;
    --cgm-leaf-tint: #d9e9dc;

    /* -------- Status, warmed to sit with green. Amber and red keep their conventional meaning -------- */
    --cgm-success: #2e7d32;
    /* Darkened from #a86400: white on amber must clear 4.5:1, and it did not. */
    --cgm-warning: #8f5200;
    --cgm-danger: #b3261e;
    --cgm-info: #0f6b6b;

    /* -------- Deep forest floor, for the sidebar -------- */
    --cgm-sidebar: #0f2a1d;
    --cgm-sidebar-hover: #17402c;
    --cgm-sidebar-ink: #e6efe8;
    --cgm-sidebar-muted: #a9c4b1;

    /* -------- Ground and ink. No pure black, no pure grey -------- */
    --cgm-body: #f5f8f4;
    --cgm-surface: #ffffff;
    --cgm-surface-alt: #fafcfa;
    --cgm-border: #d7e2d8;
    --cgm-border-strong: #bccfbe;
    /* WCAG 1.4.11: 3.23:1 on white, 3.01:1 on the page ground. Form controls only. */
    --cgm-border-input: #749879;
    --cgm-muted: #5b6b5e;
    --cgm-ink: #14251b;
    --cgm-ink-soft: #3d4f43;

    /* -------- Shape, elevation, motion -------- */
    --cgm-radius: 10px;
    --cgm-radius-sm: 7px;
    --cgm-radius-lg: 14px;
    --cgm-radius-pill: 999px;
    --cgm-shadow-sm: 0 1px 2px rgba(20, 37, 27, .06), 0 1px 3px rgba(20, 37, 27, .04);
    --cgm-shadow: 0 2px 4px rgba(20, 37, 27, .06), 0 4px 12px rgba(20, 37, 27, .05);
    --cgm-shadow-lg: 0 8px 28px rgba(20, 37, 27, .10);
    --cgm-focus-ring: 0 0 0 .2rem rgba(27, 94, 63, .28);

    /* -------- Type scale. One ratio, so nothing is sized by hand -------- */
    /*
       SOURCE SANS 3 HAS NO DEVANAGARI, so the stack names a Devanagari face explicitly.
       The platform renders Hindi in the brand heading on every page. Source Sans 3 covers Latin only —
       there is no Devanagari subset published for it at all — so those glyphs fall through the stack. With
       only Latin faces named they landed on whatever generic `sans-serif` resolved to, which differs on
       every operating system. Naming Noto Sans Devanagari first (present on Linux, Windows 10+ and
       Android) makes the Hindi line render the same way for everybody who has it, and still degrades to
       the system default for anybody who does not.
    */
    --cgm-font: "Source Sans 3", "Noto Sans Devanagari", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
    --cgm-font-mono: "SFMono-Regular", ui-monospace, Menlo, Consolas, monospace;
    --cgm-text-xs: .75rem;
    --cgm-text-sm: .8125rem;
    --cgm-text-base: .9375rem;
    --cgm-text-md: 1.0625rem;
    --cgm-text-lg: 1.25rem;
    --cgm-text-xl: 1.5rem;
    --cgm-text-2xl: 1.875rem;

    /* -------- Spacing, so gaps are chosen from a set rather than invented -------- */
    --cgm-gap-xs: .25rem;
    --cgm-gap-sm: .5rem;
    --cgm-gap: .75rem;
    --cgm-gap-md: 1rem;
    --cgm-gap-lg: 1.5rem;
    --cgm-gap-xl: 2rem;
}

/* ---------------------------------------------------------------------- */
/* Framework bridge                                                        */
/* ---------------------------------------------------------------------- */
/*
   THE HIGHEST-LEVERAGE BLOCK IN THIS FILE, and the one that was missing.

   Everything above it is our palette. Everything below it is our components. But most of what a person
   actually sees on a government back-office screen is drawn by Bootstrap and AdminLTE directly — a
   `<dl>`, a `.form-text`, a modal header, an `.input-group-text`, a disabled control, a `<code>` span,
   a dropdown divider. This file styled none of those, so they all rendered in the vendor defaults:

     --bs-body-color      #212529   near-black
     --bs-emphasis-color  #000      pure black
     --bs-primary         #0d6efd   Bootstrap blue
     --bs-secondary       #6c757d   pure grey
     --bs-border-color    #dee2e6   blue-grey

   That is where "too much black and dark grey" came from, and it could not be fixed component by
   component because the list of components is the whole framework. It is fixed by re-pointing the
   variable layer the framework itself reads. One block, and every unstyled element inherits forest —
   including any component added later that nobody remembers to theme.
*/
:root,
[data-bs-theme="light"] {
    /* Brand ramp */
    --bs-primary: var(--cgm-primary);
    --bs-primary-rgb: 27, 94, 63;
    --bs-secondary: var(--cgm-leaf-dark);
    --bs-secondary-rgb: 47, 111, 51;
    --bs-success: var(--cgm-success);
    --bs-success-rgb: 46, 125, 50;
    --bs-info: var(--cgm-info);
    --bs-info-rgb: 15, 107, 107;
    --bs-warning: var(--cgm-warning);
    --bs-warning-rgb: 143, 82, 0;
    --bs-danger: var(--cgm-danger);
    --bs-danger-rgb: 179, 38, 30;
    --bs-light: var(--cgm-leaf-soft);
    --bs-light-rgb: 232, 242, 232;
    /* `dark` must not be black. It is the deep forest the sidebar uses. */
    --bs-dark: var(--cgm-sidebar);
    --bs-dark-rgb: 15, 42, 29;

    /* Ink and ground. The four that carried black. */
    --bs-body-color: var(--cgm-ink);
    --bs-body-color-rgb: 20, 37, 27;
    --bs-body-bg: var(--cgm-body);
    --bs-body-bg-rgb: 245, 248, 244;
    --bs-emphasis-color: var(--cgm-primary-darker);
    --bs-emphasis-color-rgb: 13, 44, 29;
    --bs-heading-color: var(--cgm-primary-dark);

    --bs-secondary-color: var(--cgm-muted);
    --bs-secondary-color-rgb: 91, 107, 94;
    --bs-secondary-bg: var(--cgm-leaf-soft);
    --bs-secondary-bg-rgb: 232, 242, 232;
    --bs-tertiary-color: var(--cgm-ink-soft);
    --bs-tertiary-bg: var(--cgm-surface-alt);

    /* Greys, re-pointed so `.text-muted`, `.bg-light` and friends stop being blue-grey. */
    --bs-gray-100: #f5f8f4;
    --bs-gray-200: #e8efe8;
    --bs-gray-300: #d7e2d8;
    --bs-gray-400: #bccfbe;
    --bs-gray-500: #94a897;
    --bs-gray-600: var(--cgm-muted);
    --bs-gray-700: #47584b;
    --bs-gray-800: var(--cgm-ink-soft);
    --bs-gray-900: var(--cgm-ink);
    --bs-gray: var(--cgm-muted);
    --bs-gray-dark: var(--cgm-ink-soft);

    /* Links */
    --bs-link-color: var(--cgm-primary);
    --bs-link-color-rgb: 27, 94, 63;
    --bs-link-hover-color: var(--cgm-primary-dark);
    --bs-link-hover-color-rgb: 18, 63, 42;

    /* Structure */
    --bs-border-color: var(--cgm-border);
    --bs-border-color-translucent: rgba(20, 37, 27, .10);
    --bs-border-radius: var(--cgm-radius);
    --bs-border-radius-sm: var(--cgm-radius-sm);
    --bs-border-radius-lg: var(--cgm-radius-lg);
    --bs-border-radius-pill: var(--cgm-radius-pill);
    --bs-box-shadow-sm: var(--cgm-shadow-sm);
    --bs-box-shadow: var(--cgm-shadow);
    --bs-box-shadow-lg: var(--cgm-shadow-lg);

    /* Typography */
    --bs-body-font-family: var(--cgm-font);
    --bs-font-monospace: var(--cgm-font-mono);
    --bs-body-font-size: var(--cgm-text-base);
    --bs-body-line-height: 1.55;

    /* Subtle contextual pairs — Bootstrap draws alerts, list groups and tables from these. */
    --bs-primary-bg-subtle: var(--cgm-leaf-soft);
    --bs-primary-border-subtle: #b7d5c2;
    --bs-primary-text-emphasis: var(--cgm-primary-dark);
    --bs-secondary-bg-subtle: #eef4ef;
    --bs-secondary-border-subtle: #cfe0d2;
    --bs-secondary-text-emphasis: var(--cgm-ink-soft);
    --bs-success-bg-subtle: #e4f1e5;
    --bs-success-border-subtle: #b6d9b8;
    --bs-success-text-emphasis: #1d5720;
    --bs-info-bg-subtle: #e2f0f0;
    --bs-info-border-subtle: #aed4d4;
    --bs-info-text-emphasis: #0a4a4a;
    --bs-warning-bg-subtle: #fbf1e0;
    --bs-warning-border-subtle: #ecd5ac;
    --bs-warning-text-emphasis: #6d3f00;
    --bs-danger-bg-subtle: #fbe9e7;
    --bs-danger-border-subtle: #eeb9b4;
    --bs-danger-text-emphasis: #8c1e17;
    --bs-light-bg-subtle: var(--cgm-surface-alt);
    --bs-light-border-subtle: var(--cgm-border);
    --bs-dark-bg-subtle: var(--cgm-leaf-tint);
    --bs-dark-border-subtle: var(--cgm-border-strong);

    /* Focus. Bootstrap's default ring is blue and appears on every control. */
    --bs-focus-ring-color: rgba(27, 94, 63, .28);
    --bs-focus-ring-width: .2rem;

    /* AdminLTE reads its own layer; point it at the same tokens. */
    --lte-sidebar-bg: var(--cgm-sidebar);
    --lte-sidebar-color: var(--cgm-sidebar-ink);
    --lte-sidebar-hover-bg: var(--cgm-sidebar-hover);
    --lte-sidebar-hover-color: #ffffff;
    --lte-sidebar-active-bg: var(--cgm-primary);
    --lte-sidebar-active-color: #ffffff;
    --lte-sidebar-header-color: var(--cgm-sidebar-muted);
    --lte-app-header-bg: var(--cgm-surface);
    --lte-app-header-color: var(--cgm-ink);
    --lte-app-header-border-color: var(--cgm-border);
}

/*
   The platform is light-only by design — a government office screen is read under office light, and a
   half-finished dark mode is worse than none. But AdminLTE and Bootstrap both ship a dark theme that a
   browser or an OS setting can switch on, and it would land on a page whose components this file has
   coloured for light. Pointing the dark layer at the same tokens makes that switch harmless.
*/
[data-bs-theme="dark"] {
    --bs-body-color: var(--cgm-ink);
    --bs-body-bg: var(--cgm-body);
    --bs-emphasis-color: var(--cgm-primary-darker);
    --bs-heading-color: var(--cgm-primary-dark);
    --bs-secondary-color: var(--cgm-muted);
    --bs-border-color: var(--cgm-border);
    --bs-primary: var(--cgm-primary);
    --bs-link-color: var(--cgm-primary);
    --bs-link-hover-color: var(--cgm-primary-dark);
}

/* ---------------------------------------------------------------------- */
/* Base                                                                    */
/* ---------------------------------------------------------------------- */
body {
    background: var(--cgm-body);
    color: var(--cgm-ink);
    /*
       "Source Sans 3" FIRST, because it is the face this platform actually loads. The stack used to name
       Inter ahead of it, and Inter is linked nowhere — so every screen silently fell through to whatever
       the operating system offered, and the typography was different on every officer's machine. Source
       Sans 3 is a humanist face designed for interfaces, reads well at small sizes in both scripts this
       platform renders, and is the one already being downloaded.
    */
    /* The token, not a second copy of the stack — the two had already drifted apart. */
    font-family: var(--cgm-font);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    /* Devanagari and Latin sit at different optical sizes; a little extra leading keeps mixed labels even. */
    line-height: 1.55;
}

/* Figures that line up in a column must line up. Every table of amounts, counts and dates. */
table, .font-tabular, .text-end {
    font-variant-numeric: tabular-nums;
}

/*
   ONE TYPE SCALE, AND EVERY HEADING TAKES ITS SIZE FROM IT.

   Bootstrap sizes h1-h6 on a scale of its own that runs to 2.5rem, which on a back-office page produces
   a page title larger than anything on it needs to be, and left h4/h5/h6 — the sizes this platform
   actually uses for card and section titles — barely distinguishable from body text. Weight and colour
   carry the hierarchy here as much as size does, which is what keeps six levels legible inside the two
   rem of range a dense screen has to spend.
*/
h1, .h1 { font-size: var(--cgm-text-2xl); }
h2, .h2 { font-size: var(--cgm-text-xl); }
h3, .h3 { font-size: var(--cgm-text-lg); }
h4, .h4 { font-size: var(--cgm-text-md); }
h5, .h5 { font-size: var(--cgm-text-base); }
h6, .h6 { font-size: var(--cgm-text-sm); }

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
    color: var(--cgm-primary-dark);
    font-weight: 600;
    line-height: 1.3;
    /* A title that breaks 4 words / 1 word across two lines looks like an accident. */
    text-wrap: balance;
}

h1, h2, .h1, .h2 {
    font-weight: 700;
    letter-spacing: -.012em;
}

h6, .h6 {
    letter-spacing: .03em;
    text-transform: uppercase;
    color: var(--cgm-muted);
}

/* Paragraph rhythm. Bootstrap's 1rem bottom margin on every <p> is too much inside a dense card. */
p { margin-bottom: .75rem; }
p:last-child { margin-bottom: 0; }

small, .small { font-size: var(--cgm-text-sm); }

.app-wrapper, .content-wrapper {
    background: var(--cgm-body);
}

/* ---- Page header ---- */
.app-content-header {
    padding-top: 1.35rem;
    padding-bottom: 1.1rem;
}

.app-content-header h1 {
    font-size: var(--cgm-text-xl);
    font-weight: 700;
    letter-spacing: -.015em;
    color: var(--cgm-primary-dark);
}

.app-content {
    padding-bottom: 2.5rem;
}

/* Consistent vertical rhythm between stacked blocks, set once rather than per page. */
.app-content > .container-fluid > * + * {
    margin-top: var(--cgm-gap-md);
}

.text-muted {
    color: var(--cgm-muted) !important;
}

/* Monospace runs — application numbers, references, IFSC codes. */
code, kbd, samp, pre, .font-monospace {
    font-family: var(--cgm-font-mono);
    font-size: .9em;
}

code {
    color: var(--cgm-primary-dark);
    background: var(--cgm-leaf-soft);
    padding: .12em .38em;
    border-radius: 4px;
}

/* ---------------------------------------------------------------------- */
/* Sidebar                                                                 */
/* ---------------------------------------------------------------------- */
.app-sidebar {
    background: var(--cgm-sidebar);
}

.brand-link {
    min-height: 64px;
    border-bottom: 1px solid rgba(255, 255, 255, .08);
}

.brand-image {
    width: 40px;
    height: 40px;
    display: inline-grid;
    place-items: center;
    background: #fff;
    color: var(--cgm-primary);
    border-radius: var(--cgm-radius-sm);
}

.sidebar-wrapper {
    padding: .5rem .25rem 1rem;
}

.nav-sidebar > .nav-item {
    margin-bottom: 2px;
}

.nav-sidebar .nav-link {
    border-radius: var(--cgm-radius-sm);
    color: var(--cgm-sidebar-muted);
    padding: .55rem .8rem;
    transition: background-color .12s ease, color .12s ease;
}

.nav-sidebar .nav-link:hover {
    background: var(--cgm-sidebar-hover);
    color: #fff;
}

/*
   THE ACTIVE ITEM, which previously announced itself with a blue drop shadow.

   Three signals rather than one, because a sidebar of thirty items in one colour is scanned, not read:
   a leaf-green rail on the leading edge, a forest fill, and full-white ink at a heavier weight. The rail
   is what the eye finds first, and it is the accent's main job on this screen.

   No padding shift on hover any more. Text that moves when the pointer crosses it makes a menu feel
   loose, and it was also a 0.2rem horizontal jump on every item in a list people use all day.
*/
.nav-sidebar .nav-link.active {
    background: var(--cgm-primary);
    color: #fff;
    font-weight: 600;
    position: relative;
    box-shadow: inset 3px 0 0 0 var(--cgm-leaf);
}

.nav-sidebar .nav-link.active:hover {
    background: var(--cgm-primary);
}

.nav-sidebar .nav-link .nav-icon {
    width: 1.4rem;
    text-align: center;
    opacity: .85;
    font-size: .95em;
}

.nav-sidebar .nav-link.active .nav-icon {
    opacity: 1;
}

/* A parent whose child is the active page: marked, but never as loudly as the page itself. */
.nav-sidebar .nav-item.menu-open > .nav-link {
    background: rgba(255, 255, 255, .06);
    color: #fff;
}

.nav-sidebar .nav-treeview {
    border-left: 1px solid rgba(255, 255, 255, .08);
    margin-left: 1.35rem;
}

.nav-sidebar .nav-treeview .nav-link {
    padding-left: 1.1rem;
    font-size: .9rem;
}

.nav-sidebar .nav-treeview .nav-link:hover {
    padding-left: 1.3rem;
}

.nav-sidebar .nav-item.menu-open > a .nav-arrow {
    transform: rotate(90deg);
}

.nav-sidebar .nav-arrow {
    transition: transform .15s ease;
    font-size: .75rem;
}

.nav-sidebar .nav-link.disabled {
    opacity: .45;
    pointer-events: none;
}

/* ---------------------------------------------------------------------- */
/* Top navigation                                                          */
/* ---------------------------------------------------------------------- */
/*
   THE HEADER — a government masthead, not a marketing banner.

   A single very shallow gradient from white to the faintest leaf, and one leaf-green hairline along the
   bottom edge. That hairline is doing the real work: it separates the header from the content beneath it
   without a heavy shadow, and it ties the top of the page to the sidebar rail and the active menu item,
   so the three structural greens on screen are the same green. No glass blur, no colour wash behind
   text, nothing that moves.
*/
.app-header {
    min-height: 58px;
    background: linear-gradient(180deg, var(--cgm-surface) 0%, var(--cgm-surface-alt) 100%);
    border-bottom: 1px solid var(--cgm-border);
    box-shadow: inset 0 -2px 0 0 var(--cgm-leaf-tint), 0 1px 2px rgba(20, 37, 27, .04);
}

.app-header .navbar-nav .nav-link {
    border-radius: var(--cgm-radius-sm);
    color: var(--cgm-ink-soft);
    padding: .45rem .7rem;
}

.app-header .navbar-nav .nav-link:hover,
.app-header .navbar-nav .nav-link:focus-visible {
    background: var(--cgm-leaf-soft);
    color: var(--cgm-primary-dark);
}

.app-header .dropdown-menu {
    border-radius: var(--cgm-radius);
    border-color: var(--cgm-border);
    box-shadow: var(--cgm-shadow-lg);
    min-width: 15rem;
    padding: .35rem 0;
}

.app-header .dropdown-header {
    color: var(--cgm-muted);
    font-size: var(--cgm-text-xs);
    letter-spacing: .04em;
    text-transform: uppercase;
    font-weight: 700;
}

.app-header .dropdown-item {
    padding: .5rem .9rem;
    border-radius: var(--cgm-radius-sm);
    margin: 0 .35rem;
    width: calc(100% - .7rem);
}

.app-header .dropdown-item:hover {
    background: var(--cgm-body);
}

.app-header .badge.rounded-pill.text-bg-primary {
    width: 2rem;
    height: 2rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
}

/* ---------------------------------------------------------------------- */
/* Cards & stat cards                                                      */
/* ---------------------------------------------------------------------- */
/*
   CARDS — one surface treatment, used everywhere.

   `.app-card` and Bootstrap's own `.card` are given the same look, because the platform uses both and a
   page holding one of each looked like a page holding two design systems.
*/
.app-card,
.card {
    background: var(--cgm-surface);
    border: 1px solid var(--cgm-border);
    border-radius: var(--cgm-radius);
    box-shadow: var(--cgm-shadow-sm);
}

.card-header {
    background: var(--cgm-surface-alt);
    border-bottom: 1px solid var(--cgm-border);
    padding: .75rem 1rem;
    font-weight: 600;
    color: var(--cgm-primary-dark);
}

.card-header .card-title,
.card-header h1, .card-header h2, .card-header h3,
.card-header h4, .card-header h5, .card-header h6 {
    margin-bottom: 0;
    font-size: var(--cgm-text-base);
    text-transform: none;
    letter-spacing: 0;
    color: inherit;
}

.card-header i {
    color: var(--cgm-leaf-dark);
}

.card-body {
    padding: 1rem;
}

.card-footer {
    background: var(--cgm-surface-alt);
    border-top: 1px solid var(--cgm-border);
    padding: .7rem 1rem;
}

.module-section-heading {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--cgm-muted);
    font-size: var(--cgm-text-xs);
    margin: var(--cgm-gap-lg) 0 var(--cgm-gap);
    padding-bottom: .5rem;
    border-bottom: 2px solid var(--cgm-leaf-tint);
}

.module-section-heading:first-child {
    margin-top: 0;
}

.module-section-heading i {
    color: var(--cgm-primary);
    font-size: .95rem;
}

.stat-card {
    overflow: hidden;
    position: relative;
    transition: transform .15s ease, box-shadow .15s ease;
}

a .stat-card {
    cursor: pointer;
}

a:hover .stat-card {
    transform: translateY(-2px);
    box-shadow: var(--cgm-shadow-lg);
}

.stat-card .icon {
    font-size: 2.75rem;
    opacity: .16;
    position: absolute;
    right: 1rem;
    top: .85rem;
}

.stat-card .display-6 {
    font-weight: 700;
    letter-spacing: -.02em;
}

/* ---------------------------------------------------------------------- */
/* Buttons                                                                 */
/* ---------------------------------------------------------------------- */
/*
   EVERY VARIANT, REVIEWED — because a government form has eight buttons on it and the operator has to
   know instantly which one commits.

   Bootstrap generates `.btn-*` from its own $theme-colors, so re-pointing --bs-primary and friends in
   the bridge above already recolours all of them. What that cannot fix is the two things a palette swap
   never reaches:

     TEXT COLOUR   Bootstrap picks white-or-black text per variant from the colour it was compiled with.
                   With forest values substituted at runtime it keeps the old choice, so a light-green
                   `.btn-secondary` kept black text and a dark amber kept it too. Each is set explicitly
                   below, and each pair is measured.

     HOVER         Bootstrap darkens by a fixed shade. On the deep forest primary that produced a hover
                   state nearly identical to the resting one. Every hover here moves to a named token.
*/
.btn {
    border-radius: var(--cgm-radius-sm);
    font-weight: 600;
    letter-spacing: .008em;
    padding: .44rem .9rem;
    line-height: 1.45;
    transition: background-color .12s ease, border-color .12s ease, color .12s ease, box-shadow .12s ease;
}

/* No transform on press. A button that moves 1px under the pointer reads as a rendering glitch on a
   dense form, and it fought the focus ring. Colour carries the state instead. */
.btn:not(.disabled):not(:disabled):active {
    filter: brightness(.94);
}

.btn i {
    /* Icons in labels sat on the text baseline and rode high. */
    vertical-align: -.05em;
}

/*
   ---- EVERY VARIANT, VIA BOOTSTRAP'S OWN VARIABLE API ----

   `.btn-primary` and friends do NOT read --bs-primary. Bootstrap compiles each variant to a block of
   LITERAL values:

     .btn-primary{--bs-btn-bg:#0d6efd; --bs-btn-hover-bg:#0b5ed7; --bs-btn-disabled-bg:#0d6efd;
                  --bs-btn-focus-shadow-rgb:49,132,253; --bs-btn-active-shadow:inset 0 3px 5px rgba(0,0,0,.125)}

   Overriding `background` and `border-color` therefore repaints the resting state and leaves three
   others blue, and that is exactly what shipped: a DISABLED primary button rendered Bootstrap blue, and
   the FOCUS RING on every button on the platform was blue — on a keyboard-driven government form, the
   one state an operator sees most.

   Setting the variables instead covers all six states at once — resting, hover, focus, active, disabled
   and the focus ring — in a third of the CSS, and cannot drift out of step with itself.
*/
.btn {
    /* Neutral defaults so a bare `.btn` is forest, not the framework's grey. */
    --bs-btn-color: var(--cgm-ink-soft);
    --bs-btn-border-color: var(--cgm-border-strong);
    --bs-btn-hover-color: var(--cgm-primary-dark);
    --bs-btn-hover-bg: var(--cgm-leaf-soft);
    --bs-btn-hover-border-color: var(--cgm-leaf-dark);
    --bs-btn-focus-shadow-rgb: 27, 94, 63;
    /* Bootstrap presses buttons with a black inset shadow. Nothing on this platform is black. */
    --bs-btn-active-shadow: inset 0 2px 4px rgba(13, 44, 29, .18);
    --bs-btn-disabled-opacity: .55;
}

/* Primary: the committing action. White on forest, 7.72:1. */
.btn-primary {
    --bs-btn-color: #fff;
    --bs-btn-bg: var(--cgm-primary);
    --bs-btn-border-color: var(--cgm-primary);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--cgm-primary-dark);
    --bs-btn-hover-border-color: var(--cgm-primary-dark);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--cgm-primary-darker);
    --bs-btn-active-border-color: var(--cgm-primary-darker);
    --bs-btn-disabled-color: #fff;
    --bs-btn-disabled-bg: var(--cgm-primary);
    --bs-btn-disabled-border-color: var(--cgm-primary);
    --bs-btn-focus-shadow-rgb: 27, 94, 63;
}

/* Secondary: light green with forest ink, 10.34:1 — the brief's "Secondary — Light Green". */
.btn-secondary {
    --bs-btn-color: var(--cgm-primary-dark);
    --bs-btn-bg: var(--cgm-leaf-soft);
    --bs-btn-border-color: var(--cgm-border-strong);
    --bs-btn-hover-color: var(--cgm-primary-darker);
    --bs-btn-hover-bg: var(--cgm-leaf-tint);
    --bs-btn-hover-border-color: var(--cgm-leaf-dark);
    --bs-btn-active-color: var(--cgm-primary-darker);
    --bs-btn-active-bg: var(--cgm-leaf-tint);
    --bs-btn-active-border-color: var(--cgm-leaf-dark);
    --bs-btn-disabled-color: var(--cgm-primary-dark);
    --bs-btn-disabled-bg: var(--cgm-leaf-soft);
    --bs-btn-disabled-border-color: var(--cgm-border-strong);
    --bs-btn-focus-shadow-rgb: 47, 111, 51;
}

.btn-success {
    --bs-btn-color: #fff;
    --bs-btn-bg: var(--cgm-success);
    --bs-btn-border-color: var(--cgm-success);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: #26661f;
    --bs-btn-hover-border-color: #26661f;
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: #1d5720;
    --bs-btn-active-border-color: #1d5720;
    --bs-btn-disabled-color: #fff;
    --bs-btn-disabled-bg: var(--cgm-success);
    --bs-btn-disabled-border-color: var(--cgm-success);
    --bs-btn-focus-shadow-rgb: 46, 125, 50;
}

/* Warning: Bootstrap's amber is light enough for BLACK text and it set `--bs-btn-color:#000`.
   This amber is dark, so the ink is white at 6.22:1 — and there is no black on the platform. */
.btn-warning {
    --bs-btn-color: #fff;
    --bs-btn-bg: var(--cgm-warning);
    --bs-btn-border-color: var(--cgm-warning);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: #744200;
    --bs-btn-hover-border-color: #744200;
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: #603700;
    --bs-btn-active-border-color: #603700;
    --bs-btn-disabled-color: #fff;
    --bs-btn-disabled-bg: var(--cgm-warning);
    --bs-btn-disabled-border-color: var(--cgm-warning);
    --bs-btn-focus-shadow-rgb: 143, 82, 0;
}

.btn-danger {
    --bs-btn-color: #fff;
    --bs-btn-bg: var(--cgm-danger);
    --bs-btn-border-color: var(--cgm-danger);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: #8f1e18;
    --bs-btn-hover-border-color: #8f1e18;
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: #781813;
    --bs-btn-active-border-color: #781813;
    --bs-btn-disabled-color: #fff;
    --bs-btn-disabled-bg: var(--cgm-danger);
    --bs-btn-disabled-border-color: var(--cgm-danger);
    --bs-btn-focus-shadow-rgb: 179, 38, 30;
}

/* Info: Bootstrap's cyan also carried black ink. */
.btn-info {
    --bs-btn-color: #fff;
    --bs-btn-bg: var(--cgm-info);
    --bs-btn-border-color: var(--cgm-info);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: #0b5353;
    --bs-btn-hover-border-color: #0b5353;
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: #094444;
    --bs-btn-active-border-color: #094444;
    --bs-btn-disabled-color: #fff;
    --bs-btn-disabled-bg: var(--cgm-info);
    --bs-btn-disabled-border-color: var(--cgm-info);
    --bs-btn-focus-shadow-rgb: 15, 107, 107;
}

.btn-light {
    --bs-btn-color: var(--cgm-ink-soft);
    --bs-btn-bg: var(--cgm-surface);
    --bs-btn-border-color: var(--cgm-border-strong);
    --bs-btn-hover-color: var(--cgm-primary-dark);
    --bs-btn-hover-bg: var(--cgm-leaf-soft);
    --bs-btn-hover-border-color: var(--cgm-leaf-dark);
    --bs-btn-active-color: var(--cgm-primary-dark);
    --bs-btn-active-bg: var(--cgm-leaf-tint);
    --bs-btn-active-border-color: var(--cgm-leaf-dark);
    --bs-btn-disabled-color: var(--cgm-muted);
    --bs-btn-disabled-bg: var(--cgm-surface);
    --bs-btn-disabled-border-color: var(--cgm-border);
}

/* `dark` is the deep forest floor, never #212529. */
.btn-dark {
    --bs-btn-color: #fff;
    --bs-btn-bg: var(--cgm-sidebar);
    --bs-btn-border-color: var(--cgm-sidebar);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--cgm-primary-darker);
    --bs-btn-hover-border-color: var(--cgm-primary-darker);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--cgm-primary-darker);
    --bs-btn-active-border-color: var(--cgm-primary-darker);
    --bs-btn-disabled-color: #fff;
    --bs-btn-disabled-bg: var(--cgm-sidebar);
    --bs-btn-disabled-border-color: var(--cgm-sidebar);
    --bs-btn-focus-shadow-rgb: 15, 42, 29;
}

/*
   ---- Outline variants ----

   Each resting colour is measured against the PAGE ground (#f5f8f4), not only against white: an outline
   button on a table toolbar sits on the page, not on a card. All seven clear 4.5:1 there.
*/
.btn-outline-primary {
    --bs-btn-color: var(--cgm-primary);
    --bs-btn-border-color: var(--cgm-primary);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--cgm-primary);
    --bs-btn-hover-border-color: var(--cgm-primary);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--cgm-primary-dark);
    --bs-btn-active-border-color: var(--cgm-primary-dark);
    --bs-btn-disabled-color: var(--cgm-primary);
    --bs-btn-disabled-border-color: var(--cgm-primary);
    --bs-btn-focus-shadow-rgb: 27, 94, 63;
}

.btn-outline-secondary {
    --bs-btn-color: var(--cgm-primary-dark);
    --bs-btn-border-color: var(--cgm-border-strong);
    --bs-btn-hover-color: var(--cgm-primary-dark);
    --bs-btn-hover-bg: var(--cgm-leaf-soft);
    --bs-btn-hover-border-color: var(--cgm-leaf-dark);
    --bs-btn-active-color: var(--cgm-primary-darker);
    --bs-btn-active-bg: var(--cgm-leaf-tint);
    --bs-btn-active-border-color: var(--cgm-leaf-dark);
    --bs-btn-disabled-color: var(--cgm-muted);
    --bs-btn-disabled-border-color: var(--cgm-border);
    --bs-btn-focus-shadow-rgb: 47, 111, 51;
}

.btn-outline-success {
    --bs-btn-color: var(--cgm-success);
    --bs-btn-border-color: var(--cgm-success);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--cgm-success);
    --bs-btn-hover-border-color: var(--cgm-success);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: #26661f;
    --bs-btn-active-border-color: #26661f;
    --bs-btn-disabled-color: var(--cgm-success);
    --bs-btn-disabled-border-color: var(--cgm-success);
    --bs-btn-focus-shadow-rgb: 46, 125, 50;
}

.btn-outline-warning {
    --bs-btn-color: var(--cgm-warning);
    --bs-btn-border-color: var(--cgm-warning);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--cgm-warning);
    --bs-btn-hover-border-color: var(--cgm-warning);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: #744200;
    --bs-btn-active-border-color: #744200;
    --bs-btn-disabled-color: var(--cgm-warning);
    --bs-btn-disabled-border-color: var(--cgm-warning);
    --bs-btn-focus-shadow-rgb: 143, 82, 0;
}

.btn-outline-danger {
    --bs-btn-color: var(--cgm-danger);
    --bs-btn-border-color: var(--cgm-danger);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--cgm-danger);
    --bs-btn-hover-border-color: var(--cgm-danger);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: #8f1e18;
    --bs-btn-active-border-color: #8f1e18;
    --bs-btn-disabled-color: var(--cgm-danger);
    --bs-btn-disabled-border-color: var(--cgm-danger);
    --bs-btn-focus-shadow-rgb: 179, 38, 30;
}

.btn-outline-info {
    --bs-btn-color: var(--cgm-info);
    --bs-btn-border-color: var(--cgm-info);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--cgm-info);
    --bs-btn-hover-border-color: var(--cgm-info);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: #0b5353;
    --bs-btn-active-border-color: #0b5353;
    --bs-btn-disabled-color: var(--cgm-info);
    --bs-btn-disabled-border-color: var(--cgm-info);
    --bs-btn-focus-shadow-rgb: 15, 107, 107;
}

.btn-outline-light {
    --bs-btn-color: var(--cgm-ink-soft);
    --bs-btn-border-color: var(--cgm-border-strong);
    --bs-btn-hover-color: var(--cgm-primary-dark);
    --bs-btn-hover-bg: var(--cgm-leaf-soft);
    --bs-btn-hover-border-color: var(--cgm-leaf-dark);
    --bs-btn-active-color: var(--cgm-primary-dark);
    --bs-btn-active-bg: var(--cgm-leaf-tint);
    --bs-btn-active-border-color: var(--cgm-leaf-dark);
    --bs-btn-disabled-color: var(--cgm-muted);
    --bs-btn-disabled-border-color: var(--cgm-border);
}

.btn-outline-dark {
    --bs-btn-color: var(--cgm-sidebar);
    --bs-btn-border-color: var(--cgm-sidebar);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--cgm-sidebar);
    --bs-btn-hover-border-color: var(--cgm-sidebar);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--cgm-primary-darker);
    --bs-btn-active-border-color: var(--cgm-primary-darker);
    --bs-btn-disabled-color: var(--cgm-sidebar);
    --bs-btn-disabled-border-color: var(--cgm-sidebar);
    --bs-btn-focus-shadow-rgb: 15, 42, 29;
}

/* A link-styled button must be a forest link, not Bootstrap blue. */
.btn-link {
    --bs-btn-color: var(--cgm-primary);
    --bs-btn-hover-color: var(--cgm-primary-dark);
    --bs-btn-active-color: var(--cgm-primary-darker);
    --bs-btn-disabled-color: var(--cgm-muted);
    --bs-btn-border-color: transparent;
    --bs-btn-hover-border-color: transparent;
    --bs-btn-focus-shadow-rgb: 27, 94, 63;
    text-decoration: none;
    font-weight: 600;
}

.btn-link:hover, .btn-link:focus {
    text-decoration: underline;
}

/*
   The close button is a black SVG data URI in Bootstrap. `filter` recolours it to deep forest without
   shipping a second asset, which is what the `btn-close-white` variant would have required.
*/
.btn-close {
    filter: invert(16%) sepia(28%) saturate(1100%) hue-rotate(94deg) brightness(92%) contrast(93%);
}

.btn-close:focus {
    box-shadow: var(--cgm-focus-ring);
}

/* ---- Sizes ---- */
.btn-sm {
    border-radius: var(--cgm-radius-sm);
    padding: .3rem .65rem;
    font-size: var(--cgm-text-sm);
}

.btn-lg {
    border-radius: var(--cgm-radius);
    padding: .6rem 1.25rem;
    font-size: var(--cgm-text-md);
}

.btn-icon {
    width: 2.15rem;
    height: 2.15rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}

.btn-group-sm .btn-icon {
    width: 1.9rem;
    height: 1.9rem;
}

.btn:disabled, .btn.disabled {
    opacity: .55;
    box-shadow: none;
}

/* Toolbars: a consistent gap, so a row of actions is never crowded or scattered. */
.btn-toolbar {
    gap: var(--cgm-gap-sm);
}

/* ---------------------------------------------------------------------- */
/* Badges                                                                  */
/* ---------------------------------------------------------------------- */
.badge {
    font-weight: 600;
    letter-spacing: .01em;
    padding: .42em .7em;
}

.badge.rounded-pill {
    padding-left: .85em;
    padding-right: .85em;
}

/*
   Status badge palette shared by Scholarship and Beema application lists — see
   <x-application-status-badge>. Kept as classes (not inline utilities) so both modules stay visually
   identical without duplicating logic.

   THESE ARE NOT ALL GREEN, AND MUST NOT BE. A status badge exists to be told apart at a glance in a
   column of two hundred rows; recolouring six states into six shades of forest would make the palette
   tidy and the table unreadable. So each state keeps a distinct hue — amber pending, teal in payment,
   green done, red rejected — desaturated and shifted toward green so the set reads as one family
   without losing the signal. Every pair below measures 7.39:1 or better.
*/
.status-badge-draft {
    background: #e9eeea;
    color: #3d4f43;
}

.status-badge-pending {
    background: #fbf1e0;
    color: #6d3f00;
}

.status-badge-recommended {
    background: #e3edf5;
    color: #1c4a63;
}

.status-badge-payment-pending {
    background: #e2f0f0;
    color: #0a4a4a;
}

.status-badge-payment-done {
    background: #e4f1e5;
    color: #1d5720;
}

.status-badge-rejected {
    background: #fbe9e7;
    color: #8c1e17;
}

.status-badge-neutral {
    background: #e9eeea;
    color: #3d4f43;
}

/* ---------------------------------------------------------------------- */
/* Tables                                                                  */
/* ---------------------------------------------------------------------- */
.table thead th {
    background: var(--cgm-leaf-tint);
    color: var(--cgm-primary-dark);
    font-size: var(--cgm-text-xs);
    letter-spacing: .04em;
    text-transform: uppercase;
    white-space: nowrap;
    border-bottom-width: 1px;
}

.table thead th:first-child { border-top-left-radius: var(--cgm-radius-sm); }
.table thead th:last-child  { border-top-right-radius: var(--cgm-radius-sm); }

.table {
    --bs-table-border-color: var(--cgm-border);
    margin-bottom: 0;
}

.table td {
    vertical-align: middle;
    padding: .55rem .6rem;
    font-size: var(--cgm-text-base);
}

.table th {
    padding: .55rem .6rem;
}

/*
   Hover wins over the zebra stripe, which is the whole point of a hover: the row under the pointer must
   read as the row under the pointer whether it happens to be odd or even. `!important` because the
   nth-of-type rule below has equal specificity and comes later in the file.
*/
.table-hover > tbody > tr:hover > * {
    background-color: var(--cgm-leaf-soft) !important;
    --bs-table-accent-bg: transparent;
}

/* Alternate rows, a green whisper rather than a grey band — enough to track a row across
   thirty columns, not enough to compete with a status badge. */
.table > tbody > tr:nth-of-type(odd) > * {
    background-color: rgba(232, 242, 232, .45);
}

/* A row a person has acted on, or one flagged by a business rule. */
.table > tbody > tr.table-warning > * { background-color: var(--bs-warning-bg-subtle); }
.table > tbody > tr.table-danger  > * { background-color: var(--bs-danger-bg-subtle); }
.table > tbody > tr.table-success > * { background-color: var(--bs-success-bg-subtle); }

.table-responsive {
    border: 1px solid var(--cgm-border);
    border-radius: var(--cgm-radius-sm);
    background: var(--cgm-surface);
}

/* A table inside a card must not double its border against the card's own. */
.card > .table-responsive,
.app-card > .table-responsive {
    border: 0;
    border-radius: 0;
}

/* Row actions: a tight cluster, never a wrapping pile. */
.table .btn-icon + .btn-icon { margin-left: .2rem; }

/* ---------------------------------------------------------------------- */
/* Forms                                                                   */
/* ---------------------------------------------------------------------- */
.form-label {
    font-weight: 600;
    font-size: var(--cgm-text-sm);
    color: var(--cgm-ink-soft);
    margin-bottom: .35rem;
    letter-spacing: .005em;
}

.form-control, .form-select {
    border-radius: var(--cgm-radius-sm);
    /* Not --cgm-border: a control a person must find needs 3:1, and the divider green is 1.64:1. */
    border-color: var(--cgm-border-input);
}

.form-control:focus, .form-select:focus {
    border-color: var(--cgm-primary);
    box-shadow: var(--cgm-focus-ring);
}

.form-control:disabled, .form-control[readonly] {
    background-color: var(--cgm-leaf-soft);
    color: var(--cgm-muted);
}

.form-control::placeholder {
    color: var(--cgm-muted);
    opacity: .75;
}

/* An invalid control must be findable without relying on colour alone — the border thickens too. */
.form-control.is-invalid, .form-select.is-invalid {
    border-color: var(--cgm-danger);
    border-width: 2px;
}

.form-control.is-invalid:focus, .form-select.is-invalid:focus {
    box-shadow: 0 0 0 .2rem rgba(179, 38, 30, .22);
}

.input-group-text {
    background: var(--cgm-leaf-soft);
    border-color: var(--cgm-border-input);
    color: var(--cgm-primary-dark);
}

.form-text {
    font-size: var(--cgm-text-sm);
    color: var(--cgm-muted);
}

.invalid-feedback {
    font-size: var(--cgm-text-sm);
    font-weight: 600;
}

/* Consistent vertical rhythm between fields, set once instead of per-form utility classes. */
.form-group + .form-group,
.row > [class*="col-"] > .form-label:first-child { margin-top: 0; }

fieldset > legend,
.form-section-title {
    font-size: var(--cgm-text-sm);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--cgm-muted);
    border-bottom: 2px solid var(--cgm-leaf-tint);
    padding-bottom: .4rem;
    margin-bottom: var(--cgm-gap-md);
}

.required::after {
    color: var(--cgm-danger);
    content: " *";
    font-weight: 700;
}

.form-check-input:focus {
    box-shadow: var(--cgm-focus-ring);
}

/* ---------------------------------------------------------------------- */
/* Alerts                                                                  */
/* ---------------------------------------------------------------------- */
.alert {
    border: 1px solid transparent;
    border-left-width: 4px;
    border-radius: var(--cgm-radius-sm);
}

.alert-success {
    border-left-color: var(--cgm-success);
}

.alert-danger {
    border-left-color: var(--cgm-danger);
}

.alert-warning {
    border-left-color: var(--cgm-warning);
}

.alert-info {
    border-left-color: var(--cgm-info);
}

/* ---------------------------------------------------------------------- */
/* Pagination                                                              */
/* ---------------------------------------------------------------------- */
.pagination .page-link {
    border-radius: var(--cgm-radius-sm);
    margin: 0 .1rem;
    color: var(--cgm-ink-soft);
    border-color: var(--cgm-border);
}

.pagination .page-item.active .page-link {
    background: var(--cgm-primary);
    border-color: var(--cgm-primary);
}

.pagination .page-link:focus {
    box-shadow: var(--cgm-focus-ring);
}

/* ---------------------------------------------------------------------- */
/* Empty state                                                             */
/* ---------------------------------------------------------------------- */
.empty-state {
    padding: 3rem 1rem;
    text-align: center;
}

.empty-state-icon {
    width: 72px;
    height: 72px;
    display: inline-grid;
    place-items: center;
    border-radius: 50%;
    background: var(--cgm-leaf-soft);
    color: var(--cgm-primary);
    font-size: 1.9rem;
}

/* ---------------------------------------------------------------------- */
/* Login page                                                              */
/* ---------------------------------------------------------------------- */
.login-page {
    min-height: 100vh;
    /* Was a blue-700 gradient over slate-900 — the single most black-and-blue surface on the
       platform, and the first thing anybody sees. Now forest into leaf, over deep forest floor. */
    background:
        linear-gradient(135deg, rgba(18, 63, 42, .94), rgba(63, 145, 66, .80)),
        radial-gradient(circle at top left, rgba(255, 255, 255, .18), transparent 38%),
        var(--cgm-sidebar);
}

.login-card {
    width: min(100%, 460px);
    border-radius: var(--cgm-radius);
}

.login-emblem {
    width: 64px;
    height: 64px;
    display: grid;
    place-items: center;
    border-radius: var(--cgm-radius);
    background: var(--cgm-leaf-soft);
    color: var(--cgm-primary);
    font-size: 2rem;
}

/* ---------------------------------------------------------------------- */
/* Accessibility                                                           */
/* ---------------------------------------------------------------------- */
a:focus-visible,
button:focus-visible,
.btn:focus-visible,
.nav-link:focus-visible,
.form-control:focus-visible,
.form-select:focus-visible,
.page-link:focus-visible {
    outline: 2px solid var(--cgm-primary);
    outline-offset: 2px;
}

.visually-hidden-focusable:not(:focus) {
    clip: rect(0 0 0 0);
    position: absolute;
}

/* ---------------------------------------------------------------------- */
/* Loading states                                                          */
/* ---------------------------------------------------------------------- */
.btn.is-loading {
    position: relative;
    color: transparent !important;
    pointer-events: none;
}

.btn.is-loading::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 1rem;
    height: 1rem;
    margin: -.5rem 0 0 -.5rem;
    border: .18rem solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    color: #fff;
    animation: cgm-spin .6s linear infinite;
}

.btn-outline-primary.is-loading::after,
.btn-outline-secondary.is-loading::after,
.btn-outline-danger.is-loading::after,
.btn-outline-warning.is-loading::after,
.btn-link.is-loading::after {
    color: var(--cgm-primary);
}

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

/* ---------------------------------------------------------------------- */
/* Application journey — progress rail, KYC locks, upload previews         */
/* ---------------------------------------------------------------------- */

/* The rail stays on screen while the VLE scrolls a long form: its whole job is
   answering "how much is left", which it cannot do once scrolled past. */
.journey-rail {
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--cgm-body);
    padding: .6rem 0 .35rem;
    margin-bottom: .85rem;
}

.journey-steps {
    display: flex;
    align-items: stretch;
    gap: .35rem;
    overflow-x: auto;
    scrollbar-width: thin;
    list-style: none;
    margin: 0;
    padding: 0 0 .25rem;
}

.journey-step {
    flex: 1 1 0;
    min-width: 8.5rem;
}

.journey-step-button {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    gap: .5rem;
    text-align: left;
    background: #fff;
    border: 1px solid var(--cgm-border);
    border-radius: var(--cgm-radius-sm);
    padding: .5rem .6rem;
    font-size: .78rem;
    line-height: 1.2;
    color: var(--cgm-muted);
    cursor: pointer;
    transition: border-color .15s ease, box-shadow .15s ease, color .15s ease;
}

.journey-step-button:hover:not(:disabled) {
    border-color: var(--cgm-primary);
}

.journey-step-button:disabled {
    cursor: not-allowed;
    opacity: .65;
}

.journey-step-marker {
    flex: 0 0 1.6rem;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--cgm-leaf-soft);
    border: 1px solid var(--cgm-border);
    font-weight: 600;
    font-size: .72rem;
    color: var(--cgm-muted);
}

.journey-step-label {
    font-weight: 600;
}

.journey-step-hint {
    display: block;
    font-weight: 400;
    font-size: .7rem;
    color: var(--cgm-muted);
}

.journey-step[data-state="current"] .journey-step-button {
    border-color: var(--cgm-primary);
    box-shadow: var(--cgm-focus-ring);
    color: var(--cgm-ink);
}

.journey-step[data-state="current"] .journey-step-marker {
    background: var(--cgm-primary);
    border-color: var(--cgm-primary);
    color: #fff;
}

.journey-step[data-state="done"] .journey-step-button {
    border-color: var(--cgm-success);
    color: var(--cgm-ink);
}

.journey-step[data-state="done"] .journey-step-marker {
    background: var(--cgm-success);
    border-color: var(--cgm-success);
    color: #fff;
}

.journey-progress-bar {
    height: 4px;
    border-radius: 2px;
    background: var(--cgm-border);
    overflow: hidden;
}

.journey-progress-bar > span {
    display: block;
    height: 100%;
    width: 0;
    background: var(--cgm-success);
    transition: width .25s ease;
}

/* Sections beyond the KYC gate. Hidden rather than merely disabled: the point of
   the gate is that data entry has not begun, and a greyed-out form still reads as
   somewhere to start typing. */
.journey-gated[hidden] {
    display: none !important;
}

/* A field a biometric provider populated. Read-only look is deliberate and
   distinct from `readonly` alone, which a VLE reads as "not my turn yet" rather
   than "this cannot be changed". */
.kyc-locked {
    background-color: var(--cgm-leaf-soft) !important;
    border-color: var(--cgm-border-input) !important;
    color: var(--cgm-ink) !important;
    cursor: not-allowed;
}

.kyc-lock-note {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    font-size: .72rem;
    font-weight: 600;
    color: var(--cgm-success);
}

.badge-verified {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    background: #e4f1e5;
    color: #1d5720;
    border: 1px solid #b6d9b8;
    border-radius: var(--cgm-radius-pill);
    padding: .2rem .6rem;
    font-size: var(--cgm-text-xs);
    font-weight: 600;
}

.badge-verified.is-pending {
    background: #fbf1e0;
    color: #6d3f00;
    border-color: #ecd5ac;
}

/* Upload controls: hint, progress, and the preview of what was actually attached. */
.upload-control {
    border: 1px dashed var(--cgm-border);
    border-radius: var(--cgm-radius-sm);
    padding: .7rem;
}

.upload-control[data-state="error"] {
    border-color: var(--cgm-danger);
    border-style: solid;
}

.upload-control[data-state="ready"] {
    border-color: var(--cgm-success);
    border-style: solid;
}

.upload-preview {
    display: flex;
    align-items: center;
    gap: .6rem;
    margin-top: .5rem;
}

.upload-preview-thumb {
    flex: 0 0 44px;
    width: 44px;
    height: 44px;
    border-radius: var(--cgm-radius-sm);
    border: 1px solid var(--cgm-border);
    object-fit: cover;
    background: var(--cgm-surface-alt);
}

.upload-preview-icon {
    display: grid;
    place-items: center;
    color: var(--cgm-muted);
}

.upload-progress {
    height: 4px;
    border-radius: 2px;
    background: var(--cgm-border);
    overflow: hidden;
    margin-top: .5rem;
}

.upload-progress > span {
    display: block;
    height: 100%;
    width: 0;
    background: var(--cgm-primary);
    transition: width .15s linear;
}

@media (max-width: 767.98px) {
    .journey-rail {
        position: static;
    }

    .journey-step {
        min-width: 11rem;
    }
}

/* ---------------------------------------------------------------------- */
/* Framework components                                                    */
/* ---------------------------------------------------------------------- */
/*
   The Bootstrap components this platform uses but never styled. The bridge above gives each of them the
   right colours; these rules give them the right shape and spacing, so a modal and a card look like they
   belong to the same platform rather than to Bootstrap and to us.
*/

/* ---- Modals ---- */
.modal-content {
    border: 1px solid var(--cgm-border);
    border-radius: var(--cgm-radius-lg);
    box-shadow: var(--cgm-shadow-lg);
}

.modal-header {
    background: var(--cgm-surface-alt);
    border-bottom: 1px solid var(--cgm-border);
    border-top-left-radius: var(--cgm-radius-lg);
    border-top-right-radius: var(--cgm-radius-lg);
}

.modal-title {
    font-size: var(--cgm-text-md);
    font-weight: 600;
    color: var(--cgm-primary-dark);
}

.modal-footer {
    background: var(--cgm-surface-alt);
    border-top: 1px solid var(--cgm-border);
    gap: var(--cgm-gap-sm);
}

/* Bootstrap's backdrop is pure black at 50%. Deep forest reads warmer and matches the sidebar. */
.modal-backdrop {
    --bs-backdrop-bg: #0f2a1d;
    --bs-backdrop-opacity: .55;
}

/* ---- Dropdowns ---- */
.dropdown-menu {
    border-color: var(--cgm-border);
    border-radius: var(--cgm-radius);
    box-shadow: var(--cgm-shadow-lg);
    padding: .35rem;
}

.dropdown-item {
    border-radius: var(--cgm-radius-sm);
    padding: .45rem .7rem;
    font-size: var(--cgm-text-base);
}

.dropdown-item:hover, .dropdown-item:focus {
    background: var(--cgm-leaf-soft);
    color: var(--cgm-primary-dark);
}

.dropdown-item.active, .dropdown-item:active {
    background: var(--cgm-primary);
    color: #fff;
}

.dropdown-divider {
    border-top-color: var(--cgm-border);
}

/* ---- Tabs and pills ---- */
.nav-tabs {
    border-bottom: 1px solid var(--cgm-border);
    gap: .15rem;
}

.nav-tabs .nav-link {
    border: 0;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    color: var(--cgm-muted);
    font-weight: 600;
    padding: .55rem .9rem;
}

.nav-tabs .nav-link:hover {
    color: var(--cgm-primary-dark);
    border-bottom-color: var(--cgm-leaf-tint);
    background: transparent;
}

.nav-tabs .nav-link.active {
    color: var(--cgm-primary-dark);
    border-bottom-color: var(--cgm-leaf);
    background: transparent;
}

.nav-pills .nav-link {
    border-radius: var(--cgm-radius-pill);
    color: var(--cgm-ink-soft);
    font-weight: 600;
}

.nav-pills .nav-link.active {
    background: var(--cgm-primary);
    color: #fff;
}

/* ---- List groups ---- */
.list-group-item {
    border-color: var(--cgm-border);
    padding: .65rem .85rem;
}

.list-group-item.active {
    background: var(--cgm-primary);
    border-color: var(--cgm-primary);
    color: #fff;
}

.list-group-item-action:hover {
    background: var(--cgm-leaf-soft);
    color: var(--cgm-primary-dark);
}

/* ---- Breadcrumb ---- */
.breadcrumb {
    font-size: var(--cgm-text-sm);
    margin-bottom: 0;
    --bs-breadcrumb-divider-color: var(--cgm-border-strong);
}

.breadcrumb-item a {
    color: var(--cgm-primary);
    text-decoration: none;
    font-weight: 600;
}

.breadcrumb-item a:hover { text-decoration: underline; }
.breadcrumb-item.active  { color: var(--cgm-muted); }

/* ---- Progress ---- */
.progress {
    background: var(--cgm-leaf-tint);
    border-radius: var(--cgm-radius-pill);
    height: .6rem;
}

.progress-bar { background: var(--cgm-leaf-dark); }

/* ---- Tooltips and popovers ---- */
.tooltip-inner {
    background: var(--cgm-sidebar);
    border-radius: var(--cgm-radius-sm);
    font-size: var(--cgm-text-sm);
    padding: .35rem .6rem;
}

.tooltip .tooltip-arrow::before { border-top-color: var(--cgm-sidebar); }

.popover {
    border-color: var(--cgm-border);
    border-radius: var(--cgm-radius);
    box-shadow: var(--cgm-shadow-lg);
}

.popover-header {
    background: var(--cgm-leaf-soft);
    color: var(--cgm-primary-dark);
    border-bottom-color: var(--cgm-border);
}

/* ---- Definition lists: the detail-page workhorse on both modules ---- */
dl dt {
    color: var(--cgm-muted);
    font-weight: 600;
    font-size: var(--cgm-text-sm);
}

dl dd {
    color: var(--cgm-ink);
    margin-bottom: .55rem;
}

/* ---- Horizontal rules ---- */
hr {
    border-top-color: var(--cgm-border);
    opacity: 1;
}

/* ---- Accordions ---- */
.accordion-item {
    border-color: var(--cgm-border);
}

.accordion-button {
    font-weight: 600;
    color: var(--cgm-primary-dark);
    background: var(--cgm-surface-alt);
}

.accordion-button:not(.collapsed) {
    background: var(--cgm-leaf-soft);
    color: var(--cgm-primary-dark);
    box-shadow: none;
}

.accordion-button:focus {
    box-shadow: var(--cgm-focus-ring);
    border-color: var(--cgm-primary);
}

/* ---------------------------------------------------------------------- */
/* Responsive                                                              */
/* ---------------------------------------------------------------------- */
/*
   FOUR WIDTHS, AND ONE RULE THAT MATTERS MORE THAN ALL OF THEM.

   Nothing on this platform may scroll the page sideways. A government back-office screen is full of
   tables thirty columns wide, and the failure mode is always the same: one wide table drags the whole
   document horizontally, so the sidebar and the header scroll away from the content. The fix is that the
   TABLE scrolls inside its own box and the BODY never does — the two declarations at the top of this
   block — and every width below is refinement on top of that.

   Targets: desktop 1920/1440, laptop 1280, tablet 1024/768, mobile 430/375.
*/
html, body {
    overflow-x: hidden;
}

/* Wide content scrolls inside itself. Tables, code, diagrams, the AXIS payment preview. */
.table-responsive,
.overflow-scroll-x {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

/* A long unbroken run — an application number, an IFSC, an email — must wrap rather than push. */
.text-break-anywhere,
dl dd,
.card-body p {
    overflow-wrap: break-word;
}

/* ---- Laptop: 1280 and below. Trim the shell so content keeps its width. ---- */
@media (max-width: 1399.98px) {
    .app-content-header {
        padding-top: 1.1rem;
        padding-bottom: .9rem;
    }
}

/* ---- Tablet landscape and below ---- */
@media (max-width: 991.98px) {
    .app-content-header .col-sm-6:last-child {
        margin-top: .5rem;
    }

    .app-content-header .breadcrumb {
        float: none !important;
        justify-content: flex-start;
    }

    /* Stat tiles: four across becomes two, never four squeezed. */
    .stat-card .display-6 {
        font-size: var(--cgm-text-xl);
    }

    /* A button row that would wrap mid-label wraps between buttons instead. */
    .btn-toolbar, .d-flex.gap-2 {
        flex-wrap: wrap;
    }
}

/* ---- Tablet portrait / large phone ---- */
@media (max-width: 767.98px) {
    .content-header .container-fluid,
    .content .container-fluid,
    .app-content > .container-fluid,
    .app-content-header > .container-fluid {
        padding-left: 1rem;
        padding-right: 1rem;
    }

    .app-content-header h1 {
        font-size: var(--cgm-text-lg);
    }

    .stat-card .icon {
        display: none;
    }

    /* Table cells stop being nowrap, or a 30-column table becomes a 4000px scroll. */
    .table thead th {
        white-space: normal;
    }

    .table td, .table th {
        padding: .5rem .45rem;
        font-size: var(--cgm-text-sm);
    }

    /* A form laid out in two columns becomes one. */
    .card-header {
        flex-wrap: wrap;
        gap: .35rem;
    }

    /* Modals get the screen rather than a margin. */
    .modal-dialog {
        margin: .5rem;
    }

    /* Pagination: numbers stay reachable with a thumb and never overflow. */
    .pagination {
        flex-wrap: wrap;
        justify-content: center;
        row-gap: .25rem;
    }
}

/* ---- Phone ---- */
@media (max-width: 575.98px) {
    .app-card > .p-3 {
        padding: .85rem !important;
    }

    .card-body {
        padding: .85rem;
    }

    /* Full-width primary action: a 44px target is the minimum comfortable tap. */
    .btn-block-sm,
    .card-footer > .btn:only-child {
        width: 100%;
    }

    .btn, .btn-sm {
        min-height: 2.25rem;
    }

    /* A page title and its subtitle must not eat a third of a small screen. */
    .app-content-header {
        padding-top: .85rem;
        padding-bottom: .7rem;
    }

    /* Definition lists stack: a 5/7 split at 375px leaves neither side readable. */
    dl.row > dt, dl.row > dd {
        width: 100%;
        max-width: 100%;
        flex: 0 0 100%;
    }

    dl.row > dd {
        margin-bottom: .7rem;
    }
}

/* ---- Print: an officer's file copy ---- */
@media print {
    .app-sidebar, .app-header, .app-footer,
    .btn, .pagination, .public-bar, .breadcrumb {
        display: none !important;
    }

    .app-main, .app-wrapper, body {
        margin: 0 !important;
        background: #fff !important;
    }

    .app-card, .card {
        border: 1px solid #999 !important;
        box-shadow: none !important;
        break-inside: avoid;
    }

    /*
       THE ONE PLACE PURE BLACK IS CORRECT, and it is not a screen.
       Forest green on paper costs colour toner and prints as indistinct grey on the mono laser printers
       these offices actually have. A file copy an officer signs wants black ink on white.
    */
    .table thead th {
        background: #eee !important;
        color: #000 !important;
    }

    /* Links in a printed copy are dead text; underlining them only adds noise. */
    a {
        color: #000 !important;
        text-decoration: none !important;
    }
}

/* ---------------------------------------------------------------------- */
/* Public bar — the sign-in page's links for people with no account        */
/* ---------------------------------------------------------------------- */
/*
   Deep forest, full width, above everything. It reads as part of the page's
   furniture rather than as a call to action competing with Sign In, which is
   what a row of buttons there would have done.
*/
.public-bar {
    background: var(--cgm-sidebar);
    border-bottom: 3px solid var(--cgm-leaf);
    /*
       Full width explicitly. AdminLTE gives `body.login-page` a flex layout, which made this bar a flex
       item that shrank to its own content — so on a wide screen it rendered as a floating box in the middle
       of the page rather than as the page's top bar.
    */
    width: 100%;
    flex: 0 0 auto;
}

.public-bar-link {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .35rem .75rem;
    border-radius: var(--cgm-radius-sm);
    color: var(--cgm-sidebar-ink);
    font-size: .875rem;
    font-weight: 600;
    text-decoration: none;
    transition: background-color .15s ease, color .15s ease;
}

.public-bar-link:hover,
.public-bar-link:focus-visible {
    background: rgba(255, 255, 255, .1);
    color: #fff;
}

.public-bar-link:focus-visible {
    outline: 2px solid var(--cgm-leaf);
    outline-offset: 1px;
}

.public-bar-link i {
    color: var(--cgm-leaf);
}

.public-bar-link:hover i,
.public-bar-link:focus-visible i {
    color: #fff;
}

/* The login page's own ground, so the forest bar sits on something that agrees with it. */
body.login-page {
    background: linear-gradient(160deg, var(--cgm-primary-dark) 0%, var(--cgm-sidebar) 100%);
}

/* ---------------------------------------------------------------------- */
/* Declaration                                                             */
/* ---------------------------------------------------------------------- */
/*
   A person is being asked to accept legal responsibility for what they have entered. It used to be one
   line of label text beside a tick box, which does not read as that. A bordered block with a heading
   does.
*/
.declaration-block {
    background: var(--cgm-leaf-soft);
    border: 1px solid var(--cgm-border);
    border-left: 4px solid var(--cgm-leaf-dark);
    border-radius: var(--cgm-radius-sm);
    padding: var(--cgm-gap-md);
}

.declaration-block-heading {
    font-size: var(--cgm-text-sm);
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--cgm-primary-dark);
    margin-bottom: .55rem;
}

.declaration-block-text {
    font-size: var(--cgm-text-sm);
    line-height: 1.6;
    color: var(--cgm-ink);
    margin-bottom: .55rem;
}

/* The acceptance sits apart from the text it refers to, so ticking is a separate act from reading. */
.declaration-block-accept {
    margin-top: .35rem;
    padding-top: .65rem;
    border-top: 1px solid var(--cgm-border-strong);
    font-weight: 600;
}

.declaration-block-accept .form-check-label {
    color: var(--cgm-primary-dark);
}

/* ---- On the application record ---- */
.declaration-record-text {
    font-size: var(--cgm-text-sm);
    line-height: 1.6;
    color: var(--cgm-ink);
}

.declaration-record-meta {
    padding-top: .6rem;
    border-top: 1px solid var(--cgm-border);
}

/*
   In a printed file copy the declaration must be legible and must not break across pages — an officer
   signing a copy needs the undertaking and its acceptance stamp on the same sheet.
*/
@media print {
    .declaration-record,
    .declaration-block {
        break-inside: avoid;
        background: #fff !important;
        border: 1px solid #999 !important;
    }
}

/* ---------------------------------------------------------------------- */
/* Language switch, date ticker, user manual card                          */
/* ---------------------------------------------------------------------- */

/* ---- The language switch ---- */
.language-switch {
    display: inline-flex;
    align-items: center;
    gap: .15rem;
    background: rgba(255, 255, 255, .10);
    border: 1px solid rgba(255, 255, 255, .18);
    border-radius: var(--cgm-radius-pill);
    padding: .18rem .3rem;
}

.language-switch-icon {
    color: var(--cgm-sidebar-muted);
    font-size: .95rem;
    margin: 0 .2rem 0 .3rem;
}

/*
   Each option is a submit button, so it must be stripped of button chrome without losing its focus
   ring — a switch nobody can reach with a keyboard is not a switch.
*/
.language-switch-option {
    appearance: none;
    background: transparent;
    border: 0;
    border-radius: var(--cgm-radius-pill);
    padding: .22rem .6rem;
    font-size: var(--cgm-text-sm);
    font-weight: 600;
    line-height: 1.3;
    color: var(--cgm-sidebar-ink);
    cursor: pointer;
    transition: background-color .12s ease, color .12s ease;
}

.language-switch-option:hover,
.language-switch-option:focus-visible {
    background: rgba(255, 255, 255, .16);
    color: #fff;
}

/* The current language is shown, not hidden: somebody needs to see what they are already reading. */
.language-switch-option.is-current {
    background: var(--cgm-leaf);
    color: #fff;
    cursor: default;
}

/* On a light ground — the admin header — the same switch inverts. */
.app-header .language-switch,
.manual-card .language-switch {
    background: var(--cgm-leaf-soft);
    border-color: var(--cgm-border);
}

.app-header .language-switch-icon { color: var(--cgm-muted); }

.app-header .language-switch-option {
    color: var(--cgm-ink-soft);
}

.app-header .language-switch-option:hover,
.app-header .language-switch-option:focus-visible {
    background: var(--cgm-leaf-tint);
    color: var(--cgm-primary-dark);
}

.app-header .language-switch-option.is-current {
    background: var(--cgm-primary);
    color: #fff;
}

/* ---- The application-date bar: a fixed chip, not a ticker ---- */
/*
   It used to scroll. Once the administrative marquee arrived, two moving strips across the top of a
   sign-in page meant the eye had nowhere to rest and neither message got read. The date is one short fact
   that does not change within a day, so it sits still; the movement is the marquee's alone.
*/
.date-bar {
    background: var(--cgm-leaf-soft);
    border-top: 1px solid var(--cgm-border);
    border-bottom: 1px solid var(--cgm-border);
    padding: .4rem var(--cgm-gap-md);
    width: 100%;
    max-width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
}

.date-bar-item {
    font-size: var(--cgm-text-base);
    font-weight: 600;
    color: var(--cgm-primary-dark);
    letter-spacing: .01em;
    overflow-wrap: break-word;
}

/* ---- The administrative marquee ---- */
/*
   ITS OWN GEOMETRY, AND NOT THE DATE TICKER'S.

   It first reused `.date-ticker`, whose items are sized at exactly one third of the track because three
   copies are rendered there. The marquee renders TWO passes over N announcements, so with one
   announcement there were two items at 33% inside a 300% track — and on a 390px screen the two copies
   overlapped on top of each other, printing the message across itself.

   Two groups instead, each holding every announcement and each at least one viewport wide, with the track
   translating by exactly half. That loops seamlessly for one announcement or for six.
*/
.announcement-marquee {
    overflow: hidden;
    background: var(--cgm-leaf-tint);
    border-bottom: 1px solid var(--cgm-border);
    padding: .4rem 0;
    width: 100%;
    max-width: 100%;
}

.announcement-track {
    display: flex;
    width: max-content;
    animation: cgm-marquee 30s linear infinite;
}

.announcement-group {
    display: flex;
    align-items: center;
    gap: 4rem;
    padding-right: 4rem;
    /* At least a full viewport, so a single short message does not loop several times per screen. */
    min-width: 100vw;
    justify-content: center;
    flex: 0 0 auto;
}

.announcement-item {
    white-space: nowrap;
    font-size: var(--cgm-text-base);
    font-weight: 600;
    color: var(--cgm-primary-darker);
    letter-spacing: .01em;
}

@keyframes cgm-marquee {
    /* Two groups, so half the track is exactly one full pass. Count-independent. */
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}

/* Pause on hover, so somebody can read a maintenance window rather than chase it. */
.announcement-marquee:hover .announcement-track {
    animation-play-state: paused;
}

@media (prefers-reduced-motion: reduce) {
    /*
       No scroll at all. The announcements are stacked and centred instead — the information is the
       message, not the movement, and some people cannot read moving text.
    */
    .announcement-track {
        animation: none;
        width: 100%;
        flex-direction: column;
    }

    .announcement-group {
        min-width: 0;
        width: 100%;
        flex-wrap: wrap;
        gap: .35rem;
        padding-right: 0;
        row-gap: .35rem;
    }

    /* The duplicate group exists only to make the scroll seamless. */
    .announcement-group + .announcement-group {
        display: none;
    }

    .announcement-item {
        white-space: normal;
        text-align: center;
    }
}

/* On a narrow screen a long announcement must still be readable, not raced past. */
@media (max-width: 575.98px) {
    .announcement-track {
        animation-duration: 45s;
    }

    .announcement-item {
        font-size: var(--cgm-text-sm);
    }
}

/* The admin screen's preview, so it reads as a page fragment rather than a form field. */
.announcement-preview {
    border: 1px dashed var(--cgm-border-strong);
    border-radius: var(--cgm-radius-sm);
    overflow: hidden;
}

.announcement-preview .date-ticker {
    border-top: 0;
    border-bottom: 0;
}

/* ---- Announcement history ---- */
.announcement-audit {
    padding: .6rem 0;
    border-bottom: 1px solid var(--cgm-border);
}

.announcement-audit:last-child { border-bottom: 0; }

.announcement-audit-changes {
    margin: .35rem 0 0;
    padding-left: 1.1rem;
    font-size: var(--cgm-text-sm);
    color: var(--cgm-ink-soft);
}

/* ---- The application-date ticker (shared marquee geometry) ---- */
/*
   A scrolling banner, and the scroll is the only decorative thing on the page — so it is also the only
   thing that has to be switched off for somebody who cannot read moving text.
*/
.date-ticker {
    overflow: hidden;
    background: var(--cgm-leaf-soft);
    border-top: 1px solid var(--cgm-border);
    border-bottom: 1px solid var(--cgm-border);
    padding: .4rem 0;
    width: 100%;
    /* A ticker must never be the reason the page scrolls sideways. */
    max-width: 100%;
}

/*
   EACH COPY IS A FULL VIEWPORT WIDE, so only one is ever on screen.

   The first version sized each copy to its own text and laid three side by side. In motion that scrolls
   correctly; standing still on a wide screen it showed the same sentence three times across the banner,
   which reads as a rendering fault rather than a ticker. Giving each copy `min-width: 100%` means the
   track is exactly three viewports long, one sentence is visible at a time, and translating by a third
   still loops seamlessly.
*/
.date-ticker-track {
    display: flex;
    align-items: center;
    width: 300%;
    animation: cgm-ticker 22s linear infinite;
}

.date-ticker-item {
    flex: 0 0 33.3333%;
    min-width: 33.3333%;
    display: flex;
    align-items: center;
    justify-content: center;
    white-space: nowrap;
    font-size: var(--cgm-text-base);
    font-weight: 600;
    color: var(--cgm-primary-dark);
    letter-spacing: .01em;
}

@keyframes cgm-ticker {
    /*
       STARTS AT 0, NOT OFF-SCREEN RIGHT.
       Beginning at translateX(100%) meant the banner was EMPTY for the first several seconds of every
       page load, which on the one element whose whole job is to state today's date is the worst possible
       moment to say nothing. At 0 the first copy is centred and readable immediately; translating by a
       third brings the next copy into the same place, so the loop is seamless either way.
    */
    from { transform: translateX(0); }
    to   { transform: translateX(-33.3333%); }
}

.date-ticker:hover .date-ticker-track {
    /* Pause on hover so somebody can actually read the date rather than chase it. */
    animation-play-state: paused;
}

@media (prefers-reduced-motion: reduce) {
    .date-ticker-track {
        animation: none;
        width: 100%;
        transform: none;
    }

    /* The duplicates exist only to make the scroll seamless; with no scroll they are noise. */
    .date-ticker-item {
        flex: 0 0 100%;
        min-width: 100%;
    }

    .date-ticker-item + .date-ticker-item {
        display: none;
    }
}

/* ---- The user manual card ---- */
.manual-card {
    display: flex;
    align-items: flex-start;
    gap: var(--cgm-gap-md);
    background: var(--cgm-surface);
    border: 1px solid var(--cgm-border);
    border-left: 4px solid var(--cgm-leaf);
    border-radius: var(--cgm-radius);
    box-shadow: var(--cgm-shadow-sm);
    padding: var(--cgm-gap-md);
    text-align: start;
}

.manual-card-mark {
    flex: 0 0 auto;
    width: 2.75rem;
    height: 2.75rem;
    display: grid;
    place-items: center;
    border-radius: var(--cgm-radius-sm);
    background: var(--cgm-leaf-soft);
    color: var(--cgm-primary);
    font-size: 1.3rem;
}

.manual-card-body { min-width: 0; }

.manual-card-heading {
    font-size: var(--cgm-text-md);
    font-weight: 700;
    color: var(--cgm-primary-dark);
    line-height: 1.3;
}

.manual-card-intro {
    margin: .2rem 0 .65rem;
    font-size: var(--cgm-text-sm);
    color: var(--cgm-muted);
    overflow-wrap: break-word;
}

.manual-card-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--cgm-gap-sm);
}

.manual-card-meta {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
    margin-top: .5rem;
    font-size: var(--cgm-text-xs);
    color: var(--cgm-muted);
}

.manual-card-empty {
    font-size: var(--cgm-text-sm);
    color: var(--cgm-muted);
}

.manual-card-others {
    display: flex;
    flex-wrap: wrap;
    gap: var(--cgm-gap);
    margin-top: .6rem;
    padding-top: .55rem;
    border-top: 1px dashed var(--cgm-border);
}

.manual-card-others a {
    font-size: var(--cgm-text-sm);
    font-weight: 600;
    color: var(--cgm-primary);
    text-decoration: none;
}

.manual-card-others a:hover { text-decoration: underline; }

@media (max-width: 575.98px) {
    .manual-card { flex-direction: column; }
    .manual-card-actions .btn { width: 100%; }
}

/* ---------------------------------------------------------------------- */
/* Brand heading — the organisation and the scheme, in both scripts        */
/* ---------------------------------------------------------------------- */
/*
   EVERY SIZE IS FLUID. `clamp(min, preferred, max)` lets one set of markup
   read correctly from a 320px phone to a wide desktop without a breakpoint
   deciding which lines are allowed to exist — and without a hardcoded pixel
   size that breaks the moment the viewport is narrower than it assumed.

   The organisation's name is long and in two scripts. Three things keep it
   legible: `text-wrap: balance` so the last line is not one orphaned word,
   `overflow-wrap: break-word` so nothing escapes its container at any width,
   and a max width in `ch` so the line length stays readable instead of
   stretching across a 27-inch monitor.
*/
.brand-hero {
    max-width: 46ch;
    margin-inline: auto;
}

.brand-emblem {
    width: clamp(3rem, 12vw, 4.25rem);
    height: clamp(3rem, 12vw, 4.25rem);
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--cgm-primary);
    color: #fff;
    font-size: clamp(1.35rem, 5vw, 1.9rem);
    box-shadow: 0 2px 10px rgba(18, 63, 42, .28);
}

/*
   THE FEDERATION'S OWN EMBLEM, in place of the placeholder mark above.

   IT IS NOT CROPPED TO A CIRCLE, and that is the whole reason this is a separate rule rather than an
   `<img>` dropped inside `.brand-emblem`. That class draws a solid green disc with `border-radius: 50%`
   and centres a glyph on it. The federation's artwork already carries its own circular border with the
   organisation's full name set around the rim, so a CSS circle would have clipped that name into an arc
   of unreadable fragments, and the green disc would have sat behind a mark that supplies its own ground.

   `aspect-ratio` with `object-fit: contain` means a file that is not perfectly square is letterboxed and
   centred rather than stretched — a department sending a 1000x940 export gets a correct emblem, not a
   subtly ovalised one. The intrinsic width/height in the markup reserves the space before the image
   arrives, so the title beneath it does not jump on load.

   It runs materially larger than the placeholder — 68px against 44px on a phone, 112px against 68px on a
   desktop — for two compounding reasons. A glyph fills its box edge to edge, while a rimmed roundel spends
   its outermost ring on a border, so matching the boxes makes the real logo read smaller than the mark it
   replaced. And this emblem carries the organisation's full name set around that rim: at the placeholder's
   size the text ring degrades into a texture, and the one piece of information the artwork adds over a
   generic mark is the piece that disappears first.
*/
.brand-emblem-image {
    display: block;
    width: clamp(4.25rem, 18vw, 7rem);
    height: auto;
    aspect-ratio: 1;
    object-fit: contain;
}

/* A bar, sidebar or footer, alongside `.brand-compact-mark`'s footprint. */
.brand-compact-image {
    flex: 0 0 auto;
    width: 1.6rem;
    height: 1.6rem;
    aspect-ratio: 1;
    object-fit: contain;
}

/*
   The sidebar's 40px white tile. The inset keeps the roundel's rim off the tile's own rounded corners,
   which otherwise clip four small bites out of the border at exactly the size it is least forgiving.
*/
.brand-image-logo {
    width: 38px;
    height: 38px;
    aspect-ratio: 1;
    object-fit: contain;
}

/*
   NO WHITE TILE BEHIND THE REAL EMBLEM. `.brand-image` is a white rounded square, which is right for a
   single-colour glyph on a dark rail — it gives the glyph a ground to be legible against. The federation's
   emblem supplies its own cream disc, so the tile put a white SQUARE behind a CIRCLE and read as a badge
   the artwork does not have.

   A modifier class rather than `:has(.brand-image-logo)`: the selector would be tidier, but this rail is
   the first thing an officer sees on a government desktop whose browser age we do not control, and a
   `:has()` that silently no-ops leaves a white square around the logo on exactly those machines.
*/
.brand-image-plain {
    background: none;
    border-radius: 0;
}

/* The abbreviation, as a caption under the mark. Never the title. */
.brand-abbreviation {
    margin-top: .4rem;
    font-size: clamp(.68rem, 2vw, .78rem);
    font-weight: 700;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--cgm-muted);
}

/*
   THE PLATFORM TITLE IS THE PRIMARY LINE, and the organisation sits beneath it.

   The order was the other way round and the organisation's hundred-character name dominated a page it
   was not the subject of. `-primary` and `-secondary` rather than `-hi` and `-en`, because which script
   comes first now depends on the language being read — the class describes the ROLE, not the language,
   so the styling does not have to be duplicated per locale.
*/
.brand-platform-primary {
    margin: .55rem 0 .2rem;
    font-size: clamp(1.05rem, 4.2vw, 1.4rem);
    font-weight: 700;
    line-height: 1.32;
    color: var(--cgm-primary-dark);
    text-wrap: balance;
    overflow-wrap: break-word;
    /* Never truncated. A government platform's own name is not an ellipsis. */
    max-width: 46ch;
    margin-left: auto;
    margin-right: auto;
}

.brand-platform-secondary {
    margin: 0;
    font-size: clamp(.88rem, 3vw, 1.02rem);
    font-weight: 600;
    line-height: 1.35;
    color: var(--cgm-primary);
    text-wrap: balance;
    overflow-wrap: break-word;
    max-width: 46ch;
    margin-left: auto;
    margin-right: auto;
}

/* A leaf-green rule: the platform above it, the organisation that runs it below. */
.brand-rule {
    width: clamp(3rem, 20%, 5rem);
    margin: .85rem auto;
    border: 0;
    border-top: 2px solid var(--cgm-leaf);
    opacity: 1;
}

.brand-organisation-primary {
    margin: 0 auto .15rem;
    font-size: clamp(.85rem, 2.9vw, .98rem);
    font-weight: 600;
    line-height: 1.4;
    color: var(--cgm-ink-soft);
    text-wrap: balance;
    overflow-wrap: break-word;
    max-width: 46ch;
}

.brand-organisation-secondary {
    margin: 0 auto;
    font-size: clamp(.76rem, 2.5vw, .86rem);
    font-weight: 500;
    line-height: 1.4;
    color: var(--cgm-muted);
    text-wrap: balance;
    overflow-wrap: break-word;
    max-width: 46ch;
}

/* ---- Compact: a top bar, a sidebar, a footer ---- */
.brand-compact {
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    min-width: 0;
}

.brand-compact-mark {
    color: var(--cgm-primary);
    font-size: 1.1rem;
    flex: 0 0 auto;
}

.brand-compact-text {
    display: flex;
    flex-direction: column;
    line-height: 1.15;
    min-width: 0;
}

.brand-compact-platform {
    font-size: clamp(.8rem, 2.2vw, .95rem);
    font-weight: 700;
    color: var(--cgm-ink);
    /* One line in a bar; the full name is on the sign-in page and in the footer. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.brand-compact-caption {
    font-size: .66rem;
    font-weight: 700;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--cgm-muted);
}

/* The sidebar's own ground is dark, so the compact block inverts there. */
.sidebar-brand .brand-compact-platform,
.app-sidebar .brand-compact-platform { color: var(--cgm-sidebar-ink); }
.sidebar-brand .brand-compact-caption,
.app-sidebar .brand-compact-caption { color: rgba(255, 255, 255, .62); }
.sidebar-brand .brand-compact-mark,
.app-sidebar .brand-compact-mark { color: var(--cgm-leaf); }

/*
   IN THE SIDEBAR THE NAME WRAPS, IT DOES NOT CLIP.

   `.brand-compact-platform` is nowrap-with-ellipsis, which is right in a horizontal bar where there is
   always more width to be had. The sidebar is a fixed 250px and the scheme name is 37 characters, so
   nowrap ran it straight off the edge — the rail showed "Tendu Leaves Collector Welfare Sche" cut
   mid-word, with no ellipsis, because the overflow left the sidebar rather than the element.

   Two lines, clamped, and the brand block given the height to hold them. Truncating the department's own
   scheme name in its own navigation is not an option the brief allows.
*/
.app-sidebar .brand-compact,
.app-sidebar .brand-link {
    max-width: 100%;
    overflow: hidden;
}

.app-sidebar .brand-compact-platform {
    white-space: normal;
    text-overflow: clip;
    display: -webkit-box;
    /*
       THREE, not two. The name is "CGMFPFED Tendu Leaf Collectors' Welfare Platform" and at .82rem in a
       250px rail it takes three lines; clamped at two it lost the word "Platform" — and the point of this
       whole block is that the department's own name is not truncated in its own navigation. The clamp stays
       as the guard it was meant to be, one line looser, so a longer name in a future deployment is bounded
       instead of spilling down the rail.
    */
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    font-size: .82rem;
    line-height: 1.25;
}

.app-sidebar .brand-link {
    min-height: 68px;
    align-items: center;
}

/*
   ...AND THE BRAND BLOCK ITSELF HAS TO ALLOW THE SECOND LINE, which is why the wrap above was invisible
   even once the right class was on the right element. AdminLTE sets `.sidebar-brand { height: 3.5rem;
   overflow: hidden }` — a hard 56px with clipping — while `.brand-link` above reserves 68px inside it. The
   twelve-pixel difference is the second line of the name, cut off by a parent that was never told the block
   grew. `height: auto` with a floor rather than a taller fixed height, so a shorter name in a future
   deployment does not leave a band of empty rail.
*/
.sidebar-brand {
    height: auto;
    min-height: 4.25rem;
}

/* Collapsed rail: the mark alone, so nothing spills. */
.sidebar-collapse .app-sidebar .brand-compact-text {
    display: none;
}
