/* ═══════════════════════════════════════════════════════════════════════════
   AE Planet UI — the brand design system (September 2026)

   One stylesheet for every staff screen. It is loaded by layouts/admin.blade.php
   AFTER Bootstrap and the Vite bundle and BEFORE each page's @push('styles'),
   so a page can still override anything here with a rule of equal specificity.

   This was a light system until September 2026, when the owner asked for the
   CRM to look like aeplanet.com — "full cinematic, everywhere". The structure
   did not change; the tokens did. That was only possible because the light
   conversion had already moved every colour out of the views and into this
   file, and BrandSystemTest kept it that way.

   Rules of the house (see docs/UI-SYSTEM.md):
     • colours come from the tokens below, never from literals in a view;
     • the only colours that exist are the 2024 brand six — purple #62219B,
       magenta #CC64D2, periwinkle #6F71C2, lavender #AFAEDC, black, white —
       blended over black, plus a named semantic set for good/warn/critical;
     • purple is a FILL, never a glyph: it is 2.2:1 on this canvas. Text that
       wants the accent uses --ae-accent-text, which is magenta at 6.3:1;
     • the legacy names (.ae-page-card, .ae-table, .ae-btn-primary, .section-title…)
       keep working — they are re-skinned here, not renamed;
     • --purple/--gold/--pink/--teal survive as aliases, all mapped onto the
       brand, so a rule nobody has converted yet degrades to something on-palette.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
    /* ── The brand, and only the brand ──────────────────────────────────────
       The 2024 guidelines permit six colours and forbid the rest: purple
       #62219B, magenta #CC64D2, periwinkle #6F71C2, lavender #AFAEDC, black
       and white. Every surface below is one of those blended over black, so
       the CRM and aeplanet.com are demonstrably the same object.

       Semantic colour is the one deliberate exception. Good / warning /
       critical must not be a brand decision — a failed debit order has to
       read as failed whatever the palette says — so those hues stay outside
       the six and are tuned for legibility on a dark ground. */
    --brand-purple:     #62219b;
    --brand-magenta:    #cc64d2;
    --brand-peri:       #6f71c2;
    --brand-lav:        #afaedc;

    /* Canvas + surfaces: purple over black, climbing in 5% steps. */
    --ae-bg:            #05030a;
    --ae-surface:       #0e0817;
    --ae-surface-2:     #150e22;
    --ae-surface-3:     #1d142e;
    --ae-border:        #271c3c;
    --ae-border-strong: #382a54;

    /* Text. Lavender is the muted tone because it is both brand and 9.9:1 on
       the canvas — the rare case where the palette hands you the right answer. */
    --ae-text:          #ffffff;
    --ae-text-2:        #e4e0f0;   /* 16.2:1 on --ae-surface */
    --ae-muted:         #afaedc;   /* 9.9:1 on --ae-bg, 9.0:1 on --ae-surface-3 */
    --ae-faint:         #837fa6;   /* 4.6:1 — placeholders and timestamps only */

    /* The accent. Purple stays the brand and the fill, but it is 2.2:1 on this
       canvas, so it must never carry a glyph: --ae-accent-text is magenta,
       which is 6.3:1. Getting this wrong is the single easiest way to make the
       dark CRM unreadable. */
    --ae-accent:        #62219b;   /* white text on this = 9.5:1 */
    --ae-accent-hover:  #7c2cc4;   /* lifts on hover rather than sinking, as it did on white */
    --ae-accent-text:   #cc64d2;   /* 6.3:1 on the canvas, 5.6:1 on --ae-surface-3 */
    --ae-accent-soft:   rgba(98, 33, 155, .26);
    --ae-accent-ring:   rgba(204, 100, 210, .38);

    /* Semantic — outside the six on purpose (see above), lifted for dark. */
    --ae-success:       #4ade80;   /* 10.5:1 on the canvas */
    --ae-success-soft:  rgba(74, 222, 128, .15);
    --ae-warning:       #fbbf24;   /* 11.4:1 */
    --ae-warning-soft:  rgba(251, 191, 36, .15);
    --ae-danger:        #f87171;   /* fills and icons */
    --ae-danger-text:   #fca5a5;   /* 8.4:1 — red words that still read as red */
    --ae-danger-soft:   rgba(248, 113, 113, .15);
    --ae-info:          #8b8dd6;   /* periwinkle, lifted to 6.4:1 */
    --ae-info-soft:     rgba(111, 113, 194, .18);

    /* Brand gold is NOT in the 2024 palette. The token survives because older
       rules reference it, and it is mapped onto the brand so a forgotten rule
       degrades to something on-brand rather than reintroducing a seventh hue. */
    --ae-brand-gold:    var(--brand-lav);

    /* Identity / series palette. Same six, in the same order, as
       window.AE_CHART_COLORS in layouts/admin.blade.php: use these when several
       things need telling apart and none of them means good, bad or urgent.
       Brand-first, then two neutral steps, all legible on the dark canvas.
       Colour is never the only signal — the label sits next to the swatch. */
    --ae-viz-1: #cc64d2;
    --ae-viz-2: #6f71c2;
    --ae-viz-3: #afaedc;
    --ae-viz-4: #9b4dd6;
    --ae-viz-5: #f0a6f5;
    --ae-viz-6: #5b5ea8;

    /* Tinted borders, for a card that carries a status without shouting */
    --ae-accent-border:  rgba(204, 100, 210, .42);
    --ae-success-border: rgba(74, 222, 128, .38);
    --ae-warning-border: rgba(251, 191, 36, .38);
    --ae-danger-border:  rgba(248, 113, 113, .38);
    --ae-info-border:    rgba(111, 113, 194, .45);
    --ae-accent-soft-hover: rgba(98, 33, 155, .38);
    --ae-accent-tint:   #5b3d78;   /* "not the current one": past periods, inactive bars */

    /* Cinematic layer — the gradient, glass and glow the public site uses.
       Kept as tokens so a screen opts in by name instead of inventing its own. */
    --ae-grad:          linear-gradient(100deg, #62219b, #cc64d2 38%, #6f71c2 72%, #afaedc);
    --ae-grad-text:     linear-gradient(100deg, #cc64d2, #6f71c2 45%, #afaedc);
    --ae-ring-grad:     conic-gradient(from 210deg, #62219b, #cc64d2, #6f71c2, #afaedc, #62219b);
    --ae-glass:         rgba(255, 255, 255, .045);
    --ae-glass-2:       rgba(255, 255, 255, .075);
    --ae-hairline:      rgba(255, 255, 255, .10);
    --ae-glow:          0 0 0 1px rgba(204, 100, 210, .22), 0 18px 48px rgba(98, 33, 155, .28);

    /* Shape + depth. A drop shadow does nothing on black, so elevation is
       carried by surface step and hairline, and the shadows only deepen. */
    --ae-radius:        12px;
    --ae-radius-sm:     8px;
    --ae-radius-xs:     6px;
    --ae-shadow-sm:     0 1px 2px rgba(0, 0, 0, .55);
    --ae-shadow:        0 12px 34px rgba(0, 0, 0, .55);
    --ae-shadow-lg:     0 34px 80px rgba(0, 0, 0, .7);

    --sidebar-w:        256px;
    --topbar-h:         64px;

    /* Legacy aliases — old inline rules still reference these. Every one is
       mapped onto the brand so a rule nobody has converted yet degrades to
       something on-palette and legible on dark. */
    --purple:    var(--ae-accent);
    --pink:      var(--brand-magenta);
    --gold:      var(--brand-lav);
    --teal:      var(--brand-peri);
    --dark:      var(--ae-surface);
    --ae-purple: var(--ae-accent);
    --ae-gold:   var(--brand-lav);
    --ae-pink:   var(--brand-magenta);
    --ae-lav:    var(--brand-lav);
    --ae-dark:   var(--ae-surface);

    /* Names the redesigned workspaces already use */
    --ws-text:   var(--ae-text);
    --ws-muted:  var(--ae-muted);
    --ws-border: var(--ae-border);
}

/* ── Base ──────────────────────────────────────────────────────────────── */
html { color-scheme: dark; scroll-behavior: smooth; }
*, *::before, *::after { box-sizing: border-box; }
html, body { max-width: 100%; overflow-x: hidden; }
body {
    margin: 0;
    min-height: 100vh;
    background: var(--ae-bg);
    color: var(--ae-text);
    font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
    font-size: .9rem;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    font-feature-settings: 'cv11', 'ss01';
}
h1, h2, h3, h4, h5, h6 { color: var(--ae-text); font-weight: 600; letter-spacing: -.015em; }
a { color: var(--ae-accent-text); text-decoration: none; }
a:hover { color: var(--ae-accent-hover); }
hr { border-color: var(--ae-border); opacity: 1; }
code, kbd, pre, .mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
code { color: var(--ae-text-2); background: var(--ae-surface-3); border-radius: 4px; padding: .1em .35em; font-size: .85em; }
:focus-visible { outline: 2px solid var(--ae-accent); outline-offset: 3px; border-radius: 4px; }
::selection { background: var(--ae-accent-soft); color: var(--ae-text); }
[hidden] { display: none !important; }
a, button, input, select, textarea, summary { -webkit-tap-highlight-color: transparent; }
img, svg, video, canvas, iframe { max-width: 100%; }
.mesh-bg-fixed { display: none; }
.tabular, .ae-num, .ae-kpi-value, td.num, .ae-table .num { font-variant-numeric: tabular-nums; }
/* The Vite bundle's preflight sets list-style:none on every ol/ul, so numbered
   procedures (the training guide's steps, the mailbox explainer) lost their markers.
   Restore them for prose inside the page, and leave navigation lists alone. */
.content-area ol:not([class]), .content-area ul:not([class]), .ae-prose ol, .ae-prose ul,
.ae-note ol, .ae-note ul, .ae-page-card ol:not([class]), .ae-page-card ul:not([class]) {
    list-style: revert; padding-left: 1.4rem; margin-bottom: .8rem;
}
.content-area ol:not([class]) li, .content-area ul:not([class]) li, .ae-prose li { margin-bottom: .25rem; }

/* Skip link */
.ws-skip { position: fixed; left: calc(var(--sidebar-w) + 16px); top: -60px; z-index: 2000; padding: 10px 16px; border-radius: var(--ae-radius-sm); background: var(--ae-accent); color: #fff; font-weight: 600; box-shadow: var(--ae-shadow); }
.ws-skip:focus { top: 12px; }

/* ── Surfaces ──────────────────────────────────────────────────────────── */
.ae-glass, .ae-card, .ae-page-card, .ae-glass-deep,
.glass-card, .dashboard-card, .stat-card, .kpi-card, .metric-card, .summary-card,
.report-card, .settings-card, .donor-card, .profile-card, .widget-card, .filter-card {
    background: var(--ae-surface);
    border: 1px solid var(--ae-border);
    border-radius: var(--ae-radius);
    box-shadow: var(--ae-shadow-sm);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    color: var(--ae-text);
}
.ae-card { padding: 1.25rem 1.4rem; }
.ae-page-card { padding: 1.5rem 1.6rem; }
.ae-glass-deep { background: var(--ae-surface-2); box-shadow: none; }
.content-area, .ae-page-card, .ae-card { overflow-wrap: anywhere; }

/* ── Type helpers ──────────────────────────────────────────────────────── */
.section-title, .ae-card-title { font-size: .98rem; font-weight: 600; color: var(--ae-text); margin: 0; letter-spacing: -.01em; }
.section-sub, .ae-text-muted, .ae-page-subtitle, .ae-muted, .muted, .text-muted { color: var(--ae-muted) !important; }
.section-sub { font-size: .8rem; }
.ae-page-header { margin-bottom: 1.4rem; }
.ae-page-title { font-size: 1.5rem; font-weight: 650; color: var(--ae-text); letter-spacing: -.03em; line-height: 1.15; margin: 0; }
.ae-page-subtitle { font-size: .86rem; margin-top: .3rem; }
.ae-card-header { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .6rem 1rem; margin-bottom: 1.1rem; }
.ae-card-header > :first-child { min-width: min(100%, 12rem); }
.ae-card-title.ae-card-title--accent { display: flex; align-items: center; gap: .55rem; }
.ae-card-title--accent::before { content: ''; width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: var(--ae-accent); box-shadow: 0 0 0 3px var(--ae-accent-soft); }
.ae-eyebrow { display: inline-flex; align-items: center; gap: .45rem; font-size: .68rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--ae-muted); }
.ae-label, .form-label {
    display: block; font-size: .72rem; font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
    color: var(--ae-muted); margin-bottom: .4rem;
}

/* ── Tables ────────────────────────────────────────────────────────────── */
.ae-table, .table, .data-table, .records-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: .84rem; color: var(--ae-text-2); margin-bottom: 0; }
.ae-table thead tr, .table thead tr, .data-table thead tr { background: var(--ae-surface-2); }
.ae-table thead th, .table thead th, .data-table thead th {
    padding: .7rem 1rem; font-weight: 600; font-size: .68rem; text-transform: uppercase; letter-spacing: .07em;
    color: var(--ae-muted); border-bottom: 1px solid var(--ae-border); background: var(--ae-surface-2); white-space: nowrap;
}
.ae-table thead th:first-child { border-radius: var(--ae-radius-sm) 0 0 0; }
.ae-table thead th:last-child  { border-radius: 0 var(--ae-radius-sm) 0 0; }
.ae-table tbody tr, .table tbody tr { background: transparent; transition: background .12s; }
.ae-table tbody tr:nth-child(even), .table tbody tr:nth-child(even) { background: transparent; }
.ae-table tbody tr:hover, .table tbody tr:hover, .table-hover tbody tr:hover { background: var(--ae-surface-2); }
.ae-table tbody td, .table tbody td, .data-table tbody td { padding: .78rem 1rem; border-bottom: 1px solid var(--ae-border); color: var(--ae-text-2); vertical-align: middle; background: transparent; box-shadow: none; }
.ae-table tbody tr:last-child td { border-bottom: none; }
.ae-table td, .ae-table th { vertical-align: middle; white-space: nowrap; }
/* A cell holding a sentence: wraps, and keeps a floor so it cannot be squeezed to one
   character per line by its nowrap siblings. Never set white-space:normal on its own. */
.ae-table td.ae-cell-wrap, .ae-table th.ae-cell-wrap, .ae-cell-wrap { white-space: normal; min-width: 14rem; overflow-wrap: anywhere; }
.ae-table td.ae-cell-wrap-sm, .ae-cell-wrap-sm { white-space: normal; min-width: 9rem; overflow-wrap: anywhere; }
.ae-table td strong, .ae-table td b, .table td strong { color: var(--ae-text); font-weight: 600; }
.table > :not(caption) > * > * { background: transparent; color: inherit; border-bottom-color: var(--ae-border); }
.table-striped > tbody > tr:nth-of-type(odd) > * { background: var(--ae-surface-2); color: inherit; }
/* Bootstrap dark/colour tables were used to sit on the old dark page; they are plain light tables now. */
.table-dark, .table-dark > :not(caption) > * > *, .table-primary, .table-secondary, .table-light > :not(caption) > * > * { --bs-table-bg: var(--ae-surface); --bs-table-color: var(--ae-text-2); --bs-table-border-color: var(--ae-border); --bs-table-striped-bg: var(--ae-surface-2); --bs-table-striped-color: var(--ae-text-2); --bs-table-hover-bg: var(--ae-surface-2); --bs-table-hover-color: var(--ae-text); background: var(--ae-surface); color: var(--ae-text-2); border-color: var(--ae-border); }
.table-dark thead th, .table-dark th { background: var(--ae-surface-2); color: var(--ae-muted); }
.table-responsive { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.ae-table-wrap { border: 1px solid var(--ae-border); border-radius: var(--ae-radius-sm); overflow: auto; background: var(--ae-surface); }
.ae-table-wrap .ae-table thead th:first-child, .ae-table-wrap .ae-table thead th:last-child { border-radius: 0; }
/* ── Colouring one cell, and links inside cells ──────────────────────────────
   `.ae-table tbody td` above is specificity 0-1-2, so a page's own `.my-cell`
   rule (0-1-0) loses to it however late it is loaded — which made four rules on
   the Netcash reconciliation page inert, and printed a reversal deduction, a gross
   receipt and a qualifying certificate amount in the same grey. Use these instead
   of inventing a class, or qualify your own as `.ae-table tbody td.my-cell`. */
.ae-table tbody td.is-accent, .table tbody td.is-accent { color: var(--ae-accent-text); font-weight: 650; }
.ae-table tbody td.is-danger, .table tbody td.is-danger { color: var(--ae-danger-text); }
.ae-table tbody td.is-success, .table tbody td.is-success { color: var(--ae-success); }
.ae-table tbody td.is-warn, .table tbody td.is-warn { color: var(--ae-warning); }
.ae-table tbody td.is-muted, .table tbody td.is-muted { color: var(--ae-muted); }
/* A link in a cell has to look like one. It keeps the accent and carries a dotted
   underline that firms up on hover; buttons and badges that happen to be anchors are
   excluded. And a <strong> inside the link inherits, because the cell rule for bold
   text would otherwise repaint it and leave the commission drill-down looking like
   static text — no colour, no underline, no hover. */
.ae-table tbody td a:not([class*="btn"]):not([class*="badge"]), .table tbody td a:not([class*="btn"]):not([class*="badge"]) {
    color: var(--ae-accent-text);
    text-decoration: underline dotted var(--ae-accent-border);
    text-underline-offset: 3px;
}
.ae-table tbody td a:not([class*="btn"]):not([class*="badge"]):hover, .table tbody td a:not([class*="btn"]):not([class*="badge"]):hover {
    color: var(--ae-accent-hover);
    text-decoration: underline solid currentColor;
}
.ae-table tbody td a strong, .ae-table tbody td a b, .table tbody td a strong, .table tbody td a b { color: inherit; }

/* ── Forms ─────────────────────────────────────────────────────────────── */
.ae-form-control, .ae-form-select, .ae-input, textarea.ae-input, select.ae-input,
.form-control, .form-select, .form-input, .form-textarea,
input[type=text], input[type=email], input[type=number], input[type=password], input[type=search],
input[type=tel], input[type=url], input[type=date], input[type=month], input[type=time], input[type=datetime-local], textarea, select {
    display: block; width: 100%;
    padding: .55rem .8rem;
    background: var(--ae-surface);
    border: 1px solid var(--ae-border-strong);
    border-radius: var(--ae-radius-sm);
    color: var(--ae-text);
    font-size: .875rem; font-family: inherit; line-height: 1.4;
    transition: border-color .15s, box-shadow .15s;
    outline: none; appearance: none; -webkit-appearance: none;
    box-shadow: none;
}
input[type=checkbox], input[type=radio], input[type=range], input[type=submit], input[type=button], input[type=hidden] { display: inline-block; width: auto; appearance: auto; -webkit-appearance: auto; border: 0; padding: 0; background: transparent; }
/* A swatch needs a real box. width:auto collapsed it to a hairline in Chrome. */
input[type=color] { display: inline-block; width: 3rem; height: 2.1rem; padding: 2px; appearance: auto; -webkit-appearance: auto; background: var(--ae-surface); border: 1px solid var(--ae-border-strong); border-radius: var(--ae-radius-xs); cursor: pointer; }
.form-check-input { display: inline-block; width: 1em; height: 1em; border: 1px solid var(--ae-border-strong); background-color: var(--ae-surface); }
.form-check-input:checked { background-color: var(--ae-accent); border-color: var(--ae-accent); }
.form-check-input:focus { box-shadow: 0 0 0 3px var(--ae-accent-ring); border-color: var(--ae-accent); }
.form-switch .form-check-input { width: 2em; }
textarea.ae-input, textarea.form-control, textarea { min-height: 92px; resize: vertical; }
.ae-form-control::placeholder, .ae-input::placeholder, .form-control::placeholder, input::placeholder, textarea::placeholder { color: var(--ae-faint); opacity: 1; }
.ae-form-control:focus, .ae-form-select:focus, .ae-input:focus, .form-control:focus, .form-select:focus, input:focus, textarea:focus, select:focus {
    border-color: var(--ae-accent); box-shadow: 0 0 0 3px var(--ae-accent-ring); background: var(--ae-surface); color: var(--ae-text);
}
.ae-input.is-invalid, .form-control.is-invalid, .is-invalid { border-color: var(--ae-danger) !important; }
.invalid-feedback, .text-danger { color: var(--ae-danger) !important; }
.ae-form-select, select.ae-input, select, .form-select {
    /* The chevron is stroked in lavender so it reads on the dark field. */
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none' stroke='%23afaedc' stroke-width='1.6'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right .7rem center; padding-right: 2.1rem;
}
select[multiple], select[size] { background-image: none; padding-right: .8rem; }
.ae-form-select option, select.ae-input option, select option { background: var(--ae-surface); color: var(--ae-text); }
input.ae-input[type=file], input.form-control[type=file] { display: block; width: 100%; padding: .4rem .6rem; border: 1px solid var(--ae-border-strong); border-radius: var(--ae-radius-sm); background: var(--ae-surface); color: var(--ae-muted); }
input[type=file]::file-selector-button { background: var(--ae-accent-soft); border: 0; color: var(--ae-accent-text); border-radius: 6px; padding: .3rem .8rem; margin-right: .75rem; cursor: pointer; font-weight: 600; font-size: .8rem; font-family: inherit; }
.input-group-text { background: var(--ae-surface-2); border-color: var(--ae-border-strong); color: var(--ae-muted); }
.form-text { color: var(--ae-muted); }
fieldset { border: 0; padding: 0; min-width: 0; }
legend { color: var(--ae-text); font-weight: 600; font-size: 1rem; }
.form-check-label { color: var(--ae-text-2); }

/* ── Buttons ───────────────────────────────────────────────────────────── */
.ae-btn, .ae-btn-primary, .ae-btn-secondary, .ae-btn-danger, .ae-btn-outline, .ae-btn-success, .ae-btn-warning,
.btn { display: inline-flex; align-items: center; justify-content: center; gap: .45rem; padding: .52rem 1rem; border-radius: var(--ae-radius-sm); font-size: .84rem; font-weight: 600; font-family: inherit; line-height: 1.3; cursor: pointer; text-decoration: none; border: 1px solid transparent; transition: background .15s, border-color .15s, color .15s, box-shadow .15s; box-shadow: none; white-space: nowrap; }
.ae-btn, .ae-btn-secondary, .btn-secondary, .btn-light, .btn-outline-secondary, .btn-ghost, .action-btn { background: var(--ae-surface); border-color: var(--ae-border-strong); color: var(--ae-text-2); }
.ae-btn:hover, .ae-btn-secondary:hover, .btn-secondary:hover, .btn-light:hover, .btn-outline-secondary:hover, .btn-ghost:hover, .action-btn:hover { background: var(--ae-surface-3); border-color: var(--ae-border-strong); color: var(--ae-text); }
.ae-btn-primary, .btn-primary, .btn-success, .consent-btn, .btn-download { background: var(--ae-accent); border-color: var(--ae-accent); color: #fff; }
.ae-btn-primary:hover, .btn-primary:hover, .btn-success:hover, .consent-btn:hover, .btn-download:hover, .ae-btn-primary:focus, .btn-primary:focus { background: var(--ae-accent-hover); border-color: var(--ae-accent-hover); color: #fff; transform: none; }
.ae-btn-primary:active, .btn-primary:active { background: var(--ae-accent-hover); border-color: var(--ae-accent-hover); color: #fff; transform: none; }
.ae-btn-outline, .btn-outline-primary { background: transparent; border-color: var(--ae-border-strong); color: var(--ae-text-2); }
.ae-btn-outline:hover, .btn-outline-primary:hover { background: var(--ae-surface-3); color: var(--ae-text); border-color: var(--ae-border-strong); }
.ae-btn-danger, .btn-danger, .btn-outline-danger { background: var(--ae-danger-soft); border-color: var(--ae-danger-border); color: var(--ae-danger-text); }
.ae-btn-danger:hover, .btn-danger:hover, .btn-outline-danger:hover { background: rgba(248,113,113,.26); color: #fff; border-color: var(--ae-danger); }
.ae-btn-warning, .btn-warning, .btn-outline-warning { background: var(--ae-warning-soft); border-color: var(--ae-warning-border); color: var(--ae-warning); }
.ae-btn-warning:hover, .btn-warning:hover, .btn-outline-warning:hover { background: rgba(251,191,36,.26); color: #fff; border-color: var(--ae-warning); }
.btn-info, .btn-outline-info { background: var(--ae-info-soft); border-color: var(--ae-info-border); color: var(--ae-info); }
.btn-info:hover, .btn-outline-info:hover { background: rgba(111,113,194,.3); color: #fff; border-color: var(--ae-info); }
.btn-dark { background: var(--ae-surface-3); border-color: var(--ae-border-strong); color: var(--ae-text); }
.btn-link { background: transparent; border-color: transparent; color: var(--ae-accent-text); padding-left: .25rem; padding-right: .25rem; }
.ae-btn-sm, .btn-sm { padding: .34rem .7rem; font-size: .76rem; border-radius: var(--ae-radius-xs); }
.ae-btn-lg, .btn-lg { padding: .7rem 1.4rem; font-size: .95rem; }
.ae-btn:disabled, .ae-btn[disabled], .btn:disabled, .btn.disabled, .ae-btn-primary:disabled, .ae-btn-primary[disabled], .ae-btn-secondary[disabled], .ae-btn-danger[disabled] { opacity: .5; cursor: not-allowed; transform: none; box-shadow: none; }
.ae-btn-icon { width: 34px; height: 34px; padding: 0; }
/* Bootstrap's close glyph is a black SVG; on dark it has to be inverted or it
   disappears into the panel it is meant to close. */
.btn-close { filter: invert(1) grayscale(1) brightness(2); opacity: .7; }
.btn-close:hover { opacity: 1; }
.btn-check:checked + .btn { background: var(--ae-accent-soft); border-color: var(--ae-accent); color: var(--ae-accent-text); }

/* ── Badges + chips ────────────────────────────────────────────────────── */
.ae-badge, .badge, .status-badge, .pill, .tag,
.ae-badge-success, .ae-badge-warning, .ae-badge-danger, .ae-badge-info, .ae-badge-neutral, .ae-badge-accent {
    display: inline-flex; align-items: center; gap: .3rem; padding: .22rem .6rem; border-radius: 999px;
    font-size: .7rem; font-weight: 600; line-height: 1.2; letter-spacing: .01em; white-space: nowrap;
    background: var(--ae-surface-3); color: var(--ae-text-2); border: 1px solid transparent;
}
.ae-badge-success, .badge-success, .status-success, .status-active, .status-paid, .status-approved, .text-bg-success, .badge.bg-success { background: var(--ae-success-soft) !important; color: var(--ae-success) !important; }
.ae-badge-warning, .badge-warning, .status-warning, .status-pending, .status-draft, .text-bg-warning, .badge.bg-warning { background: var(--ae-warning-soft) !important; color: var(--ae-warning) !important; }
.ae-badge-danger, .badge-danger, .status-danger, .status-failed, .status-rejected, .status-cancelled, .text-bg-danger, .badge.bg-danger { background: var(--ae-danger-soft) !important; color: var(--ae-danger-text) !important; }
.ae-badge-info, .badge-info, .status-info, .status-processing, .text-bg-info, .text-bg-primary, .badge.bg-info, .badge.bg-primary { background: var(--ae-info-soft) !important; color: var(--ae-info) !important; }
.ae-badge-accent { background: var(--ae-accent-soft); color: var(--ae-accent-text); }
.ae-badge-neutral, .badge.bg-secondary, .text-bg-secondary, .badge.bg-light, .text-bg-light, .badge.bg-dark, .text-bg-dark { background: var(--ae-surface-3) !important; color: var(--ae-text-2) !important; }
.ae-chip { display: inline-flex; align-items: center; gap: .4rem; padding: .3rem .7rem; border: 1px solid var(--ae-border); border-radius: 999px; background: var(--ae-surface); color: var(--ae-text-2); font-size: .76rem; font-weight: 500; }
.ae-chip strong { color: var(--ae-text); font-weight: 650; }
.ae-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ae-accent); display: inline-block; }
/* is-success was missing while the other four existed, so a green status dot fell
   back to the accent and rendered purple. The donor directory hit it. */
.ae-dot.is-success { background: var(--ae-success); } .ae-dot.is-warn { background: var(--ae-warning); } .ae-dot.is-danger { background: var(--ae-danger); } .ae-dot.is-info { background: var(--ae-info); } .ae-dot.is-muted { background: var(--ae-faint); }

/* ── Alerts, toasts ────────────────────────────────────────────────────── */
.alert { border-radius: var(--ae-radius-sm); border: 1px solid var(--ae-border); background: var(--ae-surface); color: var(--ae-text-2); }
.alert-success { background: var(--ae-success-soft); border-color: var(--ae-success-border); color: var(--ae-success); }
.alert-warning { background: var(--ae-warning-soft); border-color: var(--ae-warning-border); color: var(--ae-warning); }
.alert-danger  { background: var(--ae-danger-soft);  border-color: var(--ae-danger-border); color: var(--ae-danger-text); }
.alert-info, .alert-primary { background: var(--ae-info-soft); border-color: var(--ae-info-border); color: var(--ae-info); }
.ae-note { display: flex; gap: .7rem; align-items: flex-start; padding: .8rem 1rem; border-radius: var(--ae-radius-sm); border: 1px solid var(--ae-border); background: var(--ae-surface-2); color: var(--ae-text-2); font-size: .84rem; }
.ae-note.is-warn { background: var(--ae-warning-soft); border-color: var(--ae-warning-border); color: var(--ae-warning); }
.ae-note.is-danger { background: var(--ae-danger-soft); border-color: var(--ae-danger-border); color: var(--ae-danger-text); }
.ae-note.is-success { background: var(--ae-success-soft); border-color: var(--ae-success-border); color: var(--ae-success); }
.ae-note.is-info { background: var(--ae-info-soft); border-color: var(--ae-info-border); color: var(--ae-info); }

/* Bottom-right: the old top-right position covered the primary action on any page
   whose header put a button there (it hid "Show them" on the fundraiser lead card). */
.toast-zone { position: fixed; bottom: 20px; right: 20px; z-index: 9999; display: flex; flex-direction: column; align-items: flex-end; min-width: 320px; max-width: 420px; pointer-events: none; }
.toast-item { display: flex; align-items: flex-start; gap: .65rem; margin-bottom: .55rem; padding: .85rem 1rem; border-radius: var(--ae-radius-sm); border: 1px solid var(--ae-border); background: var(--ae-surface); color: var(--ae-text); font-size: .86rem; font-weight: 500; box-shadow: var(--ae-shadow-lg); pointer-events: all; animation: toastSlideIn .3s cubic-bezier(.34, 1.56, .64, 1); border-left-width: 4px; }
.toast-item.success { border-left-color: var(--ae-success); } .toast-item.success .toast-icon { color: var(--ae-success); }
.toast-item.error   { border-left-color: var(--ae-danger); }  .toast-item.error .toast-icon { color: var(--ae-danger); }
.toast-item.warning { border-left-color: var(--ae-warning); }           .toast-item.warning .toast-icon { color: var(--ae-warning); }
.toast-item .toast-icon { flex-shrink: 0; margin-top: 1px; line-height: 1; display: inline-flex; }
.toast-item .toast-close { background: none; border: none; color: var(--ae-muted); cursor: pointer; font-size: 1.1rem; padding: 0; margin-left: auto; line-height: 1; flex-shrink: 0; }
.toast-item .toast-close:hover { color: var(--ae-text); }
@keyframes toastSlideIn { from { opacity: 0; transform: translateX(24px); } to { opacity: 1; transform: none; } }

/* ── Modals, dropdowns, pagination, tabs, progress ──────────────────────── */
.modal-content { background: var(--ae-surface); color: var(--ae-text); border: 1px solid var(--ae-border); border-radius: 14px; box-shadow: var(--ae-shadow-lg); backdrop-filter: none; }
.modal-header, .modal-footer { border-color: var(--ae-border); }
.modal-title { color: var(--ae-text); font-weight: 600; }
.modal-backdrop.show { opacity: .35; }
.dropdown-menu { background: var(--ae-surface); border: 1px solid var(--ae-border); border-radius: var(--ae-radius-sm); box-shadow: var(--ae-shadow); padding: .35rem; }
.dropdown-item { color: var(--ae-text-2); border-radius: 6px; font-size: .84rem; padding: .45rem .7rem; }
.dropdown-item:hover, .dropdown-item:focus { background: var(--ae-surface-3); color: var(--ae-text); }
.dropdown-divider { border-color: var(--ae-border); }
.pagination { gap: 4px; }
.page-link { color: var(--ae-text-2); background: var(--ae-surface); border: 1px solid var(--ae-border); border-radius: var(--ae-radius-xs) !important; font-size: .8rem; padding: .35rem .65rem; }
.page-link:hover { background: var(--ae-surface-3); color: var(--ae-text); border-color: var(--ae-border-strong); }
.page-item.active .page-link { background: var(--ae-accent); border-color: var(--ae-accent); color: #fff; }
.page-item.disabled .page-link { color: var(--ae-muted); background: var(--ae-surface-2); }
.nav-tabs { border-bottom: 1px solid var(--ae-border); gap: .25rem; }
.nav-tabs .nav-link { color: var(--ae-muted); border: 0; border-bottom: 2px solid transparent; font-weight: 500; font-size: .85rem; padding: .55rem .9rem; }
.nav-tabs .nav-link:hover { color: var(--ae-text); border-color: var(--ae-border-strong); }
.nav-tabs .nav-link.active { color: var(--ae-accent-text); background: transparent; border-bottom-color: var(--ae-accent); }
.nav-pills .nav-link { color: var(--ae-text-2); border-radius: var(--ae-radius-sm); }
.nav-pills .nav-link.active { background: var(--ae-accent-soft); color: var(--ae-accent-text); }
.progress { background: var(--ae-surface-3); border-radius: 999px; height: 8px; }
.progress-bar { background: var(--ae-accent); }
.list-group-item { background: var(--ae-surface); border-color: var(--ae-border); color: var(--ae-text-2); }
.accordion-item, .accordion-button { background: var(--ae-surface); color: var(--ae-text); border-color: var(--ae-border); }
.accordion-button:not(.collapsed) { background: var(--ae-surface-2); color: var(--ae-text); box-shadow: none; }
.card { background: var(--ae-surface); border-color: var(--ae-border); border-radius: var(--ae-radius); color: var(--ae-text); }
.card-header, .card-footer { background: var(--ae-surface-2); border-color: var(--ae-border); }
/* --ae-text is white on this theme, so the old "dark chip, white words" pairing
   would have been white on white. The tooltip sits on a lifted surface instead. */
.tooltip-inner { background: var(--ae-surface-3); color: var(--ae-text); border: 1px solid var(--ae-border-strong); }
.offcanvas { background: var(--ae-surface); color: var(--ae-text); }
.bg-dark, .bg-black { background: var(--ae-surface-3) !important; color: var(--ae-text) !important; }
.text-white, .text-light { color: var(--ae-text) !important; }
.btn .text-white, .ae-btn-primary .text-white, .btn-primary .text-white, .btn-dark .text-white, .bg-primary .text-white, .bg-success .text-white, .bg-danger .text-white { color: #fff !important; }
.text-white-50 { color: var(--ae-muted) !important; }
.bg-primary { background: var(--ae-accent) !important; }
.text-primary { color: var(--ae-accent-text) !important; }
.text-success { color: var(--ae-success) !important; }
.text-warning { color: var(--ae-warning) !important; }
.text-info    { color: var(--ae-info) !important; }
.border, .border-top, .border-bottom, .border-start, .border-end { border-color: var(--ae-border) !important; }

/* ── Layout helpers for pages ──────────────────────────────────────────── */
.ae-toolbar { display: flex; flex-wrap: wrap; gap: .75rem; align-items: flex-end; padding: 1rem 1.2rem; margin-bottom: 1.25rem; background: var(--ae-surface); border: 1px solid var(--ae-border); border-radius: var(--ae-radius); }
.ae-toolbar .ae-label, .ae-toolbar label { margin-bottom: .3rem; }
.ae-toolbar > * { min-width: 0; }
.ae-stack { display: flex; flex-direction: column; gap: 1rem; }
.ae-row { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; }
.ae-between { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.ae-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.ae-grid-2 { display: grid; gap: 1rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ae-grid-3 { display: grid; gap: 1rem; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ae-grid-4 { display: grid; gap: 1rem; grid-template-columns: repeat(4, minmax(0, 1fr)); }
.ae-divider { height: 1px; background: var(--ae-border); margin: 1.25rem 0; }

/* KPI tile — a number with a label, optionally a hint */
.ae-kpi { display: flex; flex-direction: column; gap: .3rem; padding: 1.1rem 1.25rem; background: var(--ae-surface); border: 1px solid var(--ae-border); border-radius: var(--ae-radius); box-shadow: var(--ae-shadow-sm); min-width: 0; }
.ae-kpi-label { font-size: .7rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--ae-muted); }
.ae-kpi-value { font-size: 1.65rem; font-weight: 650; letter-spacing: -.03em; color: var(--ae-text); line-height: 1.1; }
.ae-kpi-hint { font-size: .76rem; color: var(--ae-muted); }
.ae-kpi.is-accent .ae-kpi-value { color: var(--ae-accent-text); }
.ae-kpi.is-danger .ae-kpi-value { color: var(--ae-danger); }
.ae-kpi.is-warn .ae-kpi-value { color: var(--ae-warning); }
.dash-kpi-value, .kaylin-total { color: var(--ae-text); }

/* Clickable tile (report cards, tool launchers) */
.ae-tile { display: flex; align-items: center; gap: 1rem; padding: 1.1rem 1.25rem; background: var(--ae-surface); border: 1px solid var(--ae-border); border-radius: var(--ae-radius); color: var(--ae-text); text-decoration: none; transition: border-color .15s, box-shadow .15s, background .15s; text-align: left; width: 100%; font-family: inherit; cursor: pointer; }
.ae-tile:hover { border-color: var(--ae-border-strong); box-shadow: var(--ae-shadow); color: var(--ae-text); background: var(--ae-surface); }
.ae-tile-icon { width: 42px; height: 42px; flex-shrink: 0; display: grid; place-items: center; border-radius: 10px; background: var(--ae-accent-soft); color: var(--ae-accent-text); font-size: 1.15rem; }
.ae-tile-title { font-weight: 600; font-size: .92rem; color: var(--ae-text); }
.ae-tile-desc { font-size: .78rem; color: var(--ae-muted); margin-top: .1rem; }

/* Definition lists / key facts */
.ae-facts { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: .9rem 1.25rem; margin: 0; }
.ae-facts dt, .ae-fact-label { font-size: .68rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--ae-muted); margin-bottom: .2rem; }
.ae-facts dd, .ae-fact-value { margin: 0; font-size: .9rem; color: var(--ae-text); font-weight: 500; overflow-wrap: anywhere; }

/* Empty + loading states */
.ae-empty, .empty-state, .ae-empty-state, .no-results, .blank-state { padding: 2.5rem 1.5rem; text-align: center; color: var(--ae-muted); background: var(--ae-surface-2); border: 1px dashed var(--ae-border-strong); border-radius: var(--ae-radius); }
.ae-empty strong, .empty-state strong { display: block; color: var(--ae-text); font-weight: 600; margin-bottom: .25rem; }
.ae-empty-icon { font-size: 1.6rem; color: var(--ae-muted); margin-bottom: .5rem; }
.ae-empty p, .ae-empty .ae-empty-body { margin: 0 auto; max-width: 46ch; }
.skeleton, .ae-skeleton, [data-skeleton] { background: linear-gradient(90deg, var(--ae-surface-3) 25%, var(--ae-surface-2) 50%, var(--ae-surface-3) 75%); background-size: 200% 100%; animation: aeShimmer 1.4s infinite; border-radius: 6px; color: transparent !important; }
@keyframes aeShimmer { to { background-position: -200% 0; } }

/* ── Names the views already use ───────────────────────────────────────────
   Each of these appears in a converted view; without them the element rendered
   unstyled. They are thin aliases over what the system already provides. */
.ae-alert, .ae-alert-success, .ae-alert-danger, .ae-alert-error, .ae-alert-warning, .ae-alert-info {
    display: flex; gap: .6rem; align-items: flex-start; padding: .75rem 1rem; margin-bottom: 1rem;
    border: 1px solid var(--ae-border); border-radius: var(--ae-radius-sm);
    background: var(--ae-surface-2); color: var(--ae-text-2); font-size: .85rem;
}
.ae-alert-success { background: var(--ae-success-soft); border-color: var(--ae-success-border); color: var(--ae-success); }
.ae-alert-danger, .ae-alert-error { background: var(--ae-danger-soft); border-color: var(--ae-danger-border); color: var(--ae-danger-text); }
.ae-alert-warning { background: var(--ae-warning-soft); border-color: var(--ae-warning-border); color: var(--ae-warning); }
.ae-alert-info { background: var(--ae-info-soft); border-color: var(--ae-info-border); color: var(--ae-info); }
.ae-badge-muted, .ae-badge-gray, .ae-badge-grey { background: var(--ae-surface-3); color: var(--ae-text-2); }
.ae-input-error, .ae-form-error { display: block; margin-top: .3rem; font-size: .76rem; color: var(--ae-danger-text); }
.ae-code, .ae-code-box, code.ae-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .82rem;
    background: var(--ae-surface-3); color: var(--ae-text); border: 1px solid var(--ae-border);
    border-radius: var(--ae-radius-xs); padding: .5rem .7rem; overflow-wrap: anywhere;
}
code.ae-code, span.ae-code { display: inline-block; padding: .1em .4em; }
.ae-label-pro, .ae-form-label, .ae-lab { display: block; font-size: .72rem; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; color: var(--ae-muted); margin-bottom: .4rem; }
.ae-card-content, .ae-card-body { padding: 1.25rem 1.4rem; }
.ae-page-card > .ae-card-content, .ae-page-card > .ae-card-body, .ae-card > .ae-card-content, .ae-card > .ae-card-body { padding: 0; }
.ae-pagination { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; margin-top: 1rem; }

/* A hand-rolled modal (not Bootstrap's): a fixed shade plus a centred panel. */
.ae-modal { position: fixed; inset: 0; z-index: 1080; display: none; align-items: center; justify-content: center; padding: 1rem; }
.ae-modal.is-open, .ae-modal[open], .ae-modal.show { display: flex; }
.ae-modal-shade { position: absolute; inset: 0; background: rgba(17, 24, 39, .45); }
.ae-modal-panel {
    position: relative; z-index: 1; width: min(560px, 100%); max-height: 86dvh; overflow: auto;
    background: var(--ae-surface); color: var(--ae-text); border: 1px solid var(--ae-border);
    border-radius: 14px; box-shadow: var(--ae-shadow-lg); padding: 1.4rem 1.5rem;
}

/* Avatars / initials */
.ae-avatar { display: inline-grid; place-items: center; width: 36px; height: 36px; border-radius: 10px; background: var(--ae-accent-soft); color: var(--ae-accent-text); font-weight: 650; font-size: .85rem; flex-shrink: 0; }

/* ═══════════════════════════════════════════════════════════════════════════
   SHELL — sidebar, topbar, content
   ═══════════════════════════════════════════════════════════════════════════ */
.sidebar {
    position: fixed; top: 0; left: 0; width: var(--sidebar-w); height: 100dvh;
    background: var(--ae-surface); border-right: 1px solid var(--ae-border);
    display: flex; flex-direction: column; z-index: 100; overflow-y: auto; overflow-x: hidden;
    transition: transform .25s cubic-bezier(.4, 0, .2, 1); backdrop-filter: none; box-shadow: none;
}
.sidebar::-webkit-scrollbar { width: 6px; }
.sidebar::-webkit-scrollbar-thumb { background: var(--ae-border); border-radius: 99px; }
.sidebar-brand { display: flex; align-items: center; gap: 11px; padding: 18px 18px 14px; border-bottom: 0; flex-shrink: 0; }
/* The sidebar badge is the real logo image now (<x-brand-mark>), not a letterform
   drawn in CSS — it used to be --ae-text on --ae-brand-gold, which after the
   re-theme resolved to lavender on white. This only gives it its glow. */
.ws-brand-mark, .ae-brand-img { flex-shrink: 0; border-radius: 50%; }
.ws-brand-mark { filter: drop-shadow(0 0 12px rgba(204, 100, 210, .45)); }
.sidebar-logo { background: none; -webkit-text-fill-color: currentColor; font-size: 1rem; font-weight: 650; color: var(--ae-text); letter-spacing: -.025em; line-height: 1.1; }
.sidebar-logo .ws-brand-dot { color: var(--ae-accent); }
.sidebar-portal { color: var(--ae-muted); font-size: .6rem; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; margin-top: 4px; }
.user-card { margin: 4px 12px 10px; padding: 10px 11px; background: var(--ae-surface-2); border: 1px solid var(--ae-border); border-radius: 10px; flex-shrink: 0; }
.user-avatar { width: 32px; height: 32px; border-radius: 9px; display: grid; place-items: center; font-size: .8rem; font-weight: 650; background: var(--ae-accent-soft); color: var(--ae-accent-text); box-shadow: none; flex-shrink: 0; }
.user-name { font-size: .8rem; font-weight: 600; color: var(--ae-text); }
.user-role { font-size: .66rem; color: var(--ae-muted); text-transform: capitalize; margin-top: 1px; }
.nav-wrap { padding: 0 12px 16px; flex: 1; }
.nav-group-label { padding: 16px 10px 6px; color: var(--ae-muted); font-size: .62rem; font-weight: 650; letter-spacing: .1em; text-transform: uppercase; user-select: none; }
.ws-nav-toggle { display: flex; justify-content: space-between; align-items: center; width: 100%; border: 0; border-radius: 6px; background: transparent; text-align: left; cursor: pointer; font: inherit; }
.ws-nav-toggle:hover { color: var(--ae-text-2); }
.ws-nav-chevron { font-size: .8rem; transform: rotate(90deg); transition: transform .15s; }
.ws-nav-toggle[aria-expanded=false] .ws-nav-chevron { transform: none; }
.nav-link-ae { display: flex; align-items: center; gap: 9px; min-height: 36px; padding: 6px 10px; margin-bottom: 2px; border-radius: 8px; border: 1px solid transparent; color: var(--ae-text-2); text-decoration: none; font-size: .82rem; font-weight: 500; transition: background .15s, color .15s; }
.nav-link-ae:hover { background: var(--ae-surface-3); color: var(--ae-text); border-color: transparent; }
.nav-link-ae.active { background: var(--ae-accent-soft); color: var(--ae-accent-text); border-color: transparent; font-weight: 600; position: relative; }
/* The active item carries a slice of the brand gradient on its leading edge —
   the one piece of the website's livery that survives at 36px. */
.nav-link-ae.active::before { content: ''; position: absolute; left: 0; top: 7px; bottom: 7px; width: 3px; border-radius: 0 3px 3px 0; background: var(--ae-grad); }
.nav-icon, .nav-link-ae:hover .nav-icon, .nav-link-ae.active .nav-icon { width: 24px; height: 24px; display: grid; place-items: center; flex-shrink: 0; border-radius: 6px; background: transparent; color: var(--ae-muted); font-size: .9rem; }
.nav-link-ae.active .nav-icon { color: var(--ae-accent); }
.nav-icon svg { width: 15px; height: 15px; }
/* The dashed border and hover fill here were still the emerald accent this
   system used for about a week in September 2026. */
.nav-link-ae.is-cta { color: var(--ae-accent-text); background: var(--ae-accent-soft); border: 1px dashed var(--ae-accent-border); margin-top: 4px; }
.nav-link-ae.is-cta:hover { background: var(--ae-accent-soft-hover); }
.nav-link-ae.is-cta .nav-icon { color: var(--ae-accent); }
.nav-count { margin-left: auto; display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 20px; padding: 0 6px; border-radius: 999px; background: var(--ae-surface-3); color: var(--ae-text-2); font-size: .66rem; font-weight: 700; }
.nav-count.is-warn { background: var(--ae-warning-soft); color: var(--ae-warning); }
.nav-count.is-danger { background: var(--ae-danger-soft); color: var(--ae-danger-text); }
.nav-hint { font-size: .68rem; color: var(--ae-muted); font-weight: 400; }
.sidebar-bottom { padding: 12px; border-top: 1px solid var(--ae-border); flex-shrink: 0; }
.btn-signout { display: flex; align-items: center; gap: .6rem; width: 100%; padding: 8px 10px; background: transparent; border: 1px solid transparent; border-radius: 8px; color: var(--ae-muted); font-size: .8rem; font-weight: 500; font-family: inherit; cursor: pointer; transition: background .15s, color .15s; }
.btn-signout:hover { background: var(--ae-danger-soft); color: var(--ae-danger-text); border-color: transparent; }
.ws-sidebar-close { display: none; }

.main-wrap { margin-left: var(--sidebar-w); min-height: 100vh; display: flex; flex-direction: column; }
/* No staff session, so no sidebar: the public PayFast outcome pages extend this layout. */
.main-wrap--bare { margin-left: 0; }
.main-wrap--bare .content-area { max-width: 760px; padding-top: 40px; }
.topbar { position: sticky; top: 0; z-index: 50; display: flex; align-items: center; justify-content: space-between; gap: 18px; min-height: var(--topbar-h); padding: 10px 32px; background: rgba(255, 255, 255, .9); border-bottom: 1px solid var(--ae-border); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); flex-shrink: 0; }
.page-heading { font-size: .95rem; font-weight: 600; color: var(--ae-text); letter-spacing: -.01em; }
.page-crumb { font-size: .72rem; color: var(--ae-muted); margin-top: 1px; }
.topbar-menu-btn { display: none; width: 36px; height: 36px; align-items: center; justify-content: center; background: var(--ae-surface); border: 1px solid var(--ae-border); color: var(--ae-text-2); border-radius: 8px; cursor: pointer; }
.topbar-menu-btn:hover { background: var(--ae-surface-3); }
.ws-topbar-actions { display: flex; align-items: center; gap: 10px; }
.ws-search-trigger { display: flex; align-items: center; justify-content: space-between; gap: 14px; min-width: 200px; padding: 7px 10px; border: 1px solid var(--ae-border); border-radius: 8px; background: var(--ae-surface-2); color: var(--ae-muted); font: inherit; font-size: .78rem; cursor: pointer; transition: border-color .15s, background .15s; }
.ws-search-trigger:hover { border-color: var(--ae-border-strong); background: var(--ae-surface); color: var(--ae-text-2); }
.ws-search-trigger > span { display: flex; align-items: center; gap: 8px; }
.ws-search-trigger kbd { font-family: inherit; color: var(--ae-muted); background: var(--ae-surface); border: 1px solid var(--ae-border); border-radius: 4px; font-size: .62rem; padding: 1px 5px; }
.ws-charity { margin: 0; }
.ws-charity select { display: inline-block; width: auto; max-width: 200px; min-height: 34px; padding: .32rem 2rem .32rem .65rem; font-size: .76rem; font-weight: 500; border-radius: 8px; background-color: var(--ae-surface); border-color: var(--ae-border); color: var(--ae-text-2); cursor: pointer; }
.ws-charity select.is-scoped { background-color: var(--ae-accent-soft); border-color: var(--ae-accent-border); color: var(--ae-accent-text); font-weight: 600; }
.ws-security { display: inline-flex; align-items: center; gap: .4rem; padding: .36rem .75rem; border-radius: 8px; font-size: .76rem; font-weight: 600; text-decoration: none; background: var(--ae-warning-soft); border: 1px solid var(--ae-warning-border); color: var(--ae-warning); }
.ws-security:hover { background: rgba(251,191,36,.26); color: var(--ae-text); }
.ws-today { color: var(--ae-muted); font-size: .74rem; white-space: nowrap; }
.content-area { flex: 1; width: 100%; max-width: 1800px; margin: 0 auto; padding: 28px 32px 48px; }
.ws-duplicate-banner { display: flex; align-items: center; gap: .6rem; margin-bottom: 1rem; padding: .7rem 1rem; border-radius: var(--ae-radius-sm); background: var(--ae-warning-soft); border: 1px solid var(--ae-warning-border); color: var(--ae-warning); font-size: .84rem; font-weight: 500; text-decoration: none; }
.ws-duplicate-banner i { color: var(--ae-warning); }
.ws-duplicate-banner .ws-banner-cta { margin-left: auto; font-weight: 700; }

/* Command palette */
.ws-dialog { width: min(600px, calc(100vw - 32px)); max-height: min(640px, 82dvh); margin: 10dvh auto auto; padding: 0; background: var(--ae-surface); color: var(--ae-text); border: 1px solid var(--ae-border); border-radius: 14px; box-shadow: var(--ae-shadow-lg); }
.ws-dialog::backdrop { background: rgba(17, 24, 39, .45); backdrop-filter: blur(3px); }
.ws-dialog-head { padding: 18px 20px; border-bottom: 1px solid var(--ae-border); }
.ws-dialog-title { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
.ws-dialog-title h2 { font-size: .9rem; margin: 0; font-weight: 600; }
.ws-dialog-close { color: var(--ae-muted); background: var(--ae-surface-2); border: 1px solid var(--ae-border); border-radius: 5px; font: inherit; font-size: .7rem; padding: 3px 7px; cursor: pointer; }
.ws-command-input { width: 100%; padding: 11px 13px; font-size: .9rem; }
.ws-command-results { padding: 8px; overflow-y: auto; max-height: 370px; }
.ws-command-link { display: flex; align-items: center; justify-content: space-between; gap: 18px; padding: 11px 14px; border: 1px solid transparent; border-radius: 8px; color: var(--ae-text); text-decoration: none; font-size: .84rem; }
.ws-command-link small { color: var(--ae-muted); font-size: .7rem; }
.ws-command-link:hover, .ws-command-link:focus { color: var(--ae-accent-text); background: var(--ae-accent-soft); border-color: transparent; }
.ws-command-footer { padding: 12px 20px; border-top: 1px solid var(--ae-border); color: var(--ae-muted); font-size: .7rem; }
.ws-command-empty { padding: 26px 20px; color: var(--ae-muted); font-size: .84rem; text-align: center; }

/* Mobile drawer */
.sidebar-overlay { display: none; position: fixed; inset: 0; background: rgba(17, 24, 39, .45); z-index: 99; backdrop-filter: blur(2px); }
@media (min-width: 1500px) { .content-area { padding: 34px 42px 56px; } .topbar { padding-left: 42px; padding-right: 42px; } }
@media (max-width: 1200px) { .ws-today { display: none; } .ws-search-trigger { min-width: 38px; padding: 8px; } .ws-search-trigger .ws-search-label, .ws-search-trigger kbd { display: none; } .content-area { padding: 24px; } .topbar { padding: 10px 24px; } }
@media (max-width: 991px) {
    .sidebar { transform: translateX(-100%); z-index: 110; box-shadow: none; }
    .sidebar.open { transform: translateX(0); box-shadow: var(--ae-shadow-lg); }
    .sidebar-overlay.open { display: block; }
    .main-wrap { margin-left: 0; }
    .topbar-menu-btn { display: inline-flex; }
    .ws-sidebar-close { display: block; margin-left: auto; color: var(--ae-muted); border: 0; background: transparent; font-size: 1.4rem; line-height: 1; cursor: pointer; }
    .ws-skip { left: 15px; }
    .content-area { padding: 20px; }
    /* A table with no wrapper gets its own scroller on a phone, so a wide one does
       not stretch the page. */
    .content-area table { display: block; width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch; white-space: nowrap; }
    /* But a table that is ALREADY inside .table-responsive must not become a second
       one. Two nested horizontal scrollers split a row between them: on the donor
       directory the wrapper scrolled 360→1050 and the table then scrolled 1050→1353,
       so you reached the end of one scrollbar with 300px of the row still hidden
       behind another. One scroller, on the wrapper, which is what it is for. */
    .content-area .table-responsive > table { display: table; width: auto; min-width: 100%; overflow: visible; }
    .ae-page-card { padding: 1.15rem !important; }
    .dash-kpi-value, .kaylin-total { font-size: 1.7rem !important; }
    .ae-grid-3, .ae-grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 600px) {
    .topbar { padding: 10px 15px; flex-wrap: wrap; gap: 10px; }
    .ws-topbar-actions { gap: 8px; }
    .ws-charity select { max-width: 150px; }
    .page-crumb { max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .content-area { padding: 16px 14px 32px; }
    .toast-zone { right: 12px; left: 12px; bottom: 12px; min-width: unset; max-width: unset; }
    .fields, .fields.two-col, .fields.three-col, .fields.one-col, .signup-grid, .stat-grid, .kpi-grid, .grid-2, .grid-3, .grid-4, .ae-grid-2, .ae-grid-3, .ae-grid-4 { grid-template-columns: 1fr !important; }
    .page-heading { font-size: .9rem; }
    h1 { font-size: 1.35rem; }
    .ae-page-title { font-size: 1.25rem; }
    .dash-kpi-value, .kaylin-total { font-size: 1.5rem !important; }
    table { font-size: .82rem; }
    .modal-dialog { margin: .5rem; }
    .ws-dialog { margin-top: 6dvh; }
}
@media (max-width: 380px) { .content-area { padding: 14px 10px; } .ae-page-card { padding: .9rem !important; } }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } *, *::before, *::after { animation: none !important; transition: none !important; } }
@media print {
    body { background: #fff; }
    .sidebar, .topbar, .ws-dialog, .ws-skip, .toast-zone, .sidebar-overlay { display: none !important; }
    .main-wrap { margin: 0; }
    .content-area { padding: 0; max-width: none; }
    .ae-page-card, .ae-card, .ae-glass { box-shadow: none; border-color: #ccc; break-inside: avoid; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   CINEMATIC LAYER — September 2026

   The owner asked for the CRM to look like aeplanet.com, "full cinematic,
   everywhere". Everything above is the system; this is the livery on top of it.
   It is deliberately last so it can lean on the tokens without fighting them,
   and every rule here is either a brand colour, an alpha blend of one, or pure
   black — the guidelines allow nothing else.

   One thing it does NOT do: touch the metrics of a table, a form control or a
   figure. Staff read this CRM all day, so the glass, glow and gradient sit on
   the chrome — shell, headers, empty states, KPIs — and leave the data alone.
   ═══════════════════════════════════════════════════════════════════════════ */

/* The ground: black with two brand auroras, fixed so it does not scroll with
   the content. Matches the hero treatment on the public site. */
body {
    background:
        radial-gradient(58% 44% at 12% 0%, rgba(98, 33, 155, .30), transparent 62%),
        radial-gradient(48% 38% at 92% 8%, rgba(204, 100, 210, .16), transparent 66%),
        radial-gradient(60% 50% at 78% 100%, rgba(111, 113, 194, .14), transparent 68%),
        var(--ae-bg);
    background-attachment: fixed;
}

/* Surfaces become glass over that ground rather than flat panels. */
.ae-glass, .ae-card, .ae-page-card, .ae-glass-deep,
.glass-card, .dashboard-card, .stat-card, .kpi-card, .metric-card, .summary-card,
.report-card, .settings-card, .donor-card, .profile-card, .widget-card, .filter-card,
.ae-kpi, .user-card, .ae-table-wrap {
    background: linear-gradient(180deg, var(--ae-glass), transparent 42%), var(--ae-surface);
    border-color: var(--ae-hairline);
}
.ae-page-card, .ae-card { box-shadow: var(--ae-shadow-sm), inset 0 1px 0 rgba(255, 255, 255, .06); }

/* Page headers carry the gradient rule the website uses under its hero. */
.ae-page-header { position: relative; padding-bottom: 1rem; }
.ae-page-header::after {
    content: ''; position: absolute; left: 0; bottom: 0; width: 72px; height: 2px;
    border-radius: 2px; background: var(--ae-grad);
}

/* Figures are the one piece of data that gets the livery: they are the thing
   people look at first, and a number is short enough that a gradient across it
   never lands a glyph in the unreadable purple stop. */
.ae-kpi-value, .ae-page-title {
    background: var(--ae-grad-text); -webkit-background-clip: text; background-clip: text;
    color: transparent;
}
.ae-kpi { position: relative; overflow: hidden; }
.ae-kpi::after {
    content: ''; position: absolute; inset: auto -30% -70% auto; width: 180px; height: 180px;
    border-radius: 50%; background: radial-gradient(closest-side, rgba(204, 100, 210, .16), transparent);
    pointer-events: none;
}
/* A KPI that means something keeps its semantic colour — brand livery must not
   repaint "overdue" in magenta. */
.ae-kpi.is-accent .ae-kpi-value, .ae-kpi.is-danger .ae-kpi-value, .ae-kpi.is-warn .ae-kpi-value {
    background: none; -webkit-background-clip: border-box; background-clip: border-box;
}
.ae-kpi.is-accent .ae-kpi-value { color: var(--ae-accent-text); }
.ae-kpi.is-danger .ae-kpi-value { color: var(--ae-danger-text); }
.ae-kpi.is-warn   .ae-kpi-value { color: var(--ae-warning); }

/* The shell: sidebar and topbar become the glass chrome of the public site. */
.sidebar {
    background: linear-gradient(180deg, rgba(98, 33, 155, .16), transparent 30%), rgba(5, 3, 10, .82);
    backdrop-filter: blur(18px) saturate(1.2); -webkit-backdrop-filter: blur(18px) saturate(1.2);
    border-right-color: var(--ae-hairline);
}
.topbar {
    background: rgba(5, 3, 10, .72);
    backdrop-filter: blur(18px) saturate(1.2); -webkit-backdrop-filter: blur(18px) saturate(1.2);
    border-bottom-color: var(--ae-hairline);
}
.sidebar::-webkit-scrollbar-thumb { background: var(--ae-border-strong); }

/* The primary action glows, the way the website's magenta button does. */
.ae-btn-primary, .btn-primary { box-shadow: 0 8px 26px rgba(98, 33, 155, .42); }
.ae-btn-primary:hover, .btn-primary:hover { box-shadow: 0 12px 34px rgba(204, 100, 210, .45); }

/* Empty states and notes get a hairline of brand rather than a flat grey box. */
.ae-empty { border: 1px dashed var(--ae-border-strong); border-radius: var(--ae-radius); background: var(--ae-glass); }
.ae-note { border-left: 3px solid transparent; border-image: var(--ae-grad) 1; }
.ae-note.is-warn, .ae-note.is-danger, .ae-note.is-success, .ae-note.is-info { border-image: none; }

/* Scrollbars, so the browser's own light chrome does not break the illusion. */
* { scrollbar-color: var(--ae-border-strong) transparent; scrollbar-width: thin; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--ae-border-strong); border-radius: 99px; border: 2px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background: var(--ae-accent); background-clip: content-box; }

/* Anyone who has asked their device for less motion gets the livery without the
   animation, and the blur comes off — it is the expensive part. */
@media (prefers-reduced-motion: reduce) {
    .sidebar, .topbar { backdrop-filter: none; -webkit-backdrop-filter: none; background: var(--ae-surface); }
}

/* Print stays on paper terms: black on white, no livery. */
@media print {
    body { background: #fff !important; }
    .ae-kpi-value, .ae-page-title { background: none !important; -webkit-text-fill-color: #000 !important; color: #000 !important; }
    .ae-page-header::after, .ae-kpi::after { display: none !important; }
}
