@charset "UTF-8";
/* ============================================================================
   AptaOps theme layer — the "Aperture" design system
   ----------------------------------------------------------------------------
   Loads AFTER materia.custom.css and BEFORE the per-tenant
   wwwroot/company/{registrationId}/assets/css/default.css, so a customer's own
   brand colour and logo still win. Nothing here touches markup: it retargets
   the Bootstrap custom properties the Materia theme already reads, then adds
   component rules where the design differs from Materia's defaults.

   Source of truth: design_handoff_aptaops_identity/tokens/tokens.css and the
   component tables in that bundle's README.

   Two deliberate departures from the handoff, both because this is a dense
   operations portal rather than the marketing site:

   1. Base font size stays at Materia's 14px. The handoff's own product screens
      specify 14px names, 13px mono data and 15px card headers; its 16px body is
      for marketing prose. Raising the base would reflow all 125 views.
   2. The sidebar keeps Materia's icon rail plus fly-out rather than becoming
      the handoff's 232px labelled column. The design language is applied to the
      rail we have: primary-deep fill, brand-derived active marker, mono labels.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   1. Tokens
   ------------------------------------------------------------------------- */
:root,
[data-bs-theme="light"] {
    /* Brand */
    --apta-primary: #0F4C4A;
    --apta-primary-deep: #0A3433;
    --apta-primary-hover: #0A3433;
    --apta-secondary: #2B3238;
    --apta-accent: #B4762F;
    --apta-accent-hover: #9C641F;
    --apta-accent-text: #8A5B1E;
    --apta-dark: #0B1417;

    /* Neutrals */
    --apta-bg: #F6F7F5;
    --apta-surface: #FFFFFF;
    --apta-surface-sunken: #EDEFEA;
    --apta-surface-sunken-hover: #E3E6E1;
    --apta-border: #D8DCD6;
    --apta-border-subtle: #EDEFEA;
    --apta-border-strong: #B9BFB7;

    /* Text */
    --apta-text: #101A1A;
    --apta-text-body: #3C4A48;
    --apta-text-muted: #5C6866;
    --apta-text-disabled: #9AA5A2;
    --apta-text-on-primary: #FFFFFF;

    /* Status */
    --apta-success: #157F4E;
    --apta-success-tint: #E6F2EB;
    --apta-success-text: #0E5B38;
    --apta-warning: #C9910B;
    --apta-warning-tint: #FBF2DC;
    --apta-warning-text: #7A5905;
    --apta-error: #B3261E;
    --apta-error-tint: #F9E7E5;
    --apta-error-text: #8C1D17;
    --apta-info: #1D6E77;
    --apta-info-tint: #E4EFF0;
    --apta-info-text: #134E55;

    /* Disabled control */
    --apta-disabled-bg: #F1F2EF;
    --apta-disabled-border: #E3E6E1;

    /* Type */
    --apta-font-sans: "IBM Plex Sans", "Segoe UI", system-ui, sans-serif;
    --apta-font-mono: "IBM Plex Mono", ui-monospace, "Cascadia Mono", Consolas, monospace;

    /* Radius — 2px controls and badges, 3px cards and panels. Nothing else. */
    --apta-radius-sm: 2px;
    --apta-radius-md: 3px;

    /* Spacing, 8px base */
    --apta-space-1: 4px;
    --apta-space-2: 8px;
    --apta-space-3: 12px;
    --apta-space-4: 16px;
    --apta-space-5: 24px;
    --apta-space-6: 32px;
    --apta-space-7: 44px;
    --apta-space-8: 64px;

    /* The only box-shadow in the system */
    --apta-focus-ring: 0 0 0 2px var(--apta-surface), 0 0 0 4px var(--apta-accent);

    /* Colour-only transitions. No motion on layout. */
    --apta-transition: 120ms ease-out;
}

[data-bs-theme="dark"] {
    --apta-bg: #0B1417;
    --apta-surface: #132125;
    --apta-surface-sunken: #0B1417;
    --apta-surface-sunken-hover: #1B2C31;
    --apta-border: #26383B;
    --apta-border-subtle: #1B2C31;
    --apta-border-strong: #354548;

    --apta-primary: #4FA39D;
    --apta-primary-deep: #0A3433;
    --apta-primary-hover: #6FB8B2;
    --apta-accent: #C98C3E;
    --apta-accent-hover: #D8A45C;
    --apta-accent-text: #D8A45C;

    --apta-text: #E8EDEB;
    --apta-text-body: #CFDCD9;
    --apta-text-muted: #9CB0AD;
    --apta-text-disabled: #6C807D;
    --apta-text-on-primary: #06201F;

    --apta-success: #34A56F;
    --apta-success-tint: #122A20;
    --apta-success-text: #7FD3A8;
    --apta-warning: #E0AE2E;
    --apta-warning-tint: #2C2410;
    --apta-warning-text: #EBC96E;
    --apta-error: #D6483F;
    --apta-error-tint: #2E1512;
    --apta-error-text: #EE8C85;
    --apta-info: #3A939C;
    --apta-info-tint: #12262A;
    --apta-info-text: #7FC3CA;

    --apta-disabled-bg: #17272B;
    --apta-disabled-border: #26383B;

    --apta-focus-ring: 0 0 0 2px var(--apta-bg), 0 0 0 4px var(--apta-accent);
}

/* ---------------------------------------------------------------------------
   2. Bootstrap remap
   ---------------------------------------------------------------------------
   Materia reads these throughout, so redefining them re-skins most of the app
   without a single markup change.
   ------------------------------------------------------------------------- */
:root,
[data-bs-theme="light"],
[data-bs-theme="dark"] {
    --bs-font-sans-serif: var(--apta-font-sans);
    --bs-font-monospace: var(--apta-font-mono);
    --bs-body-font-family: var(--apta-font-sans);

    --bs-primary: var(--apta-primary);
    --bs-secondary: var(--apta-secondary);
    --bs-success: var(--apta-success);
    --bs-warning: var(--apta-warning);
    --bs-danger: var(--apta-error);
    --bs-info: var(--apta-info);
    --bs-light: var(--apta-surface-sunken);
    --bs-dark: var(--apta-dark);

    --bs-body-bg: var(--apta-bg);
    --bs-body-color: var(--apta-text-body);
    --bs-emphasis-color: var(--apta-text);
    --bs-heading-color: var(--apta-text);
    --bs-secondary-color: var(--apta-text-muted);
    --bs-border-color: var(--apta-border);
    --bs-border-color-translucent: var(--apta-border);

    --bs-link-color: var(--apta-primary);
    --bs-link-hover-color: var(--apta-primary-hover);

    /* 3px is the largest radius in the system. Materia ships .5rem/.75rem. */
    --bs-border-radius: var(--apta-radius-md);
    --bs-border-radius-sm: var(--apta-radius-sm);
    --bs-border-radius-lg: var(--apta-radius-md);
    --bs-border-radius-xl: var(--apta-radius-md);
    --bs-border-radius-2xl: var(--apta-radius-md);

    /* Materia's own surface tokens */
    --bs-theme-component-bg: var(--apta-surface);
    --bs-theme-popup-bg: var(--apta-surface);
    --bs-theme-popup-hover-bg: var(--apta-surface-sunken);
    --bs-theme-list-hover-bg: var(--apta-bg);
    --bs-theme-body-highlight-bg: var(--apta-surface-sunken);
    --bs-secondary-bg: var(--apta-surface-sunken);
    --bs-tertiary-bg: var(--apta-bg);

    --bs-card-bg: var(--apta-surface);
    --bs-card-border-color: var(--apta-border);
    --bs-card-box-shadow: none;
}

:root,
[data-bs-theme="light"] {
    --bs-primary-rgb: 15, 76, 74;
    --bs-secondary-rgb: 43, 50, 56;
    --bs-success-rgb: 21, 127, 78;
    --bs-warning-rgb: 201, 145, 11;
    --bs-danger-rgb: 179, 38, 30;
    --bs-info-rgb: 29, 110, 119;
    --bs-body-bg-rgb: 246, 247, 245;
    --bs-body-color-rgb: 60, 74, 72;
}

[data-bs-theme="dark"] {
    --bs-primary-rgb: 79, 163, 157;
    --bs-success-rgb: 52, 165, 111;
    --bs-warning-rgb: 224, 174, 46;
    --bs-danger-rgb: 214, 72, 63;
    --bs-info-rgb: 58, 147, 156;
    --bs-body-bg-rgb: 11, 20, 23;
    --bs-body-color-rgb: 207, 220, 217;
}

/* Sidebar defaults. A tenant's own default.css loads after this file and
   overrides them, which is how customer branding survives the rebrand.

   In practice a customer sheet only ever sets --cms-sidebar-bg, so the other
   five are DERIVED from it rather than pinned to AptaOps colours. Pinning them
   was the bug: an orange or blue tenant kept the AptaOps rail text and the
   AptaOps deep-green fly-out, which is how the menu ended up as pale green
   labels on orange. Now a customer sets one colour and the whole menu follows.

   A light brand (THS lime) still overrides --cms-sidebar-fg / -fg-active to a
   dark colour in its own sheet: white-on-lime is unreadable and no formula
   fixes that. */
:root {
    --cms-sidebar-bg: var(--apta-primary-deep);
    --cms-sidebar-fg: rgba(255, 255, 255, .78);
    --cms-sidebar-fg-active: #FFFFFF;
    --cms-sidebar-highlight: rgba(255, 255, 255, .18);
    /* Fly-out panel: a light wash of the brand colour, dark text on top. 16% is
       low enough that even a near-black brand yields a genuinely light panel. */
    --cms-sidebar-sub-bg: color-mix(in srgb, var(--cms-sidebar-bg) 16%, #FFFFFF);
    --cms-sidebar-sub-fg: var(--apta-text);

    /* Marker on the active rail item. It has to read against whatever colour the
       rail is, so it is lifted off the brand towards the active text colour:
       copper on an orange or a lime rail is invisible. */
    --cms-sidebar-marker: color-mix(in srgb, var(--cms-sidebar-bg) 20%, var(--cms-sidebar-fg-active));
}

/* ---------------------------------------------------------------------------
   3. Type
   ------------------------------------------------------------------------- */
body {
    font-family: var(--apta-font-sans);
    color: var(--apta-text-body);
    background-color: var(--apta-bg);
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
    font-family: var(--apta-font-sans);
    color: var(--apta-text);
    font-weight: 600;
}

h1, .h1 { font-size: 40px; line-height: 1.05; letter-spacing: -.025em; }
h2, .h2 { font-size: 28px; line-height: 1.2;  letter-spacing: -.02em; }
h3, .h3 { font-size: 20px; line-height: 1.3;  letter-spacing: -.01em; }
h4, .h4 { font-size: 17px; line-height: 1.35; letter-spacing: -.01em; }
h5, .h5 { font-size: 15px; line-height: 1.4; }
h6, .h6 { font-size: 14px; line-height: 1.4; }

/* Display, for the few marketing-weight headings inside the portal */
.apta-display {
    font-size: 56px;
    line-height: 1;
    letter-spacing: -.03em;
    font-weight: 600;
    color: var(--apta-text);
}

/* Mono is for identifiers, references, dates, currency and table data.
   Never for running prose. */
.apta-mono,
.data-mono {
    font-family: var(--apta-font-mono);
    font-size: 13px;
    line-height: 1.45;
    font-variant-numeric: tabular-nums;
    color: var(--apta-text-body);
}

.apta-overline {
    font-family: var(--apta-font-mono);
    font-size: 11px;
    line-height: 1.3;
    letter-spacing: .14em;
    text-transform: uppercase;
    font-weight: 500;
    color: var(--apta-text-muted);
}

/* Numbers line up in every table, always. */
table td,
table th,
.gridjs-table td,
.gridjs-table th {
    font-variant-numeric: tabular-nums;
}

.text-muted,
.text-body-secondary {
    color: var(--apta-text-muted) !important;
}

.text-body-emphasis {
    color: var(--apta-text) !important;
}

/* Copper never carries text at its surface value: 3.1:1. This is the 5.2:1
   text variant from the handoff's accessibility rules. */
.text-accent {
    color: var(--apta-accent-text) !important;
}

/* ---------------------------------------------------------------------------
   4. Focus
   ---------------------------------------------------------------------------
   One ring, everywhere, always visible. It is the only box-shadow in the
   system, so it never competes with elevation.
   ------------------------------------------------------------------------- */
:where(a, button, input, select, textarea, [tabindex], .btn, .form-control, .form-select, .form-check-input, .choices__inner):focus-visible {
    outline: none;
    box-shadow: var(--apta-focus-ring);
}

.btn:focus,
.btn:focus-visible,
.form-control:focus,
.form-select:focus,
.form-check-input:focus,
.choices.is-focused .choices__inner {
    box-shadow: var(--apta-focus-ring);
    border-color: var(--apta-primary);
}

/* ---------------------------------------------------------------------------
   5. Elevation
   ---------------------------------------------------------------------------
   No drop shadows anywhere. Hairlines and whitespace do the separating.
   Overlays keep a shadow only because they float over arbitrary content and a
   1px hairline is not enough to detach them.
   ------------------------------------------------------------------------- */
.card,
.card-body,
.accordion-item,
.list-group,
.alert,
.nav-tabs,
.table-responsive,
.btn,
.form-control,
.form-select,
.badge,
.progress {
    box-shadow: none !important;
}

.card,
.accordion-item,
.list-group,
.alert {
    border: 1px solid var(--apta-border);
    border-radius: var(--apta-radius-md);
}

/* ---------------------------------------------------------------------------
   6. Buttons
   ------------------------------------------------------------------------- */
.btn {
    --bs-btn-border-radius: var(--apta-radius-sm);
    font-family: var(--apta-font-sans);
    font-size: 14px;
    font-weight: 600;
    letter-spacing: .01em;
    line-height: 1;
    padding: 11px 18px;
    border-radius: var(--apta-radius-sm);
    /* Written as the shorthand rather than leaning on Materia's
       --bs-btn-border-width: var(--bs-border-width). If that variable is ever
       undefined the whole shorthand is invalid at computed-value time and the
       border silently disappears, which is exactly how the secondary button
       loses its outline. */
    --bs-btn-border-width: 1px;
    border: 1px solid var(--bs-btn-border-color, transparent);
    transition: background-color var(--apta-transition), color var(--apta-transition), border-color var(--apta-transition);
}

.btn-sm {
    font-size: 13px;
    font-weight: 500;
    padding: 8px 14px;
}

.btn-lg {
    font-size: 15px;
    padding: 14px 22px;
}

.btn-primary {
    --bs-btn-bg: var(--apta-primary);
    --bs-btn-border-color: var(--apta-primary);
    --bs-btn-color: var(--apta-text-on-primary);
    --bs-btn-hover-bg: var(--apta-primary-hover);
    --bs-btn-hover-border-color: var(--apta-primary-hover);
    --bs-btn-hover-color: var(--apta-text-on-primary);
    --bs-btn-active-bg: var(--apta-primary-hover);
    --bs-btn-active-border-color: var(--apta-primary-hover);
    --bs-btn-disabled-bg: var(--apta-disabled-bg);
    --bs-btn-disabled-border-color: var(--apta-disabled-border);
    --bs-btn-disabled-color: var(--apta-text-disabled);
}

.btn-outline-primary,
.btn-secondary {
    --bs-btn-bg: var(--apta-surface);
    --bs-btn-border-color: var(--apta-primary);
    --bs-btn-color: var(--apta-primary);
    --bs-btn-hover-bg: var(--apta-surface-sunken);
    --bs-btn-hover-border-color: var(--apta-primary);
    --bs-btn-hover-color: var(--apta-primary);
    --bs-btn-active-bg: var(--apta-surface-sunken);
    --bs-btn-active-color: var(--apta-primary);
    --bs-btn-active-border-color: var(--apta-primary);
}

/* Ghost — Materia's light/secondary buttons land here */
.btn-light,
.btn-outline-light,
.btn-outline-secondary {
    --bs-btn-bg: var(--apta-surface-sunken);
    --bs-btn-border-color: var(--apta-surface-sunken);
    --bs-btn-color: var(--apta-secondary);
    --bs-btn-hover-bg: var(--apta-surface-sunken-hover);
    --bs-btn-hover-border-color: var(--apta-surface-sunken-hover);
    --bs-btn-hover-color: var(--apta-secondary);
    --bs-btn-active-bg: var(--apta-surface-sunken-hover);
    --bs-btn-active-color: var(--apta-secondary);
}

.btn-link {
    --bs-btn-color: var(--apta-primary);
    --bs-btn-hover-color: var(--apta-primary-hover);
    text-decoration: none;
    padding: 11px 0;
}

.btn-link:hover {
    text-decoration: underline;
}

/* Accent. The handoff allows copper once per view, for the single most
   consequential action. Use .btn-accent deliberately, not as a default. */
.btn-accent {
    --bs-btn-bg: var(--apta-accent);
    --bs-btn-border-color: var(--apta-accent);
    --bs-btn-color: #FFFFFF;
    --bs-btn-hover-bg: var(--apta-accent-hover);
    --bs-btn-hover-border-color: var(--apta-accent-hover);
    --bs-btn-hover-color: #FFFFFF;
    --bs-btn-active-bg: var(--apta-accent-hover);
    --bs-btn-active-color: #FFFFFF;
    background-color: var(--cms-sidebar-marker, var(--apta-accent));
    border-color: var(--apta-accent);
    color: #FFFFFF;
}

.btn-success { --bs-btn-bg: var(--apta-success); --bs-btn-border-color: var(--apta-success); --bs-btn-hover-bg: var(--apta-success-text); --bs-btn-hover-border-color: var(--apta-success-text); }
.btn-danger  { --bs-btn-bg: var(--apta-error);   --bs-btn-border-color: var(--apta-error);   --bs-btn-hover-bg: var(--apta-error-text);   --bs-btn-hover-border-color: var(--apta-error-text); }
.btn-warning { --bs-btn-bg: var(--apta-warning); --bs-btn-border-color: var(--apta-warning); --bs-btn-color: #101A1A; }

/* .btn-info is deliberately NOT retargeted. Alongside .btn-danger it carries a
   state on the "Send ... Email" buttons — info means sent, danger means not sent
   yet. Painting info in the brand teal made a sent button read as an ordinary
   primary action, so it keeps Materia's cyan and the pair stays legible. */

.btn:disabled,
.btn.disabled {
    background-color: var(--apta-disabled-bg);
    border-color: var(--apta-disabled-border);
    color: var(--apta-text-disabled);
    opacity: 1;
}

/* ---------------------------------------------------------------------------
   7. Badges
   ------------------------------------------------------------------------- */
.badge {
    font-family: var(--apta-font-sans);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .02em;
    text-transform: uppercase;
    padding: 5px 10px;
    border-radius: var(--apta-radius-sm);
    line-height: 1.2;
}

/* Inside a table the badge sits in a 15px row, so it steps down a size. */
table .badge,
.gridjs-table .badge {
    font-size: 11px;
    padding: 4px 8px;
}

/* Status colour is never the only carrier of meaning — every badge keeps its
   text label. These are the tint/text pairs from the handoff. */
.badge.bg-success, .badge.badge-soft-success { background-color: var(--apta-success-tint) !important; color: var(--apta-success-text) !important; }
.badge.bg-warning, .badge.badge-soft-warning { background-color: var(--apta-warning-tint) !important; color: var(--apta-warning-text) !important; }
.badge.bg-danger,  .badge.badge-soft-danger  { background-color: var(--apta-error-tint)   !important; color: var(--apta-error-text)   !important; }
.badge.bg-info,    .badge.badge-soft-info    { background-color: var(--apta-info-tint)    !important; color: var(--apta-info-text)    !important; }
.badge.bg-primary, .badge.badge-soft-primary { background-color: var(--apta-primary)      !important; color: #FFFFFF !important; }
.badge.bg-secondary, .badge.badge-soft-secondary,
.badge.bg-light, .badge.badge-soft-light     { background-color: var(--apta-surface-sunken) !important; color: var(--apta-text-body) !important; }

/* Provisional, per the handoff's badge list */
.badge-provisional {
    background-color: var(--apta-surface-sunken) !important;
    color: var(--apta-text-body) !important;
}

/* ---------------------------------------------------------------------------
   8. Cards
   ------------------------------------------------------------------------- */
.card {
    background-color: var(--apta-surface);
    border: 1px solid var(--apta-border);
    border-radius: var(--apta-radius-md);
}

.card-header {
    background-color: transparent;
    border-bottom: 1px solid var(--apta-border-subtle);
    padding: 16px 20px;
    font-size: 15px;
    font-weight: 600;
    color: var(--apta-text);
}

/* The mono meta line that sits under a card title */
.card-header .card-meta {
    display: block;
    margin-top: 4px;
    font-family: var(--apta-font-mono);
    font-size: 12px;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    color: var(--apta-text-muted);
}

.card-body {
    padding: 18px 20px;
}

.card-footer {
    background-color: transparent;
    border-top: 1px solid var(--apta-border-subtle);
    padding: 14px 20px;
}

/* Marks the focus item in a list of cards. One per view. */
.card-focus {
    border-top: 3px solid var(--apta-accent);
}

/* No nested cards inside cards — whitespace separates instead. */
.card .card {
    border: 0;
    background-color: transparent;
}

/* ---------------------------------------------------------------------------
   9. Tables
   ------------------------------------------------------------------------- */
.table,
.gridjs-table {
    --bs-table-bg: var(--apta-surface);
    --bs-table-color: var(--apta-text-body);
    --bs-table-border-color: var(--apta-border-subtle);
    --bs-table-hover-bg: var(--apta-bg);
    --bs-table-striped-bg: var(--apta-bg);
    font-size: 14px;
    color: var(--apta-text-body);
}

.table > thead th,
.gridjs-table th.gridjs-th {
    background-color: var(--apta-surface-sunken);
    color: var(--apta-text-body);
    font-family: var(--apta-font-mono);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: .1em;
    text-transform: uppercase;
    padding: 11px 22px;
    border-bottom: 1px solid var(--apta-border);
    border-top: 0;
}

.table > tbody > tr > td,
.gridjs-table td.gridjs-td {
    padding: 15px 22px;
    border-bottom: 1px solid var(--apta-border-subtle);
    border-top: 0;
    vertical-align: middle;
}

.table > tbody > tr:hover > td,
.gridjs-table tr:hover td.gridjs-td {
    background-color: var(--apta-bg);
    transition: background-color var(--apta-transition);
}

/* The primary cell: a 14/500 name over a mono uppercase sub-line naming the
   customer company. */
.cell-primary {
    font-size: 14px;
    font-weight: 500;
    color: var(--apta-text);
}

.cell-sub {
    display: block;
    margin-top: 3px;
    font-family: var(--apta-font-mono);
    font-size: 11px;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--apta-text-muted);
}

/* Dates, references, currency */
.cell-data {
    font-family: var(--apta-font-mono);
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    color: var(--apta-text-body);
}

/* An unassigned or unresolved value asks to be looked at, so it takes the
   copper text colour rather than reading as ordinary muted content. */
.cell-unassigned {
    color: var(--apta-accent-text);
    font-weight: 500;
}

/* ---------------------------------------------------------------------------
   10. Tabs and pills
   ------------------------------------------------------------------------- */
.nav-tabs {
    border-bottom: 1px solid var(--apta-border);
}

.nav-tabs .nav-link {
    padding: 10px 14px;
    font-size: 14px;
    font-weight: 500;
    color: var(--apta-text-muted);
    border: 0;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    transition: color var(--apta-transition), border-color var(--apta-transition);
}

/* vendor.css rounds every tab by .5rem at .nav.nav-tabs .nav-link, which outranks
   the rule above. On a transparent tab whose only edge is the 2px underline, that
   radius curls the underline's ends up into a bracket — plainly visible on the
   Organisation card, where nav-justified makes each tab a third of the width.
   Same selector, so it lands. */
.nav.nav-tabs .nav-link {
    border-radius: 0;
}

/* Same rule block paints a hovered tab in Materia's leftover Selion blue, which
   with the corners squared off reads as a hard off-palette rectangle. Keep a
   hover fill, but the theme's own sunken surface. */
.nav.nav-tabs .nav-link:not(.active):not(.disabled):hover {
    background-color: var(--apta-surface-sunken);
}

.nav-tabs .nav-link:hover {
    color: var(--apta-text-body);
    border-bottom-color: var(--apta-border-strong);
}

.nav-tabs .nav-link.active {
    color: var(--apta-primary);
    font-weight: 600;
    background-color: transparent;
    border-bottom-color: var(--apta-primary);
}

.nav-pills .nav-link {
    border-radius: var(--apta-radius-sm);
    font-size: 14px;
    font-weight: 500;
    color: var(--apta-text-body);
}

.nav-pills .nav-link.active {
    background-color: var(--apta-primary);
    color: var(--apta-text-on-primary);
}

/* ---------------------------------------------------------------------------
   11. Forms
   ------------------------------------------------------------------------- */
.form-control,
.form-select,
.choices__inner {
    background-color: var(--apta-surface);
    border: 1px solid var(--apta-border-strong);
    border-radius: var(--apta-radius-sm);
    color: var(--apta-text);
    font-family: var(--apta-font-sans);
    font-size: 14px;
    transition: border-color var(--apta-transition), box-shadow var(--apta-transition);
}

.form-control::placeholder {
    color: var(--apta-text-disabled);
}

.form-control:disabled,
.form-select:disabled {
    background-color: var(--apta-disabled-bg);
    border-color: var(--apta-disabled-border);
    color: var(--apta-text-disabled);
}

.form-label,
.col-form-label {
    font-size: 13px;
    font-weight: 500;
    letter-spacing: .01em;
    line-height: 1.3;
    color: var(--apta-text-body);
}

.form-check-input {
    border-color: var(--apta-border-strong);
    border-radius: var(--apta-radius-sm);
}

.form-check-input:checked {
    background-color: var(--apta-primary);
    border-color: var(--apta-primary);
}

.form-switch .form-check-input {
    border-radius: 2em;
}

.input-group-text {
    background-color: var(--apta-surface-sunken);
    border: 1px solid var(--apta-border-strong);
    border-radius: var(--apta-radius-sm);
    color: var(--apta-text-body);
    font-size: 13px;
}

.invalid-feedback { color: var(--apta-error-text); }
.was-validated .form-control:invalid,
.form-control.is-invalid { border-color: var(--apta-error); }

/* --- A field that carries its own "create on the fly" button --------------
   Locations, course types, companies and purchase orders can all be created
   without leaving the form, from a small button beside the picker. Wrap the
   control and its button(s) in .field-with-action and the pair renders as one
   segmented input: matching height, a single shared hairline, square corners
   where they meet. It works over a plain .form-control and over a Choices.js
   select, which is what most of these pickers are, and it leaves the select's
   caret alone because the button sits outside the control rather than on top
   of it.

       <div class="field-with-action mb-3">
           <div class="form-floating">…select + label…</div>
           <div class="field-actions">
               <a class="btn btn-field-action"><i class="ph ph-plus"></i></a>
           </div>
       </div>
   ------------------------------------------------------------------------- */
.field-with-action {
    display: flex;
    align-items: stretch;
    /* the field it replaces carried .mb-1; utility classes still override this */
    margin-bottom: .25rem;
}

/* The control takes the space. .flex-grow-1 is the older wrapper some views
   still put around the floating field. */
.field-with-action > .form-floating,
.field-with-action > .flex-grow-1 {
    flex: 1 1 auto;
    min-width: 0;
    margin-right: 0 !important;
}

.field-with-action > .flex-grow-1 > .form-floating,
.field-with-action > .form-floating {
    margin-bottom: 0 !important;
}

/* Square off the edge the button attaches to. */
.field-with-action .form-control,
.field-with-action .form-select,
.field-with-action .choices__inner {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

/* A validation message lives inside .form-floating in these views. Left in
   flow it would stretch the buttons the moment it appears, so it hangs below
   the field instead. */
.field-with-action .form-floating > .text-danger {
    position: absolute;
    top: 100%;
    left: 0;
    margin-top: 2px;
    font-size: 12px;
}

.field-actions {
    display: flex;
    flex: 0 0 auto;
}

.btn-field-action {
    --bs-btn-bg: var(--apta-surface-sunken);
    --bs-btn-border-color: var(--apta-border-strong);
    --bs-btn-color: var(--apta-primary);
    --bs-btn-hover-bg: var(--apta-primary);
    --bs-btn-hover-border-color: var(--apta-primary);
    --bs-btn-hover-color: var(--apta-text-on-primary);
    --bs-btn-active-bg: var(--apta-primary-hover);
    --bs-btn-active-border-color: var(--apta-primary-hover);
    --bs-btn-active-color: var(--apta-text-on-primary);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 46px;
    padding: 0;
    font-size: 18px;
    line-height: 1;
    border-radius: 0;
    /* one shared hairline between control and button, not two stacked */
    margin-left: -1px;
    transition: background-color var(--apta-transition), border-color var(--apta-transition), color var(--apta-transition);
}

/* Only the outermost button rounds off. */
.field-actions > .btn-field-action:last-child {
    border-top-right-radius: var(--apta-radius-sm);
    border-bottom-right-radius: var(--apta-radius-sm);
}

/* Lift the hovered/focused button so it owns the shared hairline rather than
   looking half-covered by the control's border. */
.btn-field-action:hover,
.btn-field-action:focus-visible,
.btn-field-action:active {
    position: relative;
    z-index: 2;
}

/* ---------------------------------------------------------------------------
   12. Alerts
   ------------------------------------------------------------------------- */
.alert { border-radius: var(--apta-radius-md); padding: 14px 18px; font-size: 14px; }
.alert-success { background-color: var(--apta-success-tint); border-color: var(--apta-success); color: var(--apta-success-text); }
.alert-warning { background-color: var(--apta-warning-tint); border-color: var(--apta-warning); color: var(--apta-warning-text); }
.alert-danger  { background-color: var(--apta-error-tint);   border-color: var(--apta-error);   color: var(--apta-error-text); }
.alert-info    { background-color: var(--apta-info-tint);    border-color: var(--apta-info);    color: var(--apta-info-text); }

/* ---------------------------------------------------------------------------
   13. Chrome — topbar, sidebar rail, dropdowns, modals
   ------------------------------------------------------------------------- */
.navbar,
#header,
.app-header {
    background-color: var(--apta-surface);
    border-bottom: 1px solid var(--apta-border);
    box-shadow: none;
}

/* Group labels on the rail take the mono overline treatment. */
#sidebar .menu > li > div > span,
#sidebar .menu > li > a > span {
    font-family: var(--apta-font-mono);
    font-size: 10px;
    letter-spacing: .14em;
    text-transform: uppercase;
    font-weight: 500;
}

/* The marker on the active rail item: 5x5px at the right edge, painted in
   --cms-sidebar-marker so it stays visible whatever colour the rail is. */
#sidebar .menu > li:has(a.active) > a,
#sidebar .menu > li:has(a.active) > div {
    position: relative;
}

#sidebar .menu > li:has(a.active) > a::after,
#sidebar .menu > li:has(a.active) > div::after {
    content: "";
    position: absolute;
    right: 6px;
    top: 50%;
    width: 5px;
    height: 5px;
    margin-top: -2.5px;
    background-color: var(--cms-sidebar-marker, var(--apta-accent));
}

#sidebar .menu > li > ul > li > a {
    border-radius: var(--apta-radius-sm);
    font-size: 14px;
    font-weight: 500;
}

/* The nested list under an expandable group (Companies, Locations, Purchase
   Orders). vendor.css opens it flush against the row above and pays for the
   space with 1rem of padding under the last item instead, which reads as a list
   that has slipped down inside its panel. Move that breathing room to the top
   and let the last row sit on the panel's own edge.

   Overriding rather than editing vendor.css: that file is the Materia build,
   and a theme upgrade would take an edit there back out. */
#sidebar .menu-sub > ul {
    padding-top: .5rem;
}

#sidebar .menu-sub > ul > li:last-child {
    padding-bottom: 0;
}

.dropdown-menu {
    background-color: var(--apta-surface);
    border: 1px solid var(--apta-border);
    border-radius: var(--apta-radius-md);
    box-shadow: none;
    font-size: 14px;
}

.dropdown-item {
    border-radius: var(--apta-radius-sm);
    color: var(--apta-text-body);
}

.dropdown-item:hover,
.dropdown-item:focus {
    background-color: var(--apta-surface-sunken);
    color: var(--apta-text);
}

.dropdown-item.active,
.dropdown-item:active {
    background-color: var(--apta-primary);
    color: var(--apta-text-on-primary);
}

/* Overlays keep an elevation shadow: they float over arbitrary content, where
   a hairline alone does not detach them. Everything else in the system does not. */
.modal-content,
.offcanvas {
    background-color: var(--apta-surface);
    border: 1px solid var(--apta-border);
    border-radius: var(--apta-radius-md);
}

.modal-footer {
    border-top: 1px solid var(--apta-border-subtle);
    padding: 14px 20px;
}

.modal-title {
    font-size: 17px;
    font-weight: 600;
    color: var(--apta-text);
}

/* ---------------------------------------------------------------------------
   14. Misc surfaces
   ------------------------------------------------------------------------- */
.progress {
    background-color: var(--apta-surface-sunken);
    border-radius: var(--apta-radius-sm);
}

.progress-bar {
    background-color: var(--apta-primary);
}

.list-group-item {
    background-color: var(--apta-surface);
    border-color: var(--apta-border-subtle);
    color: var(--apta-text-body);
    font-size: 14px;
}

.list-group-item.active {
    background-color: var(--apta-primary);
    border-color: var(--apta-primary);
    color: var(--apta-text-on-primary);
}

.page-link {
    color: var(--apta-primary);
    border-color: var(--apta-border);
    border-radius: var(--apta-radius-sm);
    font-size: 13px;
}

.page-item.active .page-link {
    background-color: var(--apta-primary);
    border-color: var(--apta-primary);
    color: var(--apta-text-on-primary);
}

hr {
    border-color: var(--apta-border);
    opacity: 1;
}

code, kbd, pre, samp {
    font-family: var(--apta-font-mono);
}

::selection {
    background-color: var(--apta-primary);
    color: #FFFFFF;
}

/* No gradients, no glassmorphism. Strip Materia's decorative gradient fills. */
.bg-gradient {
    background-image: none !important;
}

/* ---------------------------------------------------------------------------
   15. Plugin skins
   ---------------------------------------------------------------------------
   Grid.js (mermaid theme), Choices and AlertifyJS ship their own greys and,
   in alertify's case, a blue accent. Their stylesheets load before this one,
   so a handful of rules is enough to bring them onto the palette. Structure
   and class names are untouched.
   ------------------------------------------------------------------------- */

/* --- Grid.js -------------------------------------------------------------- */
.gridjs-container {
    color: var(--apta-text-body);
    font-family: var(--apta-font-sans);
}

.gridjs-wrapper,
.gridjs-footer,
.gridjs-head {
    border-color: var(--apta-border);
    box-shadow: none;
    border-radius: var(--apta-radius-md);
    background-color: var(--apta-surface);
}

/* The header's rounded top corners. Grid.js rounds the wrapper 8px at the top,
   and when a grid has no footer its .gridjs-wrapper:nth-last-of-type(2) rule
   rounds all four — that selector outranks the block above, which is why the
   block's radius never reached these tables. The header is a shaded strip, so
   its top edge is square; only whichever element actually closes the panel
   carries the bottom radius. */
.gridjs-wrapper {
    border-radius: 0;
}

/* No footer, so the wrapper is what closes the panel. */
.gridjs-wrapper:nth-last-of-type(2) {
    border-radius: 0 0 var(--apta-radius-md) var(--apta-radius-md);
}

/* The footer sits flush under the wrapper and closes the panel itself. */
.gridjs-footer {
    border-radius: 0 0 var(--apta-radius-md) var(--apta-radius-md);
}

input.gridjs-input,
.gridjs-search-input {
    background-color: var(--apta-surface);
    border: 1px solid var(--apta-border-strong);
    border-radius: var(--apta-radius-sm);
    color: var(--apta-text);
    font-family: var(--apta-font-sans);
    font-size: 14px;
}

input.gridjs-input:focus,
.gridjs-search-input:focus {
    border-color: var(--apta-primary);
    box-shadow: var(--apta-focus-ring);
    outline: none;
}

.gridjs-th-content {
    font-family: var(--apta-font-mono);
    font-size: 11px;
    letter-spacing: .1em;
    text-transform: uppercase;
}

.gridjs-summary {
    font-family: var(--apta-font-mono);
    font-size: 12px;
    color: var(--apta-text-muted);
}

.gridjs-pagination .gridjs-pages button {
    background-color: var(--apta-surface);
    border: 1px solid var(--apta-border);
    border-radius: var(--apta-radius-sm);
    color: var(--apta-text-body);
    font-size: 13px;
}

.gridjs-pagination .gridjs-pages button:hover:not(:disabled) {
    background-color: var(--apta-surface-sunken);
}

.gridjs-pagination .gridjs-pages button.gridjs-currentPage,
.gridjs-pagination .gridjs-pages button:disabled.gridjs-currentPage {
    background-color: var(--apta-primary);
    border-color: var(--apta-primary);
    color: var(--apta-text-on-primary);
    font-weight: 600;
}

.gridjs-loading-bar {
    background-color: var(--apta-surface-sunken);
}

/* --- Choices -------------------------------------------------------------- */
.choices__list--dropdown,
.choices__list[aria-expanded] {
    background-color: var(--apta-surface);
    border: 1px solid var(--apta-border);
    border-radius: var(--apta-radius-sm);
    box-shadow: none;
}

.choices__list--dropdown .choices__item--selectable.is-highlighted,
.choices__list[aria-expanded] .choices__item--selectable.is-highlighted {
    background-color: var(--apta-surface-sunken);
    color: var(--apta-text);
}

.choices__list--multiple .choices__item {
    background-color: var(--apta-primary);
    border-color: var(--apta-primary);
    border-radius: var(--apta-radius-sm);
    color: var(--apta-text-on-primary);
    font-size: 13px;
}

/* --- AlertifyJS ----------------------------------------------------------- */
.ajs-dialog,
.ajs-message {
    background-color: var(--apta-surface);
    border: 1px solid var(--apta-border);
    border-radius: var(--apta-radius-md);
    color: var(--apta-text-body);
    font-family: var(--apta-font-sans);
}

.ajs-header {
    background-color: transparent;
    border-bottom: 1px solid var(--apta-border-subtle);
    color: var(--apta-text);
    font-weight: 600;
}

.ajs-footer {
    background-color: transparent;
    border-top: 1px solid var(--apta-border-subtle);
}

/* The footer buttons are bare <button>s in alertify: no padding, no border, and
   the ok button's blue is set from `.alertify .ajs-footer ...` in both alertify's
   default theme and app.min.css. Those five-class selectors outrank a shorter one
   here, so the ok label kept its blue on top of our fill. Everything below is
   prefixed with .alertify to win, and shaped to match .btn-primary and .btn-light
   so the confirm dialogs read like the rest of the portal. */
.alertify .ajs-footer {
    padding: var(--apta-space-3) var(--apta-space-5);
}

.alertify .ajs-footer .ajs-buttons .ajs-button {
    min-width: 0;
    min-height: 0;
    margin: 0 0 0 var(--apta-space-2);
    padding: 11px 18px;
    background-color: var(--apta-surface-sunken);
    border: 1px solid var(--apta-surface-sunken);
    border-radius: var(--apta-radius-sm);
    color: var(--apta-secondary);
    font-family: var(--apta-font-sans);
    font-size: 14px;
    font-weight: 600;
    letter-spacing: .01em;
    line-height: 1;
    text-transform: none;
    transition: background-color var(--apta-transition), color var(--apta-transition), border-color var(--apta-transition);
}

.alertify .ajs-footer .ajs-buttons .ajs-button:hover {
    background-color: var(--apta-surface-sunken-hover);
    border-color: var(--apta-surface-sunken-hover);
    color: var(--apta-secondary);
}

.alertify .ajs-footer .ajs-buttons .ajs-button.ajs-ok {
    background-color: var(--apta-primary);
    border-color: var(--apta-primary);
    color: var(--apta-text-on-primary);
}

.alertify .ajs-footer .ajs-buttons .ajs-button.ajs-ok:hover {
    background-color: var(--apta-primary-hover);
    border-color: var(--apta-primary-hover);
    color: var(--apta-text-on-primary);
}

.alertify .ajs-footer .ajs-buttons .ajs-button:focus-visible {
    box-shadow: var(--apta-focus-ring);
    outline: none;
}

.ajs-message.ajs-success { background-color: var(--apta-success-tint); color: var(--apta-success-text); border-color: var(--apta-success); }
.ajs-message.ajs-warning { background-color: var(--apta-warning-tint); color: var(--apta-warning-text); border-color: var(--apta-warning); }
.ajs-message.ajs-error   { background-color: var(--apta-error-tint);   color: var(--apta-error-text);   border-color: var(--apta-error); }

/* --- FullCalendar --------------------------------------------------------- */
.calendar.fc {
    --fc-border-color: var(--apta-border);
    --fc-today-bg-color: var(--apta-surface-sunken);
    --fc-event-bg-color: var(--apta-primary);
    --fc-event-border-color: var(--apta-primary);
    /* Dark, not white. diary/calendar.init.js paints every event as a 30%-alpha tint of
       its status colour with a solid left border, so the fill is always pale and white
       text disappears on it. The JS sets a dark colour inline on the event element, but
       FullCalendar applies this variable to the inner content of multi-day block events,
       where it wins. A course sitting on the Completed yellow was unreadable. */
    --fc-event-text-color: var(--apta-text);
    font-family: var(--apta-font-sans);
}

.calendar.fc .fc-col-header-cell-cushion,
.calendar.fc .fc-daygrid-day-number {
    font-family: var(--apta-font-mono);
    font-size: 12px;
    color: var(--apta-text-muted);
    text-decoration: none;
}

/* vendor.css turns today's date into a fixed 2rem square (width, height and
   place-content: center). The height is what makes it a square badge, and in the
   Diary that clips the number against the row above it. Unset it and the pill
   sizes to its own content; everything else in the vendor rule stays. */
.calendar.fc .fc-day-today .fc-daygrid-day-number {
    height: unset;
}

/* ---------------------------------------------------------------------------
   16. Signature components
   ---------------------------------------------------------------------------
   The three pieces the handoff calls the product's own: the qualification
   match meter, occupancy bars, and the registration-bracket frame. Bar radius
   is 1px here, which is the one exception to the 2px/3px rule — these are
   graphical marks, not controls, and 2px on an 8px bar reads as a lozenge.
   ------------------------------------------------------------------------- */

/* --- Match meter ---------------------------------------------------------
   One bar per qualification the course type requires, then a mono label
   reading "n / total · STATE". The state word matters as much as the colour:
   status is never carried by colour alone. */
.match-meter {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
}

.match-meter__bars {
    display: inline-flex;
    gap: 3px;
}

.match-meter__bar {
    display: block;
    width: 22px;
    height: 8px;
    border-radius: 1px;
    background-color: var(--apta-disabled-border);
}

.match-meter__label {
    font-family: var(--apta-font-mono);
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    letter-spacing: .04em;
    color: var(--apta-text-muted);
}

.match-meter--ready .match-meter__bar--met { background-color: var(--apta-success); }
.match-meter--ready .match-meter__label { color: var(--apta-success-text); }

.match-meter--review .match-meter__bar--met { background-color: var(--apta-warning); }
.match-meter--review .match-meter__label { color: var(--apta-warning-text); }

.match-meter--blocked .match-meter__bar--met { background-color: var(--apta-error); }
.match-meter--blocked .match-meter__label { color: var(--apta-error-text); }

/* Nothing assessed: every bar stays unfilled and the label stays muted. */
.match-meter--none .match-meter__label { color: var(--apta-text-muted); }

/* Table variant — the row is 15px tall, so the bars step down with it. */
table .match-meter,
.gridjs-table .match-meter,
.match-meter--sm {
    gap: 6px;
}

table .match-meter__bar,
.gridjs-table .match-meter__bar,
.match-meter--sm .match-meter__bar {
    width: 14px;
    height: 7px;
}

table .match-meter__label,
.gridjs-table .match-meter__label,
.match-meter--sm .match-meter__label {
    font-size: 11px;
}

/* --- Occupancy bars ------------------------------------------------------
   The scheduling grid abstracted to flat blocks. Never a gradient, never 3D. */
.occupancy {
    display: flex;
    align-items: center;
    gap: 12px;
}

.occupancy__name {
    flex: 0 0 112px;
    font-size: 13px;
    color: var(--apta-text-body);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.occupancy__track {
    display: flex;
    flex: 1 1 auto;
    gap: 3px;
    min-width: 0;
}

.occupancy__block {
    flex: 1 1 0;
    height: 14px;
    border-radius: 1px;
    background-color: var(--apta-surface-sunken);
}

.occupancy__block--booked { background-color: var(--apta-primary); }
.occupancy__block--holiday { background-color: var(--apta-info-tint); }

/* The taller variant from the handoff, for a standalone scheduling strip. */
.occupancy--lg .occupancy__track { gap: 4px; }
.occupancy--lg .occupancy__block { height: 22px; }

.occupancy-legend {
    display: flex;
    gap: 16px;
    align-items: center;
    padding-top: 12px;
    margin-top: 12px;
    border-top: 1px solid var(--apta-border-subtle);
}

.occupancy-legend__item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--apta-font-mono);
    font-size: 11px;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--apta-text-muted);
}

.occupancy-legend__swatch {
    width: 10px;
    height: 10px;
    border-radius: 1px;
    background-color: var(--apta-surface-sunken);
}

.occupancy-legend__swatch--booked { background-color: var(--apta-primary); }
.occupancy-legend__swatch--holiday { background-color: var(--apta-info-tint); }

/* --- Registration brackets -----------------------------------------------
   The mark's two corners lifted out to frame a figure, a pull quote or an
   empty state. Opposite corners only, never all four. */
.apta-brackets {
    position: relative;
    padding: 22px 26px;
}

.apta-brackets::before,
.apta-brackets::after {
    content: "";
    position: absolute;
    width: 22px;
    height: 22px;
    border: 3px solid var(--apta-primary);
    pointer-events: none;
}

.apta-brackets::before {
    top: 0;
    left: 0;
    border-right: 0;
    border-bottom: 0;
}

.apta-brackets::after {
    right: 0;
    bottom: 0;
    border-left: 0;
    border-top: 0;
}

.apta-brackets--accent::before,
.apta-brackets--accent::after {
    border-color: var(--apta-accent);
}

.apta-brackets--muted::before,
.apta-brackets--muted::after {
    border-color: var(--apta-border-strong);
}

/* --- Empty state ---------------------------------------------------------- */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 6px;
    margin: 24px auto;
    max-width: 420px;
}

.empty-state__title {
    font-size: 15px;
    font-weight: 600;
    color: var(--apta-text);
}

.empty-state__body {
    font-size: 14px;
    color: var(--apta-text-muted);
}

.empty-state__action {
    margin-top: 10px;
}

/* Grid.js writes its own "No matching records found" into .gridjs-message. */
.gridjs-td.gridjs-message {
    padding: 30px 22px;
    font-size: 14px;
    color: var(--apta-text-muted);
    text-align: center;
}
