/* ============================================================================
   eSuite Design System — Bootstrap 5.3 overlay  (NO BUILD STEP REQUIRED)
   VLE Support Ltd.

   HOW TO USE
   Load AFTER Bootstrap's CSS:
     <link rel="stylesheet" href="/assets/bootstrap-5.3.2-dist/css/bootstrap.min.css">
     <link rel="stylesheet" href="/assets/css/esuite-bootstrap.css">
   This file re-skins stock Bootstrap components to the eSuite brand and adds a
   few bespoke classes (avatar, status dot, metric tile, side nav, workspace
   tabs) that Bootstrap has no equivalent for. If you have a Sass build, prefer
   _esuite-variables.scss instead — this overlay is the drop-in fallback.
   ============================================================================ */

/* The two type faces (Poppins, and JetBrains Mono for its plain zero; both self-hosted) and the design system's tokens (drop-in copies of its
   tokens/*.css, which eCore's --es-* tokens below point at) are linked by the head just before this file: header.php and canonical-head.php. */

/* ----------------------------------------------------------------------------
   1. TOKENS  (the single source of truth — every rule below resolves to these)
---------------------------------------------------------------------------- */
:root {
  /* Primary blue ramp (anchor #4265AF) */
  --es-blue-900: #293F6D;  --es-blue-850: #33497D;  --es-blue-800: #4265AF;  --es-blue-700: #4B72C6;  --es-blue-600: #5481E0;
  --es-blue-tint: #E7ECF6;
  /* Aqua (secondary accent / info) */
  --es-aqua-700: #0673A1;  --es-aqua-600: #0098D4;  --es-aqua-500: #00AEEF;  --es-aqua-400: #1BB8F1;  --es-aqua-50: #DFF4FC;
  /* Status */
  --es-orange-700:var(--orange-700, #A33D00); --es-orange-600:#C14800; --es-orange-500:#FA650D; --es-orange-50:#FEE8D8;
  --es-red-700:#A01010;    --es-red-500:#DE1F1F;    --es-red-50:#FDDCDC;
  --es-yellow-700:#9A6200; --es-yellow-500:#FCA833; --es-yellow-50:#FEF4DC;
  --es-green-700:#09630B;  --es-green-500:#27AC2A;  --es-green-50:#D6F5D6;
  /* Neutrals */
  --es-white:#FFFFFF; --es-grey-50:#F1F2F7; --es-grey-100:#E1E6EB; --es-grey-300:#C7CCD4;
  --es-grey-400:#9F9F9F; --es-grey-600:#6B6B6B; --es-grey-700:#4D4D4D; --es-slate-500:var(--slate-500, #67728A);
  /* grey-50 IS the page colour, so anything sitting on content (zebra rows, wells, toolbars) uses this thinned tint instead. */
  --es-row-stripe: color-mix(in srgb, var(--es-grey-50) 50%, #fff);
  --es-surface-sunken: var(--es-row-stripe);
  /* Semantic */
  --es-accent: var(--es-blue-800);  --es-accent-hover: var(--es-blue-700);  --es-accent-press:#34528C;
  /* Muted text is the design system's slate-600 (6.5:1 on white). Body text stays grey-700: the system's --text-body name is taken by a size. */
  --es-text-strong: var(--text-strong, #293F6D);  --es-text-body: var(--es-grey-700);  --es-text-muted: var(--text-muted, #535E73);
  --es-border-subtle: var(--border-subtle, rgba(10,26,47,.10));  --es-border-input: var(--border-input, #8C8C8C);
  /* The edge of an outlined button: 4.83:1 on white. */
  --es-border-control-subtle: var(--border-control-subtle, #67728A);
  /* Table grid lines: between grey-100 and grey-300, soft on white and still seen on a zebra row. */
  --es-grid-line: color-mix(in srgb, var(--es-grey-100) 55%, var(--es-grey-300));
  /* Focus: a white gap and a navy ring, reversed on navy chrome; fields keep the soft glow. */
  --es-shadow-focus: var(--shadow-focus, 0 0 0 2px #fff, 0 0 0 4px #4265AF);
  --es-shadow-focus-on-navy: var(--shadow-focus-on-navy, 0 0 0 2px #293F6D, 0 0 0 4px #fff);
  --es-shadow-focus-soft: var(--shadow-focus-soft, 0 0 0 3px rgba(66,101,175,.30));
  --es-focus-ring: var(--es-shadow-focus);
  --es-avatar-fill-default: var(--avatar-fill-default, #0673A1);
  /* Type steps for dialog titles, small headings and group labels. */
  --es-text-h3: 1.1875rem;  --es-text-h4: .9375rem;  --es-text-sm: .8125rem;
  --es-text-dialog-title: var(--es-text-h3);  --es-text-h5: var(--es-text-h4);  --es-text-h6: var(--es-text-sm);
  --es-text-group-label: var(--es-text-sm);
  /* Shadows */
  --es-shadow-sm: 0 1px 3px rgba(10,26,47,.08), 0 1px 2px rgba(10,26,47,.04);
  --es-shadow-md: 0 4px 12px rgba(10,26,47,.10);
  --es-shadow-lg: 0 12px 28px rgba(10,26,47,.14);
  /* Motion */
  --es-ease: cubic-bezier(.2,0,0,1);  --es-dur: .12s;
  --es-font-sans: 'Poppins','Poppins Fallback','Segoe UI',system-ui,-apple-system,sans-serif;
  --font-sans: 'Poppins','Poppins Fallback','Segoe UI',system-ui,-apple-system,sans-serif;
  --es-font-mono: 'JetBrains Mono',ui-monospace,'SFMono-Regular',Menlo,monospace;
  /* Bootstrap's code/pre/kbd/samp and .font-monospace read this; left alone they fall to Consolas or
     SF Mono, both of which slash or dot the zero. */
  --bs-font-monospace: var(--es-font-mono);

  /* ---- Re-point Bootstrap's own variables to eSuite ---- */
  --bs-body-font-family: var(--es-font-sans);
  --bs-body-font-size: .9375rem;          /* 15px */
  --bs-body-color: var(--es-text-body);
  --bs-body-bg: var(--es-grey-50);        /* light-grey page */
  --bs-emphasis-color: var(--es-text-strong);
  --bs-secondary-color: var(--es-text-muted);
  --bs-primary: var(--es-blue-800);
  --bs-primary-rgb: 66,101,175;
  --bs-link-color: var(--es-blue-800);
  --bs-link-color-rgb: 66,101,175;
  --bs-link-hover-color: var(--es-accent-press);
  --bs-border-color: var(--es-grey-100);
  --bs-border-radius: .375rem;            /* 6px  controls */
  --bs-border-radius-sm: .25rem;          /* 4px  */
  --bs-border-radius-lg: .625rem;         /* 10px cards/nav */
  --bs-border-radius-xl: .875rem;         /* 14px panels */
  --bs-border-radius-pill: 999px;
  --bs-box-shadow-sm: var(--es-shadow-sm);
  --bs-box-shadow: var(--es-shadow-md);
  --bs-box-shadow-lg: var(--es-shadow-lg);
}

body { font-family: var(--es-font-sans); }
h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6 { color: var(--es-text-strong); font-weight: 600; }
/* Pop-up (modal) headers are coloured chrome — keep their title text white (headings default to navy above). */
.modal-header.bg-navy,.modal-header.bg-orange,.modal-header.bg-danger,
.modal-header.bg-navy .modal-title,.modal-header.bg-orange .modal-title,.modal-header.bg-danger .modal-title,
.modal-header.bg-navy h1,.modal-header.bg-navy h2,.modal-header.bg-navy h3,.modal-header.bg-navy h4,.modal-header.bg-navy h5,.modal-header.bg-navy h6 { color:#fff !important; }
/* An orange dialog header takes the darker orange, so its white title reads at 5:1. */
.modal-header.bg-orange{background:var(--es-orange-600)}
.h1,h1{font-size:2rem}.h2,h2{font-size:1.5rem}.h3,h3{font-size:1.1875rem}
.h4,h4{font-size:.9375rem}.h5,h5{font-size:var(--es-text-h5)}.h6,h6{font-size:var(--es-text-h6)}.display-1,.es-display{font-size:2.75rem;font-weight:600}
.modal-title{font-size:var(--es-text-dialog-title);font-weight:600}
a { text-decoration: none; }
a:hover { text-decoration: underline; }
/* Content links are underlined, so colour is not their only cue; components that style their own links, and navigation, keep theirs. */
a:where(:not([class]):not([role])) { color: var(--text-link); text-decoration: underline; text-underline-offset: 2px; }
:where(nav, .nav, .navbar) a:where(:not([class]):not([role])) { text-decoration: none; }
/* One focus ring for every control; on navy chrome the ring is white. */
:is(a, button, [role="button"], [role="tab"], [role="link"], summary, [tabindex]:not([tabindex="-1"])):focus-visible{
  outline:2px solid transparent;outline-offset:2px;box-shadow:var(--es-shadow-focus)}
:is([data-on-navy], .bg-navy, ul.lhs, .es-dropdown-navy, .es-table>thead, .es-matrix thead) :is(a, button, [role="button"], [role="tab"], [role="link"], summary, [tabindex]:not([tabindex="-1"])):focus-visible{
  box-shadow:var(--es-shadow-focus-on-navy)}
/* Skip link: off-screen until focused, then over the top bar (above its sticky layer, unlike the design system's 1000). */
.skip-link{position:absolute;top:6px;left:8px;z-index:1040;display:inline-flex;align-items:center;gap:var(--space-2);
  padding:6px 14px;border-radius:var(--radius-sm);background:#fff;color:var(--es-blue-900);font-size:.8125rem;font-weight:600;
  text-decoration:none;transform:translateY(-200%)}
.skip-link:focus{transform:none;box-shadow:var(--es-shadow-focus-on-navy),var(--es-shadow-md)!important}
main#main-content:focus{outline:2px solid transparent}

/* Brand wordmark — blue text, orange 2nd character */
.es-wordmark{font-weight:600;color:var(--es-blue-800);letter-spacing:var(--tracking-tight)}
.es-wordmark .e{font-weight:500}
.es-wordmark .o{color:var(--es-orange-500)}
.bg-navy .es-wordmark,.es-wordmark.on-navy{color:#fff}

/* Helpers */
.hide{display:none!important}
.text-navy{color:var(--es-blue-900)!important}
.text-aqua{color:var(--es-aqua-500)!important}
.text-muted-es{color:var(--es-text-muted)!important}
.bg-navy{background:var(--es-blue-800)!important;color:#fff}
.bg-blue-tint{background:var(--es-blue-tint)!important}
.font-mono{font-family:var(--es-font-mono)!important}
/* Monospace for what is code: snippets, links to copy, CSV, hex values. References, IDs and counts stay in the sans face. */
.es-code{font-family:var(--es-font-mono)!important}
/* <code> reads as eSuite's code: the mono face, muted, never under 12px (Bootstrap's is pink at .875em). */
code{font-family:var(--es-font-mono);color:var(--es-text-muted);font-size:max(.75rem,.875em)}
/* Bootstrap's .875em falls to 11.4px in a 13px card; 12px is the floor for any sentence. */
.small,small{font-size:max(.75rem,.875em)}
/* Group labels: sentence case, semibold, muted. .es-eyebrow is the old name. */
.es-group-label,.es-eyebrow{font-size:var(--es-text-group-label);font-weight:600;color:var(--es-text-muted)}
.es-doc-chip{display:inline-flex;align-items:center;gap:.4em;padding:calc(.35em - 1px) calc(.7em - 1px);border:1px solid currentColor;border-radius:7px;background:var(--es-green-50);color:var(--es-green-700);font-size:.8125rem;font-weight:600;text-decoration:none;transition:opacity .12s cubic-bezier(.2,0,0,1)}
.es-doc-chip:hover{opacity:.86;color:var(--es-green-700)}

/* ----------------------------------------------------------------------------
   2. BUTTONS   — 6px radius, Poppins 600, hover lifts via opacity (no shadow)
---------------------------------------------------------------------------- */
.btn{--bs-btn-font-family:var(--es-font-sans);--bs-btn-font-weight:600;
  --bs-btn-border-radius:.375rem;--bs-btn-font-size:.8125rem;
  --bs-btn-padding-y:.5625rem;--bs-btn-padding-x:1.125rem;line-height:1.2;
  transition:opacity var(--es-dur) var(--es-ease),background var(--es-dur) var(--es-ease),transform var(--es-dur) var(--es-ease)}
.btn:hover{opacity:.86}
.btn{--bs-btn-focus-box-shadow:var(--es-shadow-focus)}
/* Feedback on the press itself, not the release — Bootstrap's own base .btn:active only recolours
   background/border, which several variants here don't even set (.btn-ghost, .btn-navy) and which
   reads as too subtle to notice on the ones that do. A universal scale-down applies to every
   variant alike and is unmistakable regardless of colour. */
.btn:active{transform:scale(.97)}
.btn-sm{--bs-btn-padding-y:.3125rem;--bs-btn-padding-x:.75rem;--bs-btn-font-size:.8125rem}

/* Primary = brand blue */
.btn-primary{--bs-btn-bg:var(--es-blue-800);--bs-btn-border-color:var(--es-blue-800);
  --bs-btn-hover-bg:var(--es-blue-800);--bs-btn-hover-border-color:var(--es-blue-800);
  --bs-btn-active-bg:var(--es-accent-press);--bs-btn-active-border-color:var(--es-accent-press);--bs-btn-color:#fff}
/* Aqua (secondary accent / info CTA) — fill darkened aqua-500→aqua-700 so the #fff
   button label clears WCAG AA: white on aqua-500 ≈ 2.5:1 (fail), on aqua-700 ≈ 5.3:1
   (pass). Hover keeps the same fill (global .btn:hover dims via opacity, not colour). */
.btn-aqua,.btn-info{--bs-btn-bg:var(--es-aqua-700);--bs-btn-border-color:var(--es-aqua-700);
  --bs-btn-hover-bg:var(--es-aqua-700);--bs-btn-hover-border-color:var(--es-aqua-700);
  --bs-btn-active-bg:var(--es-aqua-700);--bs-btn-color:#fff;--bs-btn-hover-color:#fff}
/* Navy/deep */
.btn-navy{--bs-btn-bg:var(--es-blue-900);--bs-btn-border-color:var(--es-blue-900);
  --bs-btn-hover-bg:var(--es-blue-900);--bs-btn-color:#fff;--bs-btn-hover-color:#fff}
/* Orange (Add / create) — fill is orange-600 so the #fff label clears WCAG AA: white on orange-500 ≈ 3.0:1 (fail),
   on orange-600 ≈ 5.0:1 (pass), same rationale as .btn-aqua and .btn-green. */
.btn-orange,.btn-warning{--bs-btn-bg:var(--es-orange-600);--bs-btn-border-color:var(--es-orange-600);
  --bs-btn-hover-bg:var(--es-orange-600);--bs-btn-hover-border-color:var(--es-orange-600);--bs-btn-color:#fff;--bs-btn-hover-color:#fff;
  --bs-btn-active-bg:var(--es-orange-600);--bs-btn-active-border-color:var(--es-orange-600)}
/* Danger */
.btn-danger{--bs-btn-bg:var(--es-red-500);--bs-btn-border-color:var(--es-red-500);--bs-btn-hover-bg:var(--es-red-500);--bs-btn-color:#fff;--bs-btn-hover-color:#fff;--bs-btn-active-bg:var(--es-red-700)}
/* Green (achieved / proceed) — fill darkened green-500→green-700 so the #fff
   button label clears WCAG AA (white on green-500 ≈ 2.2:1 fail, on green-700
   ≈ 6.5:1 pass), same rationale as .btn-aqua. Reserve for "successful / proceed"
   actions; blue stays the default primary CTA. */
.btn-green{--bs-btn-bg:var(--es-green-700);--bs-btn-border-color:var(--es-green-700);
  --bs-btn-hover-bg:var(--es-green-700);--bs-btn-hover-border-color:var(--es-green-700);
  --bs-btn-active-bg:var(--es-green-700);--bs-btn-color:#fff;--bs-btn-hover-color:#fff}
/* Outline (1.5px) + Ghost */
.btn-outline-primary{--bs-btn-color:var(--es-aqua-700);--bs-btn-border-color:var(--es-aqua-500);--bs-btn-border-width:1.5px;
  --bs-btn-hover-bg:var(--es-aqua-700);--bs-btn-hover-border-color:var(--es-aqua-700);--bs-btn-hover-color:#fff}
.btn-ghost{--bs-btn-bg:var(--es-grey-50);--bs-btn-color:var(--es-grey-700);--bs-btn-border-color:var(--es-border-control-subtle);
  --bs-btn-border-width:1.5px;--bs-btn-hover-bg:var(--es-grey-100);--bs-btn-hover-color:var(--es-blue-900);--bs-btn-hover-border-color:var(--es-border-control-subtle)}
/* Low-emphasis "Change a completed/verified row" action — ghost button with aqua-700 text (§6.4d) */
.btn-ghost-aqua{--bs-btn-color:var(--es-aqua-700,#0673A1);--bs-btn-hover-color:var(--es-aqua-700,#0673A1)}
/* Icon button: white icons at rest, flip to orange on hover/focus (e.g. the navy "View learner" action) */
.btn.es-btn-icon-hover [class*="fa-"]{color:#fff;transition:color .12s}
.btn.es-btn-icon-hover:hover [class*="fa-"],
.btn.es-btn-icon-hover:focus-visible [class*="fa-"]{color:var(--es-orange-500,#FA650D)}

/* ----------------------------------------------------------------------------
   3. BADGES  — soft tint background + saturated text, pill
---------------------------------------------------------------------------- */
.badge{font-family:var(--es-font-sans);font-weight:600;font-size:.6875rem;padding:.25rem .625rem;border-radius:var(--radius-pill)}
.badge-soft-blue  {background:var(--es-blue-tint);color:var(--es-blue-800)}
.badge-soft-aqua  {background:var(--es-aqua-50);color:var(--es-aqua-700)}  /* aqua-600 text is 2.9:1 on the tint; aqua-700 is 4.6:1 */
.badge-soft-orange{background:var(--es-orange-50);color:var(--es-orange-700)}
.badge-soft-red   {background:var(--es-red-50);color:var(--es-red-700)}
.badge-soft-green {background:var(--es-green-50);color:var(--es-green-700)}
.badge-soft-yellow{background:var(--es-yellow-50);color:var(--es-yellow-700)}
.badge-soft-grey  {background:var(--es-grey-50);color:var(--es-grey-700)}
/* Every pill is framed in its own text colour, like the ribbon counters; the padding gives the border back. */
.badge[class*="badge-soft-"]{border:1px solid currentColor;padding:calc(.25rem - 1px) calc(.625rem - 1px)}
.badge .es-dot{width:6px;height:6px;border-radius:50%;background:currentColor;display:inline-block;margin-right:2px}

/* ----------------------------------------------------------------------------
   3b. NAV PILLS  — eSuite navy-active in-screen switcher (one source of truth)
   Bootstrap compiles the active bg as a literal #0d6efd, so re-pointing
   --bs-primary at runtime doesn't reach it. This restyles every .nav-pills bar
   (both BS5 .nav-link.active and the legacy li.active > a markup) to the eSuite
   blue-active pill with a grey-50 hover. JS hooks (.active toggling, a[data-page])
   are untouched — this is colour only.
---------------------------------------------------------------------------- */
.nav-pills{--bs-nav-pills-link-active-bg:var(--es-blue-800);gap:var(--space-1)}
.nav-pills .nav-link,.nav-pills>li>a{border-radius:var(--radius-pill);color:var(--es-blue-800)}
.nav-pills .nav-link.active,.nav-pills>li.active>a{background-color:var(--es-blue-800)!important;color:#fff!important}
.nav-pills .nav-link:not(.active):hover,.nav-pills>li:not(.active)>a:hover{background-color:var(--es-grey-50)}
.nav-pills>li.active{cursor:default}

/* ----------------------------------------------------------------------------
   4. CARDS  — white box, 10px radius, hairline border, coloured header bar
---------------------------------------------------------------------------- */
.card{--bs-card-border-radius:.625rem;--bs-card-border-color:var(--es-border-subtle);
  --bs-card-bg:var(--es-white);--bs-card-inner-border-radius:.625rem;border-width:.5px;overflow:hidden}
/* min-height is its height holding a btn-sm, so cards side by side line up whether or not one has a button. */
.card-header{font-weight:600;font-size:.8125rem;color:#fff;border-bottom:none;
  display:flex;align-items:center;justify-content:space-between;gap:.5rem;padding:.625rem 1rem;min-height:calc(2.85rem + 2px)}
.es-card-title{margin:0;font-size:inherit;font-weight:inherit;line-height:inherit;color:inherit}
.card-header.bg-navy  {background:var(--es-blue-800)}
.card-header.bg-aqua  {background:var(--es-aqua-700)}
.card-header.bg-orange{background:var(--es-orange-600)}
/* Linked headings / accordion toggles inside a coloured card header must read as the
   header text, not as a blue hyperlink (which blends into navy). Excludes .btn so
   styled buttons placed in a header keep their own colours. */
.card-header.bg-navy a:not(.btn),.card-header.bg-aqua a:not(.btn),.card-header.bg-orange a:not(.btn),
.card-header.bg-navy a:not(.btn):hover,.card-header.bg-aqua a:not(.btn):hover,.card-header.bg-orange a:not(.btn):hover{color:#fff}
/* A text link in a card header keeps a 24px target without making the header taller. */
.card-header>a:not(.btn){display:inline-flex;align-items:center;min-height:24px;margin-block:-2px}
.card-body{color:var(--es-text-body);font-size:.8125rem}
/* Organisation search — the JS builds an absolutely-positioned results dropdown
   (position:absolute; top:100%) and inserts it into the search column. Without a
   positioned wrapper the dropdown anchors to the nearest positioned ancestor —
   the .card, which sets overflow:hidden above — so it renders at the bottom edge
   of the whole card and is clipped out of view (visible in the Network tab but
   not on screen). Give the container its own positioning context so the dropdown
   anchors to the search row and escapes the card's clip. Fixes every
   organisation search (employmentStatus, learningAim, claims). */
.organisation_search_container{position:relative}

/* Content list-group (record-detail rows) — white rows, hairline dividers, one 10px rounded shell.
   :not(.lhs):not(.lhs-sub) keeps the navy VerticalNav (§10) on its own theme. Without this,
   stock BS5 derives --bs-list-group-bg from --bs-body-bg (re-pointed to grey-50) → grey full-bleed rows. */
.list-group:not(.lhs):not(.lhs-sub){
  --bs-list-group-bg: var(--es-white);
  --bs-list-group-border-color: var(--es-border-subtle);
  --bs-list-group-border-radius: .625rem;     /* 10px shell, not the 6px control radius */
  border-radius:.625rem; overflow:hidden;
}
.list-group:not(.lhs):not(.lhs-sub) > .list-group-item{
  background: var(--es-white);
  border:0; border-bottom:.5px solid var(--es-grey-100);
  padding:.75rem .9375rem; color:var(--es-text-body);
}
.list-group:not(.lhs):not(.lhs-sub) > .list-group-item:last-child{ border-bottom:0; }
.list-group:not(.lhs):not(.lhs-sub) > .list-group-item:hover{ background:var(--es-grey-50); }

/* Content is white; only the page is grey. Stock Bootstrap paints these from --bs-body-bg, which is the page colour here. */
.table       { --bs-table-bg: var(--es-white); --bs-table-striped-bg: var(--es-row-stripe); }
/* An es-table's rows carry the stripe and the hover, so its cells must not paint over them. */
.table.es-table{ --bs-table-bg: transparent; }
.dropdown-menu{ --bs-dropdown-bg: var(--es-white); }
.modal       { --bs-modal-bg: var(--es-white); }
.accordion   { --bs-accordion-bg: var(--es-white); }
.pagination  { --bs-pagination-bg: var(--es-white); }
.popover     { --bs-popover-bg: var(--es-white); }
.offcanvas   { --bs-offcanvas-bg: var(--es-white); }
.nav-tabs    { --bs-nav-tabs-link-active-bg: var(--es-white); }
.form-check-input{ --bs-form-check-bg: var(--es-white); }

/* ----------------------------------------------------------------------------
   5. FORMS  — 1.5px "blue white" border, blue focus ring
---------------------------------------------------------------------------- */
.form-label{font-size:.75rem;font-weight:600;color:var(--es-text-body);margin-bottom:.3125rem}
.form-control,.form-select{font-family:var(--es-font-sans);font-size:.8125rem;color:var(--es-text-body);
  border:1.5px solid var(--es-border-input);border-radius:.375rem;padding:.5625rem .75rem;background-color:#fff}
/* Bootstrap draws a list's arrow on its right, so a list keeps its room for it. */
.form-select{padding-right:2.25rem}
/* A small field stays small, beside a btn-sm (the rule above would otherwise win over Bootstrap's -sm) */
.form-control-sm,.form-select-sm{padding:.25rem .5rem;font-size:.75rem;border-radius:.25rem}
.form-select-sm{padding-right:2rem}
.form-control:focus,.form-select:focus{border-color:var(--es-blue-800);box-shadow:var(--es-shadow-focus-soft);background-color:#fff}
.form-control.width-auto,.form-select.width-auto{display:inline-block;width:auto!important}
/* An .es-ribbon divider orphaned at the start/end of a wrapped 2nd tier is hidden by init.js (esRibbonCollapseDividers). */
.es-ribbon-divider--wrapped{display:none!important}
/* Legacy active-item marker: init.js injects <div class="ribbonItemSelected"> into the active ribbon item
   for backwards-compat; eSuite ribbons show the active item via the .active class instead. vlesupport-theme.css
   gives .ribbonItemSelected an aqua-tint background, so left visible it paints a stripe over the active tab's
   label. Hide it globally for every eSuite ribbon (covers ribbons that don't declare their own local rule,
   e.g. mentoring, providerManager). */
.es-ribbon .ribbonItemSelected,.es-ribbon-tab .ribbonItemSelected{display:none!important}
:root,[data-bs-theme=light]{--bs-form-invalid-color:var(--es-red-700)}
.form-control.is-invalid{border-color:var(--es-red-500)}
/* A focused field that needs changing keeps the field's focus ring, not Bootstrap's red glow. */
.form-control.is-invalid:focus,.form-select.is-invalid:focus{border-color:var(--es-red-500);box-shadow:var(--es-shadow-focus-soft)}
/* A field's error is never under 12px, as .small; and error text has the one red. */
.invalid-feedback{font-size:max(.75rem,.875em)}
.text-danger{color:var(--es-red-700)!important}
.form-text{font-size:.75rem;line-height:1.45;color:var(--es-text-muted)}
.form-check-input{width:1rem;height:1rem;border:1.5px solid var(--es-border-input);accent-color:var(--es-accent)}
.form-check-input:checked{background-color:var(--es-accent);border-color:var(--es-accent)}
/* Part-ticked as ticked; in a navy header a white edge keeps any box 3:1 against the navy (white 10:1, the accent inside it 5.7:1). */
.form-check-input:indeterminate{background-color:var(--es-accent);border-color:var(--es-accent)}
.es-table>thead .form-check-input,.es-table>thead .form-check-input:checked,.es-table>thead .form-check-input:indeterminate{border-color:#fff}
/* The rich-text editor in a field's look; "body" outranks the editor's own sheet, which loads after this one. */
body .note-editor.note-frame{border:1.5px solid var(--es-border-input);border-radius:.375rem;color:var(--es-text-body);font-family:var(--es-font-sans)}
body .note-editor.note-frame:focus-within{border-color:var(--es-blue-800);box-shadow:var(--es-shadow-focus-soft)}
body .note-editor.note-frame .note-editing-area .note-editable{font-size:.8125rem;color:var(--es-text-body)}
.form-check-input:focus{box-shadow:var(--es-focus-ring)}
.form-check-label{font-size:.8125rem;color:var(--es-text-body)}

/* ----------------------------------------------------------------------------
   6. ALERTS  — 4px left rule + tint + leading icon (NOT a full border)
---------------------------------------------------------------------------- */
.alert{font-size:.8125rem;line-height:1.3;border:none;border-left:4px solid;border-radius:.5rem;
  padding:.75rem 1rem;display:flex;gap:.625rem;align-items:flex-start;overflow-wrap:break-word;word-break:break-word}
/* Flex children must be allowed to shrink below their content width, or long text/tokens
   overflow the alert in a narrow column (e.g. a col-lg-2 sidebar). Icon keeps flex-shrink:0. */
.alert>*{min-width:0}
.alert>.es-alert-icon{font-size:1rem;flex-shrink:0;margin-top:2px}
.alert-info   {background:var(--es-aqua-50);border-left-color:var(--es-aqua-500);color:#006A8E}
.alert-warning{background:var(--es-yellow-50);border-left-color:var(--es-yellow-500);color:var(--es-yellow-700)}
.alert-danger {background:var(--es-red-50);border-left-color:var(--es-red-500);color:var(--es-red-700)}
.alert-success{background:var(--es-green-50);border-left-color:var(--es-green-500);color:var(--es-green-700)}
/* A link in an alert reads in the alert's own colour, still underlined. */
.alert a:where(:not([class]):not([role])){color:inherit}

/* ----------------------------------------------------------------------------
   7. PROGRESS  — 10px pill track, brand fill, label row above
---------------------------------------------------------------------------- */
.es-progress-label{display:flex;justify-content:space-between;font-size:.6875rem;color:var(--es-text-body);margin-bottom:var(--space-1)}
.es-progress-label .val{font-weight:600}
.progress{height:10px;background:var(--es-grey-100);border-radius:var(--radius-pill)}
.progress-bar{border-radius:var(--radius-pill);transition:width .3s var(--es-ease)}
.progress-bar.tone-aqua{background:var(--es-aqua-500)}.es-progress-label.tone-aqua .val{color:var(--es-aqua-500)}
.progress-bar.tone-green{background:var(--es-green-500)}.es-progress-label.tone-green .val{color:var(--es-green-500)}
.progress-bar.tone-orange{background:var(--es-orange-500)}.es-progress-label.tone-orange .val{color:var(--es-orange-500)}
.progress-bar.tone-red{background:var(--es-red-500)}.es-progress-label.tone-red .val{color:var(--es-red-500)}
.progress-bar.tone-blue{background:var(--es-blue-800)}.es-progress-label.tone-blue .val{color:var(--es-blue-800)}
.progress-bar.tone-yellow{background:var(--es-yellow-500)}.es-progress-label.tone-yellow .val{color:var(--es-yellow-700)}

/* ----------------------------------------------------------------------------
   8. TABLES (DataTable)  — navy header, zebra rows, blue-tint hover
      Canonical markup emitted by Table::render (see public/assets/lib/Table.php):
        <div class="es-table-wrap">
          <div class="es-table-scroll"><table class="es-table">
            <thead><tr><th><span class="es-th">
              <button class="es-th-label" …>Label <i class="fa-solid fa-sort"></i></button>
              <button class="es-th-funnel" data-filter …><i class="fa-solid fa-filter"></i></button>
            </span></th>…</tr></thead>
            <tbody><tr data-href…><td class="mono">…</td>…</tr></tbody>
          </table></div>
          <div class="es-table-foot">…pager…</div>
        </div>
      Funnel popover + client-side filter behaviour lives in /assets/js/esuite-table.js.
      Add .is-active to a .es-th-funnel when its column is filtered (turns aqua).
---------------------------------------------------------------------------- */
/* A table wider than its card scrolls sideways rather than being clipped at the card's edge. */
.es-table-wrap{background:#fff;border:1px solid var(--es-grid-line);border-radius:var(--radius-lg);overflow-x:auto;overflow-y:hidden;
  font-family:var(--es-font-sans)}
/* Sideways only: overflow-x alone makes y scroll too, and half-pixel rounding gave every table a 1px vertical scrollbar. The page scrolls. */
.es-table-scroll{overflow-x:auto;overflow-y:hidden}
/* In a card with no padding the card draws the frame, so the wrap does not draw a second one. */
.card-body.p-0>.es-table-wrap,.card-body.p-0>.table-responsive>.es-table-wrap{border:0;border-radius:0}

.es-table{width:100%;border-collapse:collapse;font-size:13.5px;color:var(--es-grey-700);margin:0}

/* Header — navy bar, white text */
.es-table>thead>tr>th{background:var(--es-blue-900,#293F6D);color:#fff;font-weight:600;font-size:var(--text-sm);
  text-align:left;padding:9px 14px;white-space:nowrap;vertical-align:middle;position:sticky;top:0;z-index:1}
.es-table.head-orange>thead>tr>th{background:var(--es-orange-500)}
/* A 24px sort or filter button takes 4px of the padding, so the row keeps its height. */
.es-table>thead>tr>th:has(.es-th-label,.es-th-funnel){padding-top:7px;padding-bottom:7px}
/* The label and its sort icon on the left, the filter at the cell's right edge; a number column keeps its label by the filter. */
.es-th{display:flex;align-items:center;gap:var(--space-1);width:100%}
.es-table>thead>tr>th.es-num .es-th-label{margin-left:auto}
.es-th-label{display:inline-flex;align-items:center;gap:7px;min-height:24px;background:none;border:0;padding:0;margin:0;
  cursor:pointer;color:#fff;font:600 13px var(--es-font-sans)}
.es-th-label>i{font-size:var(--text-2xs);color:var(--text-on-navy-muted);transition:color .12s}
.es-th-label:hover>i{color:#fff}
/* Funnel */
.es-th-funnel{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:var(--radius-xs);
  border:0;padding:0;margin-left:auto;cursor:pointer;font-size:var(--text-2xs);background:transparent;flex:none;
  color:var(--text-on-navy-muted);transition:background .12s,color .12s}
.es-table>thead>tr>th.es-num .es-th-funnel{margin-left:2px}
.es-th-funnel:hover{color:#fff}
.es-th-funnel.is-active{color:#fff;background:rgba(255,255,255,.3)}

/* Body — striped + aqua hover */
.es-table>tbody>tr{transition:background .12s}
/* Only a row that opens something says so; elsewhere the row's own link does */
.es-table>tbody>tr[data-href],.es-table>tbody>tr[onclick]{cursor:pointer}
.es-table>tbody>tr:nth-child(even){background:var(--es-row-stripe)}
.es-table>tbody>tr:hover{background:var(--es-aqua-50,#DFF4FC)}
.es-table>tbody>tr>td{padding:9px 14px;border:1px solid var(--es-grid-line);white-space:nowrap;vertical-align:middle}
/* Grid: a line round every cell, faint separators on the navy header; the wrap or card draws the outside edge. */
.es-table>thead>tr>th:not(:last-child){box-shadow:inset -1px 0 0 rgba(255,255,255,.22)}
.es-table>tbody>tr:first-child>td{border-top:0}
.es-table>tbody>tr>td:first-child{border-left:0}
.es-table>tbody>tr>td:last-child{border-right:0}
.es-table-wrap .es-table>tbody>tr:last-child>td{border-bottom:0}
.es-table>tfoot>tr>td{border-top:1px solid var(--es-grid-line)}
/* IDs, references and dates line up by tabular figures, never by a monospace face. */
.es-table td.mono,.es-table .mono{font-variant-numeric:tabular-nums}
.es-table td.strong,.es-table .strong{font-weight:600;color:var(--es-blue-900,#293F6D)}
.es-table a{color:var(--es-aqua-700,#0673A1);text-decoration:none}
.es-table a:hover{text-decoration:underline}
.es-table a:where(:not([class]):not([role])){color:var(--text-link);text-decoration:underline;text-underline-offset:2px}
/* Buttons embedded in a cell are not links — never underline them (the gap between icons was showing as a stray "_") */
.es-table a.btn,.es-table a.btn:hover,.es-table a.btn:focus{text-decoration:none}
/* ...and not aqua-text either. .es-table a above sets colour for a plain row link, but wins over
   .btn's own --bs-btn-color by specificity (class+element beats class alone) — so a colour-filled
   button rendered as an <a> (e.g. btn-primary, btn-danger) showed its own fill colour as text
   instead of the white every other .btn of that colour gets. Read the button's own variable back. */
.es-table a.btn{color:var(--bs-btn-color)}

/* Auto-fit — equal-width columns that truncate (ellipsis) so the table fits the viewport (opt-in via Table "autoFit") */
.es-table.es-table-fit{table-layout:fixed}
.es-table.es-table-fit>thead>tr>th,.es-table.es-table-fit>tbody>tr>td{overflow:hidden;text-overflow:ellipsis}
.es-table.es-table-fit>thead>tr>th .es-th{max-width:100%}
.es-table.es-table-fit>thead>tr>th .es-th-label{min-width:0;overflow:hidden;text-overflow:ellipsis}

/* Column sizing: drag a heading's right-hand edge, double-click to reset; esuite-table.js pins the widths.
   The heading is sticky, which already makes it the grip's positioning box. */
.es-col-grip{position:absolute;top:0;right:0;width:24px;height:100%;cursor:col-resize;touch-action:none;
  -webkit-user-select:none;user-select:none;z-index:2}
.es-col-grip::after{content:"";position:absolute;top:22%;right:4px;width:1px;height:56%;
  background:transparent;transition:background var(--es-dur) var(--es-ease),width var(--es-dur) var(--es-ease)}
.es-col-grip:hover::after{background:var(--es-aqua-400);width:2px}
/* Drawn inside the heading's edge, where a ring outside it would be clipped. */
.es-col-grip:focus-visible{outline:2px solid #fff!important;outline-offset:-2px!important;box-shadow:none!important;border-radius:2px}
/* Room for the grip's 24px target beside a heading's filter button, so the two never overlap. */
.es-table.es-table-grips>thead>tr>th:not(:last-child){padding-right:26px}
.es-table.es-resizing{-webkit-user-select:none;user-select:none;cursor:col-resize}
.es-table.es-resizing .es-col-grip::after{background:var(--es-aqua-400);width:2px}
/* Pinned widths only hold under a fixed layout, so anything too long is clipped rather than pushing out. */
.es-table.es-table-sized{table-layout:fixed}
.es-table.es-table-sized>thead>tr>th,.es-table.es-table-sized>tbody>tr>td{overflow:hidden;text-overflow:ellipsis}
.es-table.es-table-sized>thead>tr>th .es-th{max-width:100%}
.es-table.es-table-sized>thead>tr>th .es-th-label{min-width:0;overflow:hidden;text-overflow:ellipsis}
/* A heading wraps when its column is tight, so a column of short values narrows to its data instead of a text column being cut. */
.es-table>thead>tr>th,.es-table>thead>tr>th .es-th-label{white-space:normal}
.es-table>thead>tr>th.es-num .es-th-label{text-align:right}
.es-table.es-table-fit>thead>tr>th .es-th-label,.es-table.es-table-sized>thead>tr>th .es-th-label{overflow:visible;text-overflow:clip}
/* A disclosure in a cell opens downwards in lines, never sideways past the card. */
.es-table td details[open]{white-space:normal}
.es-table td .es-cell-detail{display:block;max-width:28rem;margin-left:auto;white-space:normal}

/* Active-filter chip toolbar */
.es-table-filters{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-2);padding:9px 14px;
  background:var(--es-surface-sunken);border-bottom:.5px solid var(--es-border-subtle)}
.es-table-filters .es-filters-label{font:600 var(--es-text-group-label) var(--es-font-sans);color:var(--es-text-muted)}
.es-chip{display:inline-flex;align-items:center;gap:6px;padding:3px 5px 3px 10px;border:1px solid currentColor;border-radius:var(--radius-pill);
  background:var(--es-aqua-50,#DFF4FC);color:var(--es-aqua-700,#0673A1);font:600 12px var(--es-font-sans)}
.es-chip button{border:0;background:transparent;color:var(--es-aqua-700,#0673A1);cursor:pointer;font-size:var(--text-xs);line-height:1;padding:2px}
.es-clear-all{margin-left:auto;border:1.5px solid var(--es-grey-100,#E1E6EB);border-radius:var(--radius-sm);padding:5px var(--space-3);
  font:600 12px var(--es-font-sans);color:var(--es-grey-700,#4D4D4D);background:#fff;cursor:pointer;white-space:nowrap}
.es-clear-all:hover{background:var(--es-grey-50,#F1F2F7)}

/* ---- Funnel filter popover (Excel-style: search checklist + condition row) ---- */
/* A row's ⋯ menu in a server-paged table (es_data_table kind actions), placed by es-float.js */
.es-dt-actions{width:1%;white-space:nowrap;text-align:center}
/* A centred column (es_data_table align center): its heading's label and funnel, and its cells */
.es-table>thead>tr>th.es-dt-center,.es-table>thead>tr>th.es-dt-center.es-num{text-align:center}
.es-table>thead>tr>th.es-dt-center .es-th{justify-content:center}
.es-table>thead>tr>th.es-dt-center .es-th-label,.es-table>thead>tr>th.es-dt-center .es-th-funnel{margin-left:0;margin-right:0}
.es-table>tbody>tr>td.es-dt-center,.es-table>tbody>tr>td.es-dt-center.es-num{text-align:center}
.es-row-menu-btn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border:1.5px solid transparent;border-radius:var(--radius-sm);background:transparent;color:var(--es-text-muted);cursor:pointer}
.es-row-menu-btn:hover,.es-row-menu-btn[aria-expanded="true"]{border-color:var(--es-border-control-subtle);background:var(--es-white);color:var(--es-blue-800)}
.es-row-menu{z-index:1100;min-width:12rem;padding:var(--space-1) 0;background:#fff;border:.5px solid var(--es-border-subtle);border-radius:var(--radius-md);box-shadow:var(--shadow-md);text-align:left}
.es-row-menu[hidden]{display:none}
.es-row-menu-item{display:flex;align-items:center;gap:var(--space-2);width:100%;min-height:32px;padding:var(--space-2) var(--space-3);border:0;background:transparent;color:var(--es-text-body);font-size:var(--text-sm);text-align:left;cursor:pointer}
.es-row-menu-item:hover,.es-row-menu-item:focus-visible{background:var(--es-blue-tint);color:var(--es-blue-900)}
.es-row-menu-item[hidden]{display:none}
.es-row-menu-item>i{width:16px;color:var(--es-text-muted)}
.es-filter-menu{position:fixed;z-index:1100;width:264px;background:#fff;border:.5px solid var(--es-border-subtle);
  border-radius:12px;box-shadow:0 12px 32px rgba(10,26,47,.22);overflow:hidden;font-family:var(--es-font-sans);
  color:var(--es-grey-700,#4D4D4D);animation:esMenuIn .12s var(--es-ease)}
@keyframes esMenuIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
.es-fm-head{display:flex;align-items:center;gap:var(--space-2);padding:9px var(--space-3);background:var(--es-surface-sunken);
  border-bottom:.5px solid var(--es-border-subtle)}
.es-fm-head>i{font-size:var(--text-2xs);color:var(--es-blue-900,#293F6D)}
.es-fm-head strong{font:600 var(--text-sm) var(--es-font-sans);color:var(--es-blue-900,#293F6D);flex:1}
.es-fm-body{padding:10px var(--space-3)}
.es-fm-search,.es-fm-val,.es-fm-op{width:100%;box-sizing:border-box;padding:6px 9px;border-radius:var(--radius-sm);
  border:1.5px solid var(--es-border-input,#8C8C8C);font:400 13px var(--es-font-sans);color:var(--es-grey-700,#4D4D4D);background:#fff;outline:none}
.es-fm-search:focus,.es-fm-val:focus,.es-fm-op:focus{border-color:var(--es-aqua-500,#00AEEF);box-shadow:0 0 0 3px rgba(0,174,239,.25)}
.es-fm-list{max-height:168px;overflow-y:auto;margin:var(--space-2) 0 0;border:1px solid var(--es-grey-100,#E1E6EB);border-radius:var(--radius-sm)}
.es-fm-opt{display:flex;align-items:center;gap:var(--space-2);padding:6px 9px;font-size:var(--text-sm);cursor:pointer}
.es-fm-opt:hover{background:var(--es-grey-50,#F1F2F7)}
.es-fm-opt input{accent-color:var(--es-aqua-500,#00AEEF);width:15px;height:15px;flex:none}
.es-fm-opt span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.es-fm-opt.all{border-bottom:1px solid var(--es-grey-100,#E1E6EB);font-weight:600;position:sticky;top:0;background:#fff}
.es-fm-cond{display:flex;gap:6px;margin-top:10px}
.es-fm-op{flex:0 0 96px}
.es-fm-divider{margin:10px 0 0;font:600 var(--es-text-group-label) var(--es-font-sans);color:var(--es-text-muted)}
.es-fm-foot{display:flex;gap:var(--space-2);padding:10px var(--space-3);border-top:.5px solid var(--es-border-subtle);background:var(--es-surface-sunken)}
.es-fm-foot button{flex:1;padding:7px 10px;border-radius:var(--radius-sm);font:600 12px var(--es-font-sans);cursor:pointer}
.es-fm-clear{border:1.5px solid var(--es-grey-100,#E1E6EB);background:#fff;color:var(--es-grey-700,#4D4D4D)}
.es-fm-clear:hover{background:#fff;border-color:var(--es-grey-300,#C7CCD4)}
.es-fm-apply{border:none;background:var(--es-blue-900,#293F6D);color:#fff}
.es-fm-apply:hover{opacity:.9}

/* Footer / pagination */
.es-table-foot{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px;
  padding:10px var(--space-4);border-top:.5px solid var(--es-border-subtle);background:#fff}
.es-table-foot .es-foot-count{font:400 12px var(--es-font-sans);color:var(--es-text-muted)}
/* Rows-per-page selector */
.es-foot-size{display:inline-flex;align-items:center;gap:var(--space-2);margin-left:auto}
.es-foot-size label{margin:0;font:500 12px var(--es-font-sans);color:var(--es-text-muted)}
.es-foot-select{height:34px;padding:0 30px 0 11px;border:1px solid var(--es-border-input,#8C8C8C);border-radius:var(--radius-sm);background-color:#fff;
  color:var(--es-grey-700,#4D4D4D);font:600 13px var(--es-font-sans);cursor:pointer;appearance:none;-webkit-appearance:none;-moz-appearance:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%234D4D4D' stroke-width='2'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 9px center;background-size:14px}
.es-foot-select:focus{outline:none;border-color:var(--es-aqua-500,#00AEEF);box-shadow:0 0 0 3px rgba(0,174,239,.25)}
/* Legacy server-side pager (Bootstrap .pagination emitted by Table::render) sits in the foot — proper bordered buttons */
.es-table-foot .pagination{margin:0;display:inline-flex;flex-wrap:wrap;gap:var(--space-1);padding-left:0;list-style:none}
.es-table-foot .pagination>li{display:inline-flex}
.es-table-foot .pagination>li>a{display:inline-flex;align-items:center;justify-content:center;min-width:34px;height:34px;padding:0 10px;
  border:1px solid var(--es-grey-100,#E1E6EB);border-radius:var(--radius-sm);background:#fff;color:var(--es-grey-700,#4D4D4D);
  font:600 13px var(--es-font-sans);line-height:1;text-decoration:none;cursor:pointer;transition:background .12s,border-color .12s,color .12s}
.es-table-foot .pagination>li>a:hover{background:var(--es-grey-50,#F1F2F7);border-color:var(--es-grey-300,#C7CCD4);color:var(--es-blue-900,#293F6D)}
.es-table-foot .pagination>li.active>a{border:1.5px solid var(--es-blue-800,#4265AF);background:var(--es-blue-800,#4265AF);color:#fff;cursor:default}
.es-table-foot .pagination>li.disabled>a{opacity:.45;background:var(--es-grey-50,#F1F2F7);cursor:not-allowed;pointer-events:none}
/* The server-paged table's pager (es-data-table.js): buttons, drawn like the links above; a gap is a plain mark. */
.es-table-foot .pagination>li>button,.es-table-foot .pagination>li>span{display:inline-flex;align-items:center;justify-content:center;min-width:34px;height:34px;padding:0 10px;
  border:1px solid var(--es-grey-100,#E1E6EB);border-radius:var(--radius-sm);background:#fff;color:var(--es-grey-700,#4D4D4D);font:600 13px var(--es-font-sans);line-height:1;
  cursor:pointer;transition:background var(--es-dur) var(--es-ease),border-color var(--es-dur) var(--es-ease),color var(--es-dur) var(--es-ease)}
.es-table-foot .pagination>li>button:hover:not(:disabled){background:var(--es-grey-50,#F1F2F7);border-color:var(--es-grey-300,#C7CCD4);color:var(--es-blue-900,#293F6D)}
.es-table-foot .pagination>li.active>button{border:1.5px solid var(--es-blue-800,#4265AF);background:var(--es-blue-800,#4265AF);color:#fff;cursor:default}
.es-table-foot .pagination>li>button:disabled{opacity:.45;background:var(--es-grey-50,#F1F2F7);cursor:not-allowed}
.es-table-foot .pagination>li>span{border-color:transparent;background:transparent;cursor:default}
.es-data-table .es-table-filters[hidden],.es-data-table .es-filter-menu[hidden]{display:none}
/* While a server-paged table fetches, its rows fade, so stale rows are not taken for the answer. */
.es-data-table[aria-busy="true"] tbody{opacity:.55;transition:opacity var(--es-dur) var(--es-ease)}
/* A cell holding several items, one a line (a learner's courses). */
.es-table td.es-wrap.es-pre-line{white-space:pre-line}

/* Navy dropdown menu — matches the system nav chrome; opt-in via .es-dropdown-navy on a Bootstrap .dropdown-menu */
.dropdown-menu.es-dropdown-navy{background:var(--es-blue-900,#293F6D);border:1px solid rgba(255,255,255,.12);border-radius:var(--radius-lg);
  box-shadow:var(--es-shadow-md,0 8px 24px rgba(10,26,47,.22));padding:6px;min-width:240px}
.dropdown-menu.es-dropdown-navy .dropdown-item{display:flex;align-items:center;gap:9px;color:rgba(255,255,255,.9);
  border-radius:var(--radius-sm);padding:var(--space-2) var(--space-3);font-size:var(--text-sm);white-space:nowrap}
.dropdown-menu.es-dropdown-navy .dropdown-item:hover,.dropdown-menu.es-dropdown-navy .dropdown-item:focus{background:rgba(255,255,255,.12);color:#fff}
.dropdown-menu.es-dropdown-navy .dropdown-item .text-danger{color:#F36B6B!important}
.dropdown-menu.es-dropdown-navy .dropdown-divider{border-top-color:rgba(255,255,255,.14)}
.es-pager{display:inline-flex;gap:var(--space-1)}
.es-pager button{min-width:30px;height:30px;border-radius:var(--radius-sm);cursor:pointer;font:600 12px var(--es-font-sans);
  border:1px solid var(--es-grey-100,#E1E6EB);background:#fff;color:var(--es-grey-700,#4D4D4D)}
.es-pager button[aria-current="page"]{border:1.5px solid var(--es-aqua-500,#00AEEF);background:var(--es-aqua-50,#DFF4FC);color:var(--es-aqua-700,#0673A1)}
.es-pager button:disabled{opacity:.4;cursor:not-allowed}

/* ----------------------------------------------------------------------------
   9. BESPOKE — no Bootstrap equivalent
---------------------------------------------------------------------------- */
/* Avatar — initials chip */
.es-avatar{width:40px;height:40px;border-radius:50%;background:var(--es-avatar-fill-default);color:#fff;
  display:inline-flex;align-items:center;justify-content:center;font-weight:600;font-size:.875rem;flex-shrink:0}
/* Inverse, for the top bar: white with the bar's blue initials */
.es-avatar-inverse{background:var(--es-white);color:var(--navy-800)}

/* Status dot */
.es-status{display:inline-flex;align-items:center;gap:6px;font-size:.8125rem;color:var(--es-text-body)}
.es-status::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--es-grey-400)}
.es-status.tone-green::before{background:var(--es-green-500)}
.es-status.tone-orange::before{background:var(--es-orange-500)}
.es-status.tone-red::before{background:var(--es-red-500)}
.es-status.tone-aqua::before{background:var(--es-aqua-500)}

/* Metric tile */
.es-metric{background:var(--es-white);border:.5px solid var(--es-border-subtle);border-radius:.5rem;
  padding:.875rem 1rem;text-align:center}
.es-metric .val{font-size:1.625rem;font-weight:600;line-height:1;color:var(--es-blue-800);font-variant-numeric:tabular-nums}
/* Figure tones use the -600/-700 steps: the bright -500 fills fail 3:1 even at this size. */
.es-metric .val.tone-green{color:var(--es-green-700)}.es-metric .val.tone-orange{color:var(--es-orange-600)}
.es-metric .val.tone-red{color:var(--es-red-700)}.es-metric .val.tone-aqua{color:var(--es-aqua-700)}
.es-metric .lbl{font-size:.75rem;line-height:1.4;color:var(--es-text-muted);margin-top:6px}

/* Numbers in a column: right-aligned, digits the same width. */
.es-num,.es-table>thead>tr>th.es-num{text-align:right;font-variant-numeric:tabular-nums}
/* Hints, notes and captions: 12px muted, sentence case, never italic. */
.es-hint{font-size:.75rem;line-height:1.45;color:var(--es-text-muted)}
/* An error takes its field's hint's place. */
.is-invalid ~ .es-hint,.input-group:has(> .is-invalid) ~ .es-hint{display:none}

/* Vertical (sidebar) nav — variant 1i: navy panel, white current-page fill + 4px orange rail
   (matches the ul.lhs VerticalNav in §10). */
.es-vnav{background:var(--es-blue-900);border-radius:.625rem;padding:var(--space-2) 0;min-width:232px;overflow:hidden}
.es-vnav a{display:flex;align-items:center;gap:10px;padding:10px var(--space-4);font-size:.8125rem;
  color:rgba(255,255,255,.82);border-left:4px solid transparent;text-decoration:none;
  transition:background var(--es-dur) var(--es-ease),color var(--es-dur) var(--es-ease)}
.es-vnav a i{width:18px;text-align:center;font-size:15px;color:rgba(255,255,255,.6)}
.es-vnav a:hover{background:rgba(255,255,255,.06);color:#fff}
.es-vnav a:hover i{color:var(--text-on-navy-muted)}
.es-vnav a:focus-visible{box-shadow:inset 0 0 0 2px #fff,inset 0 0 0 4px var(--es-blue-900)!important}
/* Current page — white fill + navy text + 4px orange rail + navy icon */
.es-vnav a.active{background:#fff;color:var(--es-blue-900,#293F6D);font-weight:600;
  border-left-color:var(--es-orange-500,#FA650D)}
.es-vnav a.active i{color:var(--es-blue-800,#4265AF)}
.es-vnav a.active .badge{background:var(--es-blue-tint,#E7ECF6)!important;color:var(--es-blue-800,#4265AF)!important}
/* Default/home item (e.g. Course Detail) — persistent slightly-lighter navy so the landing
   page stands out when a different sub-page is active. The active state wins (:not(.active))
   so the home item still gets the orange current-page rail when it IS the open page. */
.es-vnav a.nav-home:not(.active){background:var(--es-blue-850,#33497D);color:#fff}
.es-vnav a.nav-home:not(.active) i{color:var(--text-on-navy-muted)}

/* In-screen underline tabs (DS "Tabs") */
.es-tabs{display:flex;border-bottom:2px solid var(--es-grey-100)}
.es-tabs button{appearance:none;background:none;border:none;cursor:pointer;padding:9px var(--space-4);margin-bottom:-2px;
  font:600 .8125rem var(--es-font-sans);color:var(--es-text-muted);border-bottom:2px solid transparent}
.es-tabs button.active{color:var(--es-accent-press);border-bottom-color:var(--es-blue-800)}

/* Workspace tabs (folder tabs below chrome) — server-rendered, JS wires interactions */
.es-wtabs{display:flex;align-items:flex-end;gap:3px;background:var(--es-grey-100);padding:7px 14px 0;min-height:43px;overflow-x:auto;scrollbar-width:thin}
.es-wtabs::-webkit-scrollbar{height:6px}.es-wtabs::-webkit-scrollbar-thumb{background:var(--es-grey-300);border-radius:3px}
.es-wtab{position:relative;display:flex;align-items:center;gap:9px;height:36px;padding:0 11px 0 14px;
  flex:0 1 auto;min-width:48px;max-width:220px;border-radius:9px 9px 0 0;cursor:pointer;user-select:none;
  white-space:nowrap;font:500 .8125rem/1.2 var(--es-font-sans);color:var(--es-grey-700);
  transition:background var(--es-dur) var(--es-ease),color var(--es-dur) var(--es-ease)}
.es-wtab:not(.active):hover{background:rgba(255,255,255,.55);color:var(--es-blue-800)}
.es-wtab.active{background:#fff;color:var(--es-blue-800);font-weight:600;z-index:3;flex-shrink:.35;min-width:96px}
.es-wtab.active::before,.es-wtab.active::after{content:"";position:absolute;bottom:0;width:10px;height:10px;background:#fff}
.es-wtab.active::before{left:-10px;-webkit-mask:radial-gradient(circle at top left,#0000 10px,#000 10.5px);mask:radial-gradient(circle at top left,#0000 10px,#000 10.5px)}
.es-wtab.active::after{right:-10px;-webkit-mask:radial-gradient(circle at top right,#0000 10px,#000 10.5px);mask:radial-gradient(circle at top right,#0000 10px,#000 10.5px)}
.es-wtab .lead{font-size:var(--text-xs);width:13px;text-align:center;flex-shrink:0;color:var(--es-grey-400)}
.es-wtab.active .lead{color:var(--es-accent)}
.es-wtab .title{overflow:hidden;text-overflow:ellipsis;min-width:0;flex:0 1 auto}
.es-wtab .close{width:19px;height:19px;border:none;background:transparent;border-radius:5px;color:var(--es-grey-400);
  cursor:pointer;font-size:var(--text-2xs);flex-shrink:0;display:inline-flex;align-items:center;justify-content:center}
.es-wtab .close:hover{background:rgba(159,159,159,.26);color:var(--es-blue-900)}
.es-wtab .pin{font-size:10px;color:var(--es-accent);opacity:.7;margin-left:1px;transform:rotate(40deg);flex-shrink:0}
.es-wtab.dragging{opacity:.4}.es-wtab.drop-target{box-shadow:inset 2.5px 0 0 0 var(--es-accent)}

/* ----------------------------------------------------------------------------
   9b. MODULE RIBBON  (.es-ribbon)
   The per-module action strip: a white bar under the top bar, joined to the current area's tab, with a hairline below. Shared,
   authoritative styling: a module ribbon.php carries markup only (container .es-ribbon, items .es-ribbon-tab or <a>) and no
   <style> of its own, so every ribbon looks the same and wraps (never scrolls). Tokens only.

   Two active mechanisms are both supported:
     · .es-ribbon-tab.active            — set server-side (e.g. home/ribbon.php)
     · .es-ribbon-tab:has(.ribbonItemSelected)
                                        — init.js injects <div.ribbonItemSelected>
                                          into the item matching `var activeRibbon`
   The injected marker itself stays hidden (rule in §5); the parent chip shows the active state. Accessibility (WCAG 2.2 AA): 30px
   chips (24px is the floor), a 3:1 border, an active cue that is not colour (the dot and the weight), the shared focus ring.
---------------------------------------------------------------------------- */
.es-ribbon{display:flex;flex-wrap:wrap;align-items:center;gap:6px;padding:10px 16px;background:var(--es-white);border-bottom:1px solid var(--grey-100)}
.es-ribbon .hidden{display:none!important}
.es-ribbon a,.es-ribbon .es-ribbon-tab{
  display:inline-flex;align-items:center;gap:var(--space-2);min-height:30px;padding:6px 12px;
  border:1.5px solid var(--es-border-control-subtle);border-radius:6px;background:var(--es-white);
  color:var(--grey-700);font-size:12px;font-weight:500;line-height:1.2;
  text-decoration:none;white-space:nowrap;cursor:pointer;position:static;top:auto;
  transition:background .12s var(--es-ease),color .12s var(--es-ease),border-color .12s var(--es-ease)}
.es-ribbon a>i,.es-ribbon .es-ribbon-tab>i{color:var(--es-text-muted);font-size:13px}
.es-ribbon a:hover,.es-ribbon .es-ribbon-tab:hover{
  border-color:var(--es-blue-600);background:var(--es-white);color:var(--es-blue-800)!important}
/* active — orange frame + tint + leading dot + semibold orange label */
.es-ribbon a.active,.es-ribbon .es-ribbon-tab.active,
.es-ribbon .es-ribbon-tab:has(.ribbonItemSelected){
  border-color:var(--orange-500);background:var(--orange-50);color:var(--orange-700)!important;font-weight:600}
.es-ribbon a.active>i,.es-ribbon .es-ribbon-tab.active>i,
.es-ribbon .es-ribbon-tab:has(.ribbonItemSelected)>i{color:var(--orange-700)}
.es-ribbon a.active::before,.es-ribbon .es-ribbon-tab.active::before,
.es-ribbon .es-ribbon-tab:has(.ribbonItemSelected)::before{
  content:"";width:6px;height:6px;border-radius:var(--radius-pill);background:var(--orange-500);flex:none}
/* counter badge — outlined pill (not colour-only) */
.es-ribbon .es-tab-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;
  height:18px;padding:0 6px;border-radius:var(--radius-pill);font-family:var(--es-font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-2xs);font-weight:700;line-height:1}
.es-ribbon .es-tab-badge-red   {background:var(--es-red-50);color:var(--es-red-700);border:1px solid var(--es-red-500)}
.es-ribbon .es-tab-badge-aqua  {background:var(--es-aqua-50);color:var(--es-aqua-700);border:1px solid var(--es-aqua-500)}
.es-ribbon .es-tab-badge-orange{background:var(--es-orange-50);color:var(--es-orange-700);border:1px solid var(--es-orange-500)}
.es-ribbon .es-tab-badge-navy  {background:var(--es-blue-tint);color:var(--es-blue-800);border:1px solid var(--es-blue-600)}
.es-ribbon .es-tab-badge-yellow{background:var(--es-yellow-50);color:var(--es-yellow-700);border:1px solid var(--es-yellow-500)}
.es-ribbon .es-tab-badge-green {background:var(--es-green-50);color:var(--es-green-700);border:1px solid var(--es-green-500)}
.es-ribbon .es-tab-badge-grey  {background:var(--es-grey-50);color:var(--es-grey-700);border:1px solid var(--es-grey-400)}
/* chips are self-delimiting — retire inline separators */
.es-ribbon .es-ribbon-divider{display:none}
/* A page in an area that draws no ribbon: the same white bar under the tab, empty (navigation.php prints it) */
.es-ribbon-spacer{height:20px;background:var(--es-white);border-bottom:1px solid var(--grey-100)}
body:has(.es-ribbon) .es-ribbon-spacer{display:none}
/* Page help: the "?" beside a page title, and what its modal shows */
.page-help-btn{display:inline-flex;align-items:center;justify-content:center;min-height:24px;background:none;border:0;padding:0;
  margin:0 0 0 .4rem;color:var(--es-blue-800);font-size:1.05rem;line-height:1;cursor:pointer;vertical-align:middle;border-radius:var(--radius-pill);transition:opacity .12s var(--es-ease)}
.page-help-btn:hover{opacity:.75}
.page-help-btn--nav{color:var(--es-white);font-size:1.15rem;min-width:36px;min-height:36px;margin:0 .25rem}
.page-help-title{display:inline-block;vertical-align:middle}
.page-help-content img{max-width:100%;height:auto}
.page-help-content table{width:100%}
.page-help-content>:last-child{margin-bottom:0}
/* In-page ribbon (.es-subribbon): the module ribbon's chips at in-page size, switching the views of one record */
.es-subribbon{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-2)}
.es-subribbon a{display:inline-flex;align-items:center;gap:var(--space-2);min-height:36px;padding:7px var(--space-3);
  border:1.5px solid var(--es-border-control-subtle);border-radius:var(--radius-md);background:var(--es-white);
  color:var(--es-grey-700);font-size:var(--text-sm);font-weight:500;line-height:1.2;text-decoration:none;white-space:nowrap;
  transition:background .12s var(--es-ease),color .12s var(--es-ease),border-color .12s var(--es-ease)}
.es-subribbon a>i{color:var(--es-text-muted);font-size:14px}
.es-subribbon a:hover{border-color:var(--es-blue-600);color:var(--es-blue-800)}
.es-subribbon a.active{border-color:var(--es-orange-500);background:var(--es-orange-50);color:var(--es-blue-900);font-weight:600}
.es-subribbon a.active>i{color:var(--es-orange-600)}
.es-subribbon a.active::before{content:"";width:8px;height:8px;border-radius:var(--radius-pill);background:var(--es-orange-500);flex:none}

/* ----------------------------------------------------------------------------
   9b+. Legacy ribbon counters
   Solid-fill counter circles (.label-as-badge) some ribbons ship (woodson, claims, jobsList, mentoring, opsManager,
   continuousimprovement) get a translucent-dark edge, so every counter circle is outlined, whatever its fill.
---------------------------------------------------------------------------- */
.es-ribbon .label-as-badge{border:1px solid rgba(0,0,0,.3)}

/* ----------------------------------------------------------------------------
   9c. Priority-overflow (⋯ More) — shared by the ribbon + workspace tabs
   A strip managed by /assets/js/es-chrome-overflow.js is given .es-ovf-on: it
   stops wrapping, clips the overflow, and folds the items that don't fit into a
   trailing ⋯ dropdown. The base strips keep their flex-wrap fallback for the
   no-JS / in-overlay (unmanaged) case, so this never breaks a modal ribbon.
---------------------------------------------------------------------------- */
.es-ovf-on{flex-wrap:nowrap!important;overflow:hidden!important}
.es-ovf-hidden{display:none!important}
.es-ovf-more[hidden],.es-ovf-menu[hidden]{display:none!important}
.es-ovf-more{display:inline-flex;align-items:center;gap:6px;flex:none;cursor:pointer;
  border:1.5px solid var(--es-border-control-subtle,#67728A);border-radius:var(--radius-md);background:#fff;
  color:var(--es-grey-700,#4D4D4D);font-family:'Poppins',system-ui,sans-serif;
  transition:background .12s var(--es-ease),color .12s var(--es-ease),border-color .12s var(--es-ease)}
.es-ovf-more:hover{border-color:var(--es-blue-600,#5481E0);color:var(--es-blue-800,#4265AF)}
.es-ovf-more[aria-expanded="true"]{border-color:var(--es-blue-600,#5481E0);
  color:var(--es-blue-800,#4265AF);background:var(--es-blue-tint,#E7ECF6)}
.es-ovf-more>i{font-size:15px}
.es-ovf-count{font-family:var(--es-font-sans);font-variant-numeric:tabular-nums;font-size:var(--text-2xs);font-weight:700;line-height:1}
.es-ovf-count:empty{display:none}
/* ⋯ sized to sit in each strip */
.es-ribbon .es-ovf-more{min-height:30px;padding:6px 12px;font-size:12px}
#esWorkspaceTabs .es-ovf-more{min-height:42px;padding:10px var(--space-3);align-self:flex-end;font-size:var(--text-sm);font-weight:500}

/* the dropdown panel (body-mounted) */
.es-ovf-menu{position:fixed;z-index:1080;min-width:220px;max-width:340px;max-height:70vh;overflow-y:auto;
  background:#fff;border:.5px solid rgba(10,26,47,.10);border-radius:var(--radius-lg);padding:6px;
  box-shadow:0 12px 28px rgba(10,26,47,.14);font-family:'Poppins',system-ui,sans-serif}
.es-ovf-item{display:flex;align-items:center;gap:2px;border-radius:var(--radius-sm)}
a.es-ovf-item,.es-ovf-link{display:flex;align-items:center;gap:11px;flex:1 1 auto;min-width:0;
  padding:9px 11px;border-radius:var(--radius-sm);text-decoration:none;font-size:var(--text-sm);font-weight:500;
  color:var(--es-grey-700,#4D4D4D)}
a.es-ovf-item:hover,.es-ovf-link:hover,.es-ovf-item:hover{background:var(--es-aqua-50,#DFF4FC);color:var(--es-blue-900,#293F6D)}
a.es-ovf-item>i,.es-ovf-link>i{width:16px;text-align:center;font-size:var(--text-sm);color:var(--es-grey-400,#9F9F9F);flex:none}
a.es-ovf-item:hover>i,.es-ovf-item:hover .es-ovf-link>i{color:var(--es-aqua-500,#00AEEF)}
.es-ovf-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
a.es-ovf-item.is-current,.es-ovf-item.is-current{background:var(--es-orange-50,#FEE8D8)}
a.es-ovf-item.is-current .es-ovf-label,.es-ovf-item.is-current .es-ovf-label{color:var(--es-blue-900,#293F6D);font-weight:600}
.es-ovf-item .es-tab-badge,.es-ovf-item .label,a.es-ovf-item .es-tab-badge,a.es-ovf-item .label{margin-left:auto}
.es-ovf-x{flex:none;width:26px;height:26px;border:none;background:transparent;border-radius:var(--radius-sm);cursor:pointer;
  color:var(--es-text-muted,#6B6B6B);display:inline-flex;align-items:center;justify-content:center;font-size:var(--text-xs)}
.es-ovf-x:hover{background:var(--es-red-50,#FDDCDC);color:var(--es-red-700,#A01010)}

/* Top app bar (chrome) */
.es-appbar{background:var(--es-blue-800);height:60px;display:flex;align-items:center;padding:0 18px;color:#fff}
.es-appbar .es-wordmark{font-size:20px}

/* ----------------------------------------------------------------------------
   9f. GLOW RING  (.es-glow-ring)  — rotating brand-colour border
   A conic-gradient swept by animating a registered angle: the box stays still
   and the colours travel round it. @property is what makes the angle
   animatable — an unregistered custom property cannot interpolate, so the
   sweep would jump rather than turn.

   Two forms, one gradient and one animation:
   - .es-glow-ring WRAPS its content: a sharp ring (::before) plus a blurred
     halo (::after), both painted behind it. The content must have an opaque
     background and the same radius — it is what covers the gradient's centre,
     leaving only the overhang visible.
   - .es-glow-ring-surface IS the ring, for when the target cannot be wrapped.
     Position it behind the target, larger by the ring width on every side.

   The glow cannot go on the element that carries the opaque background. That
   element becomes a stacking context, which paints its own background first and
   its negative-z-index children second — so the gradient fills the box instead
   of ringing it. Hence a wrapper, or a separate earlier sibling.

   Tunable per use: --es-glow-duration (one full turn), --es-glow-radius (match
   the content), --es-glow-width (visible ring thickness, wrapper form only),
   --es-glow-colours (the gradient stops; brand blue, aqua and orange by default).
---------------------------------------------------------------------------- */
@property --es-glow-angle{syntax:"<angle>";inherits:false;initial-value:0deg}
@keyframes esGlowSpin{to{--es-glow-angle:360deg}}

.es-glow-ring{position:relative;z-index:0;border-radius:var(--es-glow-radius,10px)}
.es-glow-ring::before,
.es-glow-ring::after{content:"";position:absolute;inset:calc(var(--es-glow-width,3px) * -1);z-index:-1;border-radius:inherit}
.es-glow-ring::after{inset:-8px;z-index:-2;filter:blur(14px);opacity:.85}
.es-glow-ring-surface{border-radius:var(--es-glow-radius,10px)}

.es-glow-ring::before,
.es-glow-ring::after,
.es-glow-ring-surface{
  background:conic-gradient(from var(--es-glow-angle),var(--es-glow-colours,
    var(--es-blue-800),var(--es-aqua-500),var(--es-blue-800),var(--es-orange-500),var(--es-blue-800)));
  animation:esGlowSpin var(--es-glow-duration,8s) linear infinite;
}

/* Held still rather than removed: the ring still marks what it marks. */
@media (prefers-reduced-motion:reduce){
  .es-glow-ring::before,.es-glow-ring::after,.es-glow-ring-surface{animation:none}
}

/* ----------------------------------------------------------------------------
   10. VERTICAL NAV  (.lhs side menu)  — navy panel, aqua active rail, accordion
   Re-skins the legacy global .lhs/.lhs-sub list-group into the eSuite VerticalNav.
   Markup: <ul class="list-group lhs">…</ul>; sub-groups are a <li> that contains
   <ul class="list-group lhs-sub">. JS hooks preserved: data-href, .active (header),
   .selected (current), .open (expanded group), .greyArrow (chevron), .search,
   .badge. Pair with /assets/js/esuite-nav.js for click-to-expand.
   NOTE: critical rules are scoped under `ul.lhs` and forced !important ON PURPOSE
   — the app's legacy main.css still ships the old white-flyout .lhs theme and
   loads after this file; without these guards the sub-menu renders as a white
   popover floating over (and dimming) the items below. Do not relax them.
---------------------------------------------------------------------------- */
ul.lhs.list-group{background:var(--es-blue-900,#293F6D)!important;border:0!important;border-radius:var(--radius-lg)!important;
  overflow:hidden;padding:6px 0;margin-bottom:var(--space-4);box-shadow:var(--es-shadow-sm,0 1px 3px rgba(10,26,47,.18));
  list-style:none;user-select:none}
ul.lhs>.list-group-item,
ul.lhs .lhs-sub>.list-group-item{border:0!important;border-left:4px solid transparent!important;border-radius:0!important;
  box-shadow:none!important;float:none!important;position:relative;cursor:pointer;font-size:var(--text-sm);line-height:1.3;
  padding:9px var(--space-4);background-color:transparent!important;color:rgba(255,255,255,.82)!important;
  transition:background-color .12s var(--es-ease),color .12s var(--es-ease)}
ul.lhs .list-group-item.disabled{pointer-events:none}
ul.lhs>.list-group-item:focus-visible,
ul.lhs .lhs-sub>.list-group-item:focus-visible{outline:3px solid #fff!important;outline-offset:-3px}

/* Header row (.active) — "Learners" / learner name */
ul.lhs>.list-group-item.active{background-color:transparent!important;color:#fff!important;font-weight:600;font-size:14px;
  cursor:default;padding:var(--space-3) var(--space-4) 11px;border-left:0!important;border-bottom:1px solid rgba(255,255,255,.10)!important;margin-bottom:var(--space-1)}
ul.lhs>.list-group-item.active .font-mono{color:rgba(255,255,255,.6)!important}

/* Section eyebrow — additive, non-interactive group label (variant 1i grouping).
   Matched at any depth so an eyebrow inside a conditional block/sub-list still styles. */
ul.lhs .lhs-section{border-left:0!important;background:transparent!important;cursor:default;list-style:none;
  padding:15px var(--space-4) 6px!important;font-size:var(--es-text-group-label);font-weight:600;
  color:var(--text-on-navy-muted)!important}
ul.lhs .lhs-section:hover{background:transparent!important}

/* Idle leading icons */
ul.lhs>.list-group-item:not(.active)>span.fal,
ul.lhs>.list-group-item:not(.active)>span.fa{width:17px;text-align:center;color:rgba(255,255,255,.6)!important}
/* Hover */
ul.lhs>.list-group-item:not(.active):not(.search):not(.selected):not(.lhs-section):hover{background-color:rgba(255,255,255,.06)!important;color:#fff!important}
ul.lhs>.list-group-item:not(.active):not(.search):not(.selected):not(.lhs-section):hover>span.fal,
ul.lhs>.list-group-item:not(.active):not(.search):not(.selected):not(.lhs-section):hover>span.fa{color:var(--text-on-navy-muted)!important}

/* Current page (.selected) — variant 1i: white fill + 4px orange rail + navy text/icon */
ul.lhs>.list-group-item.selected{background-color:#fff!important;color:var(--es-blue-900,#293F6D)!important;font-weight:600;
  border-left:4px solid var(--es-orange-500,#FA650D)!important}
ul.lhs>.list-group-item.selected>span.fal,
ul.lhs>.list-group-item.selected>span.fa{color:var(--es-blue-800,#4265AF)!important}
/* badge must stay legible on the white selected row */
ul.lhs>.list-group-item.selected .badge{background:var(--es-blue-tint,#E7ECF6)!important;color:var(--es-blue-800,#4265AF)!important}

/* Search row */
ul.lhs>.list-group-item.search{cursor:default;padding:6px var(--space-3) var(--space-2)}
ul.lhs>.list-group-item.search .input-group{background:rgba(255,255,255,.10);border-radius:var(--radius-sm);overflow:hidden}
ul.lhs>.list-group-item.search .form-control{border:0;background:transparent;color:#fff;font-size:12.5px;box-shadow:none}
ul.lhs>.list-group-item.search .form-control::placeholder{color:rgba(255,255,255,.55)}
ul.lhs>.list-group-item.search .btn{border:0;background:transparent;color:rgba(255,255,255,.7)}

/* Expand chevron */
ul.lhs .greyArrow{color:rgba(255,255,255,.55)!important;transition:transform .15s var(--es-ease)}
ul.lhs>.list-group-item.open>.greyArrow{transform:rotate(180deg)}

/* Collapsible sub-menu — inset panel, in-flow (never a white flyout).
   Solid navy one step lighter than the #293F6D rail (NOT a translucent black):
   a semi-transparent fill would composite over the parent's white .selected row
   and render light grey, washing out the white child labels. */
ul.lhs .lhs-sub{list-style:none;margin:var(--space-1) -16px -9px!important;padding:0!important;overflow:hidden;max-height:0;
  width:auto!important;min-width:0!important;position:static!important;float:none!important;inset:auto!important;
  transform:none!important;z-index:auto!important;box-shadow:none!important;border:0!important;border-radius:0!important;
  display:block!important;background:var(--es-blue-850,#33497D)!important;transition:max-height .2s var(--es-ease)}
ul.lhs>.list-group-item.open>.lhs-sub{max-height:1000px}
ul.lhs .lhs-sub>.list-group-item{font-size:12.5px;padding:var(--space-2) var(--space-4) var(--space-2) 34px;color:var(--text-on-navy-muted)!important}
ul.lhs .lhs-sub>.list-group-item:not(.selected):hover{background-color:rgba(255,255,255,.05)!important;color:#fff!important}
ul.lhs .lhs-sub>.list-group-item.selected{background-color:#fff!important;color:var(--es-blue-900,#293F6D)!important;font-weight:600;
  border-left:4px solid var(--es-orange-500,#FA650D)!important}
ul.lhs .lhs-sub>.list-group-item span.fal,
ul.lhs .lhs-sub>.list-group-item span.fa{width:16px;text-align:center;color:rgba(255,255,255,.6)!important}
ul.lhs .lhs-sub>.list-group-item.selected span.fal,
ul.lhs .lhs-sub>.list-group-item.selected span.fa{color:var(--es-blue-800,#4265AF)!important}
ul.lhs .lhs-sub>.list-group-item.selected .badge{background:var(--es-blue-tint,#E7ECF6)!important;color:var(--es-blue-800,#4265AF)!important}

/* Count badges — translucent white pill, monospace */
ul.lhs .badge{background:rgba(255,255,255,.14)!important;color:#fff!important;font-weight:500;font-variant-numeric:tabular-nums}
ul.lhs .lhs-sub .badge{margin-left:auto}

@media (prefers-reduced-motion:reduce){
  ul.lhs .lhs-sub,ul.lhs .greyArrow,ul.lhs .list-group-item{transition:none!important}
}

/* ----------------------------------------------------------------------------
   11. RAG MATRIX  (.es-matrix)  — attendance/KSB/risk cross-tab
   Markup: <table class="es-matrix"> with a sticky first column (row header) and
   sticky header row. Tint intersection cells with a tone class and ALWAYS keep
   the figure/letter in the cell — never colour alone (WCAG 1.4.1).
   Tones: rag-green / rag-yellow / rag-orange / rag-red / rag-info / rag-muted.
---------------------------------------------------------------------------- */
.es-matrix{border-collapse:collapse;font-family:var(--es-font-sans);font-size:var(--text-sm)}
.es-matrix th,.es-matrix td{border:.5px solid var(--es-grey-100,#E1E6EB);padding:var(--space-2) var(--space-3);text-align:center;white-space:nowrap}
.es-matrix thead th{background:var(--es-blue-900,#293F6D);color:#fff;font-weight:600;position:sticky;top:0;z-index:1}
.es-matrix thead th:first-child,.es-matrix tbody th{position:sticky;left:0;z-index:2;background:var(--es-blue-900,#293F6D);
  color:#fff;text-align:left;font-weight:600}
.es-matrix tbody th{background:#fff;color:var(--es-blue-900,#293F6D);border-right:.5px solid var(--es-grey-100,#E1E6EB)}
.es-matrix tbody td{font-family:var(--es-font-mono)}
.es-matrix .rag-green{background:var(--es-green-50,#D6F5D6);color:var(--es-green-700,#09630B)}
.es-matrix .rag-yellow{background:var(--es-yellow-50,#FEF4DC);color:var(--es-yellow-700,#9A6200)}
.es-matrix .rag-orange{background:var(--es-orange-50,#FEE8D8);color:var(--es-orange-600,#C14800)}
.es-matrix .rag-red{background:var(--es-red-50,#FDDCDC);color:var(--es-red-700,#A01010)}
.es-matrix .rag-info{background:var(--es-aqua-50,#DFF4FC);color:var(--es-aqua-700,#0673A1)}
.es-matrix .rag-muted{background:var(--es-grey-50,#F1F2F7);color:var(--es-grey-400,#9F9F9F)}

/* ----------------------------------------------------------------------------
   12. REGISTER TAKE-VIEW  (.es-register)  — tutor attendance-marking screen
   One navy-headed card: header (back · title/meta + keyboard hint · classroom
   actions · mark all present) → summary-chip well → learner register rows.
   Two new shared patterns live here: the summary chips (.es-rchip — NB the bare
   .es-chip name is already taken by the table filter chip, §9) and the
   variable-length attendance code toggle group (.es-codes / .es-code-btn).
   Provider colours (CourseAttendanceCodes.HighlightColour) arrive only via the
   inline `style` set in JS — the one sanctioned exception to tokens-only.
---------------------------------------------------------------------------- */
/* Header — 3-part flex on bg-navy */
.es-register-head{display:flex;align-items:flex-start;gap:var(--space-4);justify-content:space-between}
.es-register-head .title-block{flex:1 1 auto;min-width:0}
.es-register-head .title{font-weight:600;color:#fff;font-size:.9375rem;line-height:1.3}
.es-register-head .meta{color:rgba(255,255,255,.72);font-size:.8125rem;margin-top:2px}
.es-register-head .kbd-hint{margin-top:6px;color:rgba(255,255,255,.62);font-size:.8125rem;font-weight:400}
.es-register-head .lead-actions{flex:0 0 auto}
.es-register-head .trail-actions{display:flex;gap:var(--space-2);align-items:center;flex:0 0 auto;flex-wrap:wrap;justify-content:flex-end}
.btn.es-on-navy{color:#fff;border-color:rgba(255,255,255,.35);background:transparent}
.btn.es-on-navy:hover{background:rgba(255,255,255,.12);color:#fff}
/* Solid white chip for an action on a navy header. .bg-navy is --es-blue-800, so .btn-primary on it is
   1:1 — the same colour, an invisible button — and .btn-aqua is 1.7:1. White fill with blue-800 text is
   5.6:1 for both the label and the chip. Hover is opacity, not a colour shift, so contrast holds in
   every state. */
.btn.es-on-navy-solid{background:#fff;color:var(--es-blue-800);border-color:#fff;--bs-btn-border-width:1.5px}
.btn.es-on-navy-solid:hover,
.btn.es-on-navy-solid:focus-visible{background:#fff;color:var(--es-blue-800);border-color:#fff;opacity:.86}

/* Summary chips (the .es-chip name is taken — register uses .es-rchip) */
.es-chip-row{display:flex;flex-wrap:wrap;gap:var(--space-3);padding:10px var(--space-4);
  background:var(--es-surface-sunken);border-bottom:.5px solid var(--es-border-subtle)}
.es-rchip{display:inline-flex;align-items:center;gap:var(--space-2);font-size:.8125rem;color:var(--es-text-body)}
.es-rchip-dot{width:10px;height:10px;border-radius:var(--radius-pill);background:var(--es-grey-400,#9F9F9F);flex:0 0 auto}
.es-rchip-dot.tone-green{background:var(--es-green-500)} .es-rchip-dot.tone-yellow{background:var(--es-yellow-500)}
.es-rchip-dot.tone-red{background:var(--es-red-500)}     .es-rchip-dot.tone-aqua{background:var(--es-aqua-500)}
.es-rchip-dot.tone-blue{background:var(--es-blue-800)}   .es-rchip-dot.tone-grey{background:var(--es-grey-400,#9F9F9F)}
.es-rchip-n{font-family:var(--es-font-mono);font-variant-numeric:tabular-nums;font-weight:600}

/* Learner rows */
.es-register-rows{display:flex;flex-direction:column}
.es-register-row{display:grid;grid-template-columns:auto 1fr auto auto;align-items:center;
  gap:var(--space-4);padding:10px var(--space-4);min-height:56px;
  border-bottom:.5px solid var(--es-border-subtle);border-left:3px solid transparent;outline:none}
.es-register-row:last-child{border-bottom:0}
.es-register-row:hover{background:var(--es-blue-tint,#E7ECF6)}
.es-register-row:focus,.es-register-row.is-cursor{        /* the keyboard cursor */
  background:var(--es-blue-tint,#E7ECF6);border-left-color:var(--es-accent,#4265AF)}
.es-register-row .identity{min-width:0}
.es-register-row .name{color:var(--es-text-strong)}
.es-register-row .sub{font-size:.8125rem;color:var(--es-text-muted);margin-top:1px}
.es-register-row .sub .font-mono{font-family:var(--es-font-mono)}
.es-register-row .send-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:5px}
.es-send-chip{cursor:help}
.es-register-row .level-display{cursor:pointer;color:var(--es-blue-800);text-decoration:underline}

/* Code toggle group */
.es-codes{display:flex;flex-wrap:wrap;gap:var(--space-2);justify-content:flex-end}
.es-code-btn{min-width:44px;min-height:44px;padding:0 10px;border-radius:var(--radius-pill);
  border:1.5px solid var(--es-border-input,#E1E6EB);background:transparent;
  color:var(--es-text-muted);font-weight:600;font-size:.8125rem;line-height:1;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
  transition:opacity .14s var(--es-ease),background .14s var(--es-ease),border-color .14s var(--es-ease)}
.es-code-btn:hover{opacity:.86}
.es-code-btn:focus-visible{box-shadow:var(--es-focus-ring);border-color:var(--es-accent)}
.es-code-btn.active{border-color:transparent}   /* active fill + letter colour set inline from HighlightColour */

/* Notes button */
.es-note-btn{min-width:44px;min-height:44px;position:relative;color:var(--es-text-muted)}
.es-note-btn.has-note{color:var(--es-aqua-600,#0098D4)}
.es-note-btn.has-note::after{content:"";width:6px;height:6px;border-radius:var(--radius-pill);
  background:var(--es-aqua-500);position:absolute;top:9px;right:9px}

/* Empty state */
.es-register-empty{text-align:center;padding:var(--space-10) var(--space-6);color:var(--es-text-muted)}
.es-register-empty .fa-users{font-size:2rem;color:var(--es-grey-300,#C7CCD4);margin-bottom:var(--space-3)}

/* Compact density (40+ learners) */
.es-register.compact .es-register-row{min-height:0;padding:6px var(--space-4)}
.es-register.compact .es-avatar{width:32px!important;height:32px!important;font-size:var(--text-xs)!important}
.es-register.compact .send-chips .es-send-chip .lbl{display:none}   /* icon-only chips */
.es-register.compact .es-register-head,
.es-register.compact .es-chip-row{position:sticky;top:0;z-index:5}

/* Narrow screens: stack codes under identity */
@media (max-width:768px){
  .es-register-row{grid-template-columns:auto 1fr auto}
  .es-codes{grid-column:1 / -1;justify-content:flex-start;margin-top:6px}
}

/* ----------------------------------------------------------------------------
   13. RECORD-DETAIL ROW ACTIONS  (decision.php staff-action / profile rows)
   Purpose-named buttons for the trailing action in a .list-group row, so the
   markup is one class per the §6.4d taxonomy. Use INSTEAD of `.btn .btn-*` for
   these row actions. Icon rule: leading icon for labelled actions; trailing
   chevron for "fix / next". Auto-width + nowrap — never stretch with w-100.
---------------------------------------------------------------------------- */
.es-rowbtn{
  display:inline-flex; align-items:center; gap:.4em; white-space:nowrap;
  font:600 .75rem/1 var(--es-font-sans); border-radius:.375rem;
  padding:.4375rem .8125rem; border:1.5px solid transparent; cursor:pointer;
  text-decoration:none; transition:opacity var(--es-dur) var(--es-ease),
    background var(--es-dur) var(--es-ease), border-color var(--es-dur) var(--es-ease);
}
.es-rowbtn:hover{ opacity:.86; text-decoration:none; }
.es-rowbtn:focus-visible{ box-shadow:var(--es-focus-ring); outline:none; }
.es-rowbtn>i{ font-size:.6875rem; }

/* CHANGE — low-emphasis aqua text button (verified / completed rows; also Re-invite, Add another course) */
.es-rowbtn--change{ background:transparent; border-color:transparent;
  color:var(--es-aqua-700,#0673A1); padding-inline:.5rem; }
.es-rowbtn--change:hover{ color:var(--es-aqua-700,#0673A1); text-decoration:underline; opacity:1; }

/* FIX THIS ISSUE / SET DATES — solid red, compact, trailing chevron (outstanding action) */
.es-rowbtn--fix{ background:var(--es-red-500); border-color:var(--es-red-500); color:#fff; }
.es-rowbtn--fix:hover{ color:#fff; }
.es-rowbtn--fix:active{ background:var(--es-red-700); border-color:var(--es-red-700); }

/* MARK AS COMPLETED — solid navy / primary (NOT red) */
.es-rowbtn--complete{ background:var(--es-blue-800); border-color:var(--es-blue-800); color:#fff;
  padding:.5625rem 1.125rem; font-size:.8125rem; }
.es-rowbtn--complete:hover{ color:#fff; }
.es-rowbtn--complete:active{ background:var(--es-accent-press); border-color:var(--es-accent-press); }

/* Enrolment decision workspace — green status check icons 50% larger (scoped, user request).
   scale() gives a true +50% of the rendered size whether the icon is base or fa-lg. */
.es-decision-workspace .fa-circle-check{ display:inline-block; transform:scale(1.5); transform-origin:center; }
/* A row's text takes the room beside its icon and wraps there, rather than dropping under the icon when it is long. */
.es-decision-workspace .list-group-item > .flex-grow-1{ flex-basis:0; min-width:0; }


/* ----------------------------------------------------------------------------
   14. LEGACY RECONCILIATION  — rules folded in from the deleted main.css
   ----------------------------------------------------------------------------
   main.css (and its siblings) were removed in the ui-uplift cleanup, but the
   <link> lingered so pages kept working off a stale server copy. These are the
   rules still referenced by live markup/JS, re-homed here (the single canonical
   overlay) and re-expressed with eSuite tokens instead of the old raw hex.
   Dead main.css rules (#modal, .flashit, .badge-danger/success/…, .ribbon big-
   icon, .table-dropdown-menu, .button-bar-*) were intentionally NOT migrated.
---------------------------------------------------------------------------- */

/* Loading overlay — full-screen scrim + centred spinner box (cover.js; 469 pages).
   cover.js builds the overlay with #cCover / #cCover_container IDs (not a .cover
   class), so these rules target those IDs. The old cover.css was folded in here;
   its dead <link> injection was removed from cover.js.

   ⚠ THE OLD `animation: colorchange` WAS DROPPED AS HARMLESS AND WAS NOT. cover.js
   removed the overlay inside an animationend handler on .cover-hide, so with no
   animation on that class the event never fired and the overlay never went away —
   invisible on the ~469 pages that reload straight after done(), permanent on any
   page that finishes and stays put. cover.js no longer depends on the event (see
   dismiss() there); .cover-hide is defined below so the removal is a fade rather
   than a hard cut, but the timeout is what guarantees it. */
#cCover{ position:fixed; inset:0; width:100%; height:100%; z-index:1000;
  display:flex; align-items:center; justify-content:center;
  background-color:rgba(41,63,109,.35); }
#cCover_container.cover-hide{ animation:esCoverFade .35s ease forwards; }
@keyframes esCoverFade{ from{ opacity:1; } to{ opacity:0; } }
/* The panel grows with its message: a one-word "Saved" keeps the 140px square, and a sentence
   (a refusal, say) wraps inside it rather than spilling out of a fixed box. Centred by the
   flex scrim above, so it stays centred at any size. */
#cCover > div{ box-sizing:border-box; min-width:140px; min-height:140px;
  max-width:min(320px, calc(100% - 32px)); padding:var(--space-5); text-align:center; overflow-wrap:anywhere;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  background-color:var(--es-grey-50,#F1F2F7); border-radius:var(--radius-lg); box-shadow:var(--es-shadow-md); }
#cCover > div > span{ margin-bottom:10px; }
#cCover > div > span:last-child{ margin-bottom:0; }

/* jQuery-validation states (validation.js toggles .error / label.error at runtime). */
.error:not(label){ background-color:var(--es-red-50,#FDDCDC);
  border:1px solid var(--es-red-500,#DE1F1F) !important; border-left-width:2px !important; font-weight:600; }
label.error{ color:var(--es-red-700,#A01010); margin-left:0; }
.error::placeholder{ color:var(--es-red-700,#A01010); }
.required{ border-left:2px solid var(--es-red-500,#DE1F1F) !important; font-weight:600; }
.required::placeholder{ color:var(--es-red-700,#A01010); }
.requireOneOf{ border-left:2px dashed var(--es-red-500,#DE1F1F) !important; font-weight:600; }

/* Stacked "input block" — joins a column of inputs into one bordered group. */
.input-block > input[type='text']:not(:first-of-type):not(:last-of-type),
.input-block > span:not(:first-of-type):not(:last-of-type),
.input-block > .input-group:not(:first-of-type):not(:last-of-type) > input[type='text'],
.input-block > .input-group:not(:first-of-type):not(:last-of-type) > .input-group-addon{
  border-top:0 !important; border-bottom:0 !important; border-radius:0 !important; }
.input-block > input[type='text']:first-of-type,
.input-block > span:first-of-type,
.input-block > .input-group:first-of-type > input[type='text'],
.input-block > .input-group:first-of-type > .input-group-addon{
  border-bottom:0 !important; border-bottom-left-radius:0 !important; border-bottom-right-radius:0 !important; }
.input-block > input[type='text']:last-of-type,
.input-block > span:last-of-type,
.input-block > .input-group:last-of-type > input[type='text'],
.input-block > .input-group:last-of-type > .input-group-addon{
  border-top:0 !important; border-top-left-radius:0 !important; border-top-right-radius:0 !important; }
.input-block > .input-group{ width:100%; }
.input-block > .input-group > .input-group-addon{ width:40px; text-align:center; }

/* Textarea word/character counters. */
.textarea-counters{ color:var(--es-text-muted); font-size:var(--text-xs); }
.textarea-counters > .word-count{ float:left; }
.textarea-counters > .character-count{ float:right; }

/* Plain Bootstrap tables share the grid; one inside a card leaves the card to draw its sides. */
.table:not(.es-table):not(.table-borderless)>:not(caption)>*>*{border:1px solid var(--es-grid-line)}
.card .table:not(.es-table):not(.table-borderless)>:not(caption)>*>*:first-child{border-left:0}
.card .table:not(.es-table):not(.table-borderless)>:not(caption)>*>*:last-child{border-right:0}

/* Plain Bootstrap .table (legacy pages — NOT the .es-table DataTable) — restore a
   readable header band. The old rule painted an off-brand blue (#0580cb); re-homed
   as the eSuite grey-tint + navy header used elsewhere, so headers stay legible
   even where the stale main.css is gone (this was the learner-dashboard symptom). */
.table > tbody > tr > th{ background-color:var(--es-grey-100,#E1E6EB) !important;
  color:var(--es-blue-900,#293F6D); font-weight:600; }
.table > tbody > tr > th > a{ color:var(--es-blue-900,#293F6D); font-weight:400; }
.table:not(.table-condensed) > tbody > tr > td{ height:41px; line-height:20px; padding:10px 15px; }
.table:not(.table-condensed) > tbody > tr > th{ height:42px; line-height:20px; padding:10px 15px; }
.table.table-condensed > tbody > tr > td,
.table.table-condensed > tbody > tr > th{ padding:5px 15px; }
.table-hover > tbody > tr:hover > td{ background-color:var(--es-aqua-50,#DFF4FC) !important; cursor:pointer !important; }
.table-j-fix{ margin:0; border-bottom:0 !important; }
.table-j-fix.table-no-results{ padding:15px; margin-bottom:0 !important; border-top:1px solid var(--es-grey-100,#E1E6EB); }
.table-j-fix th a{ color:var(--es-blue-900,#293F6D); }

/* Wrap-free layout table (timeline.php / search look.php helper). */
.timeline-table{ width:100%; }
.timeline-table > tbody > tr > td{ vertical-align:top; }
.timeline-table > tbody > tr > th:not(:last-child),
.timeline-table > tbody > tr > td:not(:last-child){ white-space:nowrap; }
.timeline-table > tbody > tr > th:last-child,
.timeline-table > tbody > tr > td:last-child{ width:100%; }

/* File-upload chip list. */
.file-upload-list{ padding:0; margin:5px -5px; list-style:none; display:flex; flex-wrap:wrap; align-items:flex-start; }
.file-upload-list li{ margin:5px; padding:5px; display:flex; align-items:flex-start;
  background:var(--es-surface-sunken); border:1px solid var(--es-grey-100,#E1E6EB); border-radius:5px; }
.file-upload-list li .remove{ margin-right:10px; }

/* Vertical (stacked) dropdown-button group. */
.dd-btn-j .dropdown-menu{ top:0; min-width:auto; margin:0; padding:0; border:none; background:none;
  box-shadow:none; text-align:right; flex-direction:column; }
.dd-btn-j .open > .dropdown-menu{ display:flex; }
.dd-btn-j .dropdown-menu > button{ width:100%; margin:0 !important; padding:.5em .5em .5em .25em;
  border-radius:0; border-bottom-width:0; text-align:left; display:flex; align-items:center; }
.dd-btn-j .dropdown-menu > button:first-child{ border-top-left-radius:var(--radius-xs); border-top-right-radius:var(--radius-xs); }
.dd-btn-j .dropdown-menu > button:last-child{ border-bottom-left-radius:var(--radius-xs); border-bottom-right-radius:var(--radius-xs); }

/* ---------------------------------------------------------------------------
   Row-action ⋮ menu (STANDARDISED) — the "edit" dropdown used in list-table
   action columns: <div class="btn-group float-end"> ⋮ + .dropdown-menu of action
   buttons. Several tables (appConfig contractOutcomeType(s)/Groups, learners
   learningAims/claim_new/destinations, organisations profile_contacts) each
   shipped their own near-identical copy of this CSS; the copies fought Bootstrap's
   Popper placement and let the menu render off-screen.

   This one global rule standardises them: the menu OVERLAYS the table (absolute →
   never widens it) and drops DOWN from the button, right-aligned — its right edge
   pinned to the button's right edge so it grows leftward over the table (which is
   always to its left) and never off the right of the screen. It escapes the card /
   .table-responsive clip via the overflow-release rule below. The !important
   overrides are deliberate: they beat the inline styles Popper writes on the menu.

   (Superseded the earlier LEFT side-flyout — inset:0 100% — which top-aligned the
   menu beside the button, overlapping the adjacent column and pushing multi-item
   menus below the row's bottom edge where the lower items read as missing.) */
.btn-group.float-end > .dropdown-menu{
  position:absolute !important;
  inset:100% 0 auto auto !important;    /* drop below the button; pin the menu's right edge to the button's right edge */
  transform:none !important;
  margin:.35rem 0 0 0 !important;       /* small gap below the ⋮ button */
  min-width:12rem;                      /* right edge is pinned, so it grows leftward — never toward the screen edge */
  padding:.35rem;
  flex-direction:column; gap:.35rem;
  border:1px solid var(--es-grey-100,#E1E6EB);
  border-radius:var(--radius-lg);
  background:#fff;
  box-shadow:var(--es-shadow-md,0 4px 12px rgba(41,63,109,.12));
  text-align:left;
  z-index:1030;
}
.btn-group.float-end > .dropdown-menu.show{ display:flex; }
.btn-group.float-end > .dropdown-menu > .btn{
  width:100%; margin:0; border-radius:var(--radius-sm);
  display:flex; align-items:center; justify-content:flex-start;
  text-align:left; white-space:nowrap;
}
.btn-group.float-end > .dropdown-menu > .btn > span:first-child{
  width:1.5em; flex:0 0 auto; text-align:center; margin-right:.4em;
}
/* Clicks land on the action button, never its icon/label span (so delegated
   handlers reading the button's data-* always fire). */
.btn-group.float-end > .dropdown-menu > .btn > *{ pointer-events:none; }

/* The flyout is position:absolute, so it is still clipped by every ancestor with a
   non-visible overflow. For a Table::render list that is FOUR nested clippers:
   .es-table-scroll (overflow-x:auto → computed overflow-y:auto) and .es-table-wrap
   (overflow:hidden) that the renderer wraps every table in, then the page's own
   .table-responsive and the .card (overflow:hidden). The innermost pair is what
   crops the menu at the row's bottom edge (a short scrollbar hugging the header).
   Release the clip on all of them — but ONLY while a row-action menu is actually
   open — so the menu overlays everything; each container goes back to
   clipping/scrolling the instant it closes. :has() is already used here (§9b). */
.es-table-scroll:has(.btn-group.float-end > .dropdown-menu.show),
.es-table-wrap:has(.btn-group.float-end > .dropdown-menu.show),
.table-responsive:has(.btn-group.float-end > .dropdown-menu.show),
.card:has(.btn-group.float-end > .dropdown-menu.show){
  overflow: visible;
}

/* ── Go to top — global floating button (markup in assets/includes/footer.php) ──
   Fixed bottom-right; fades in once a long page is scrolled past the threshold.
   z-index sits below Bootstrap modals (1050+) so it never floats over a dialog. */
.es-gototop{
  position:fixed; left:50%; bottom:1.25rem; z-index:1030;
  width:2.75rem; height:2.75rem;
  display:inline-flex; align-items:center; justify-content:center;
  border:1px solid #fff; border-radius:var(--radius-pill);
  background:var(--es-blue-800,#4265AF); color:#fff; font-size:1rem; line-height:1;
  box-shadow:var(--es-shadow-md,0 4px 12px rgba(10,26,47,.18));
  cursor:pointer;
  opacity:0; visibility:hidden; transform:translateX(-50%) translateY(8px); pointer-events:none;
  transition:opacity .16s cubic-bezier(.2,0,0,1), transform .16s cubic-bezier(.2,0,0,1), visibility .16s;
}
.es-gototop.is-visible{ opacity:1; visibility:visible; transform:translateX(-50%); pointer-events:auto; }
.es-gototop:hover{ opacity:.86; }
.es-gototop:focus-visible{ outline:none; box-shadow:var(--es-focus-ring); }
@media (prefers-reduced-motion: reduce){ .es-gototop{ transition:none; } }
@media print{ .es-gototop{ display:none !important; } }

/* ── Standardised form pages (checkbox/toggle-heavy settings forms) ─────────────
   The card-grouped pattern from handoff_php_bootstrap/standardise-form-pages.md:
   flat field lists become concept .cards; single yes/no flags become toggle
   switches (label left, switch right); multi-select groups stay checkboxes in a
   responsive 2-column grid; short inputs/selects are width-capped. Presentational
   only — a page using these never changes a field name/id/submitted value.
   Checked/focus states already inherit eSuite blue via .form-check-input above. */

/* Small muted group sub-label inside a card — a sub-label, NOT a heading. */
.es-form-grouphd{
  font-size:.8125rem; font-weight:500; color:var(--es-text-muted);
  margin-bottom:.75rem;
}

/* Single yes/no flag row: switch on the left, concept label to its right
   (Bootstrap's native .form-switch order). Hairline separators between rows. */
.es-toggle-row{
  padding:.5rem 0; border-top:1px solid var(--es-grey-100);
}
.es-toggle-row:first-of-type{ border-top:0; }
.es-toggle-row .form-check{ margin:0; min-height:auto; }
.es-toggle-row .form-check-label{ color:var(--es-text-body); }

/* Multi-select checkbox group (4+ items) → responsive 2-column grid. */
.es-check-grid{ display:grid; grid-template-columns:1fr; gap:.5rem .75rem; }
@media (min-width:768px){ .es-check-grid{ grid-template-columns:1fr 1fr; } }
.es-check-grid .form-check{ margin:0; }

/* Width-cap short inputs/selects so they size to content, not the container.
   NB: only for genuinely short values (codes, hours, grades). Descriptive-option
   dropdowns are NOT short inputs — leave them full width (see §7 / .es-combo). */
.es-input-short{ max-width:220px; }
.es-input-xshort{ max-width:120px; }

/* ── Combo-select (descriptive-option dropdown) — standardise-form-pages.md §7 ──
   PREFER a native <select> when the option set is short and static: it is
   accessible for free, its chrome already matches text inputs, and its panel is
   browser-drawn so it can never overflow a neighbouring column. Reach for
   .es-combo ONLY when a searchable/custom combobox is genuinely needed for long
   descriptive options; wire open/close, selection and ARIA (role="combobox" on
   the trigger, role="listbox" on the panel, role="option" on each row,
   aria-expanded/aria-controls/aria-selected) in the page's own JS.
   The trigger reuses .form-select so the closed state is identical to §5 inputs. */
.es-combo{ position:relative; }
/* Open panel — width-LOCKED to its own trigger (never wider than its column),
   overlays as an absolute layer so it never reflows or covers an adjacent field. */
.es-combo-panel{
  position:absolute; top:calc(100% + 2px); left:0;
  width:100%; max-width:100%; max-height:16rem; overflow-y:auto;
  z-index:1035; background:#fff;
  border:1px solid var(--es-grey-100); border-radius:var(--radius-md);
  box-shadow:var(--es-shadow-md,0 4px 12px rgba(10,26,47,.12));
  padding:.25rem;
  /* No blank header/decorative row — options start immediately. Put a real
     <input class="es-combo-search"> here if the list is long enough to search. */
}
.es-combo-panel[hidden]{ display:none; }
.es-combo-search{
  width:100%; margin:.25rem 0 .35rem; padding:.375rem .6rem;
  font-size:.8125rem; border:1.5px solid var(--es-border-input); border-radius:var(--radius-sm);
}
/* Options — full-width rows, ≥40px touch target, long text wraps rather than
   widening the panel; hover/focus/active use the accent tint, not a grey block. */
.es-combo-option{
  display:flex; align-items:flex-start; gap:.5rem;
  min-height:2.5rem; padding:.5rem .75rem;
  font-size:.8125rem; color:var(--es-text-body); line-height:1.3;
  white-space:normal; border-radius:var(--radius-sm); cursor:pointer;
}
.es-combo-option:hover, .es-combo-option:focus, .es-combo-option.is-active{
  background:var(--es-aqua-50); outline:none;
}
/* Selected marked by weight (+ optional leading <i class="fa-solid fa-check">),
   never colour alone. */
.es-combo-option[aria-selected="true"]{ font-weight:600; }
.es-combo-option .es-combo-check{ flex:0 0 1em; color:var(--es-blue-800); }

/* ── Segmented radio group (single-select pill control) — §8 ────────────────────
   For a factual, mutually-exclusive question with 2–4+ options (Yes/No, Care
   status, EHC/DLA/PIP, …). NOT a switch (that implies an independent flag) and
   NOT a checkbox group. Restyles a horizontal native-radio group — emit it with
   Form::radioButtons(.., 'segmented'), which wraps label.radio-inline > radio
   options in <div class="es-segmented" role="radiogroup"> — into equal-height
   pills: one active at a time, active = blue fill + white, inactive = border-only.
   Native radios keep their name/value + keyboard/AT behaviour; :has() reflects the
   checked child onto its label. Pills wrap to a second row rather than overflow. */
.es-segmented{ display:flex; flex-wrap:wrap; gap:.375rem; align-items:center; }
.es-segmented label,
.es-segmented .radio-inline{
  position:relative; margin:0;
  display:inline-flex; align-items:center; justify-content:center;
  min-height:2.25rem; padding:.375rem .85rem;
  font-size:.8125rem; font-weight:500; color:var(--es-text-body);
  background:#fff; border:1.5px solid var(--es-border-input); border-radius:var(--radius-pill);
  cursor:pointer; white-space:nowrap;
  transition:background .12s cubic-bezier(.2,0,0,1), color .12s cubic-bezier(.2,0,0,1), border-color .12s cubic-bezier(.2,0,0,1);
}
/* Native radio hidden but present + focusable (keyboard/screen-reader intact). */
.es-segmented input[type="radio"]{
  position:absolute; width:1px; height:1px; margin:0; padding:0;
  opacity:0; pointer-events:none;
}
.es-segmented label:hover,
.es-segmented .radio-inline:hover{ border-color:var(--es-blue-600); }
/* Active pill = the label whose radio is checked. */
.es-segmented label:has(> input:checked),
.es-segmented .radio-inline:has(> input:checked){
  background:var(--es-blue-800); border-color:var(--es-blue-800); color:#fff;
}
/* Keyboard focus ring on the focused pill. */
.es-segmented label:has(> input:focus-visible),
.es-segmented .radio-inline:has(> input:focus-visible){
  box-shadow:var(--es-focus-ring);
}
/* Variant B: hand-written .form-check.form-check-inline radios (input is a sibling
   BEFORE the label, not a child). The base pill rule above already styles the
   .form-check-label and hides the input; here we reset the wrapper and drive the
   active/focus state via the adjacent-sibling selector (no :has() needed). */
.es-segmented .form-check{ padding:0; margin:0; min-height:auto; display:inline-flex; }
.es-segmented .form-check-input[type="radio"]:checked + .form-check-label{
  background:var(--es-blue-800); border-color:var(--es-blue-800); color:#fff;
}
.es-segmented .form-check-input[type="radio"]:focus-visible + .form-check-label{
  box-shadow:var(--es-focus-ring);
}

/* ============================================================ §16 funding source edit ======== */
/* urbi/appConfig/contractEdit.php is one long stack of label/control pairs plus a run of fifty-odd
   checkbox statements, and it carried NO vertical spacing at all: its rows are separated by
   <div class="clearfix">, which has no height, and neither a bare <label> nor .form-control takes a
   margin from this design system. So every field sat directly on the one above it and the checkbox
   run was Bootstrap's default .125rem apart — easy to mis-read, and easy to tick the wrong line of.

   Both are loosened by about a quarter of their OWN pitch, so the proportion is the same in each
   place rather than one flat number applied to two different-sized things:
       field row  ~57px (label 22.5 + control 35)  ->  ~71px   +24%
       check row  ~26px (min-height 24 + 2)        ->  ~32px   +23%

   row-gap, NOT --bs-gutter-y. The gutter variable pairs a margin-top on the row's children with a
   compensating NEGATIVE margin-top on the row itself, so it adds nothing between one row and the
   next — and it would eat the margin-bottom sitting below. row-gap spaces wrapped columns without
   that compensation, which leaves the two rules independent: one controls the gap between stacked
   rows, the other the gap between columns that have wrapped. */
.es-contract-edit .row { row-gap: 14px; }
.es-contract-edit .row > [class*="col-"] { margin-bottom: 14px; }
.es-contract-edit label { margin-bottom: var(--space-1); }
.es-contract-edit .form-check { min-height: 24px; margin-bottom: var(--space-2); }


/* ----------------------------------------------------------------------------
   15. VALUE PICKER  (.value-picker / .vp-modal)  — long code lists
   ----------------------------------------------------------------------------
   A rule whose InputQuery returns hundreds of ILR codes used to render as a flat
   four-column checkbox grid: no way to find a value, no way to audit what was
   set. The picker splits that into a read-only POOL on the page (what is
   selected, grouped by code type) and a MODAL that does the searching, filtering
   and ticking. Markup comes from /assets/includes/value-picker.php, behaviour
   from /assets/js/value-picker.js.

   Action colours follow the client's rule rather than each element's own
   instinct: orange opens the editor, green commits, red removes or deselects,
   grey is a neutral dismiss. That is why Close is a ghost button and Save
   selection is green while the PAGE's Save stays blue — blue is still the
   primary CTA, and only one of those two buttons actually saves the contract.
---------------------------------------------------------------------------- */

.value-picker .vp-head{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:var(--space-2);
}
.value-picker .vp-title{
  font-weight:600; font-size:.9375rem; color:var(--es-blue-900);
}
.value-picker .vp-pool{
  background:var(--es-surface-sunken); border:1px solid var(--es-grey-100);
  border-radius:var(--radius-md); padding:var(--space-4) 18px;
}
.value-picker .vp-pool-head{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
}
.value-picker .vp-pool-title{
  font-weight:600; font-size:.8125rem; color:var(--es-blue-900);
}
.value-picker .vp-pool-count{
  background:var(--es-blue-tint); color:var(--es-blue-800); border:1px solid currentColor;
  border-radius:var(--radius-pill); padding:1px 9px; font-size:.6875rem; font-weight:600;
}
.value-picker .vp-pool-meta{
  font-size:.8125rem; color:var(--es-text-muted);
}
/* Orange-600, not the .btn-orange orange-500: white on orange-500 is ~3.0:1 and fails AA at this size. Scoped here rather than changed globally. */
.value-picker .vp-edit{
  margin-left:auto;
  --bs-btn-bg:var(--es-orange-600); --bs-btn-border-color:var(--es-orange-600);
  --bs-btn-hover-bg:var(--es-orange-600); --bs-btn-hover-border-color:var(--es-orange-600);
  --bs-btn-active-bg:var(--es-orange-600); --bs-btn-color:#fff; --bs-btn-hover-color:#fff;
  min-height:34px;
}
.value-picker .vp-pool-body:not(:empty){ margin-top:14px; }
.value-picker .vp-pool-empty{
  margin:14px 0 0; font-size:.8125rem; color:var(--es-text-muted);
}
.value-picker .vp-pool-group + .vp-pool-group{ margin-top:var(--space-3); }
.value-picker .vp-pool-group-head{
  display:flex; align-items:center; gap:var(--space-2); margin-bottom:6px;
  font:600 var(--es-text-group-label)/1.4 var(--es-font-sans);
  color:var(--es-text-muted);
}
.value-picker .vp-pool-group-head .font-mono{
  letter-spacing:0; color:var(--es-blue-800); font-size:.6875rem;
}
.vp-pool-chips{ display:flex; flex-wrap:wrap; gap:6px; }

.vp-chip{
  display:inline-flex; align-items:center; gap:var(--space-2); max-width:340px;
  background:var(--es-white); border:1px solid var(--es-grey-100);
  border-radius:var(--radius-pill); padding:6px var(--space-3); font-size:.8125rem; color:var(--es-text-body);
}
.vp-chip-code{ font-size:.6875rem; font-weight:600; color:var(--es-blue-900); flex:0 0 auto; }
.vp-chip-label{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.vp-chip-remove{
  flex:0 0 auto; width:20px; height:20px; padding:0; border:0; border-radius:50%;
  background:var(--es-red-500); color:#fff; font-size:.625rem; line-height:1;
  display:inline-flex; align-items:center; justify-content:center;
  transition:opacity var(--es-dur) var(--es-ease);
}
.vp-chip-remove:hover{ opacity:.86; }

.vp-modal .modal-dialog{ max-width:1120px; }
.vp-modal .modal-content{ height:88vh; }
.vp-modal .modal-header{ align-items:flex-start; gap:var(--space-4); }
.vp-modal .vp-modal-heading{ flex:1 1 auto; min-width:0; }
.vp-modal .vp-subtitle{
  margin:2px 0 0; font-size:.8125rem; color:rgba(255,255,255,.78);
}
.vp-modal .vp-modal-state{
  display:flex; flex-direction:column; align-items:flex-end; gap:2px;
  font-size:.75rem; color:#fff; white-space:nowrap;
}
.vp-modal .vp-state-drift{ color:rgba(255,255,255,.78); }

/* Tier 1 of the scroll model: the modal body scrolls without a visible bar, so the only scrollbar on screen is the values grid's. The wheel is routed here by value-picker.js. */
.vp-modal .modal-body{
  display:flex; flex-direction:column; gap:14px;
  overflow-y:auto; overscroll-behavior:contain;
  scrollbar-width:none; -ms-overflow-style:none;
}
.vp-modal .modal-body::-webkit-scrollbar{ width:0; height:0; }

.vp-modal .vp-controls{ display:flex; align-items:center; gap:10px; }
.vp-modal .vp-search-wrap{ position:relative; flex:1 1 auto; }
.vp-modal .vp-search-wrap>[class*="fa-"]{
  position:absolute; left:12px; top:50%; transform:translateY(-50%);
  color:var(--es-grey-400); pointer-events:none;
}
.vp-modal .vp-search{ padding-left:36px; }

.vp-modal .vp-cats{ display:flex; flex-wrap:wrap; gap:6px; }
.vp-modal .vp-cat{
  display:inline-flex; align-items:center; gap:6px; white-space:nowrap;
  background:var(--es-white); border:1.5px solid var(--es-grey-100);
  border-radius:var(--radius-pill); padding:6px 14px; min-height:32px;
  font:600 .75rem/1 var(--es-font-sans); color:var(--es-blue-800);
  transition:background-color var(--es-dur) var(--es-ease), border-color var(--es-dur) var(--es-ease);
}
.vp-modal .vp-cat:hover{ background:var(--es-grey-50); }
.vp-modal .vp-cat.active{
  background:var(--es-blue-800); border-color:var(--es-blue-800); color:#fff;
}
.vp-modal .vp-cat .font-mono{ font-size:.6875rem; opacity:.8; }

.vp-modal .vp-meta{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  font-size:.8125rem; color:var(--es-text-muted);
}
.vp-modal .vp-bulk{ display:flex; gap:6px; margin-left:auto; }
.vp-modal .vp-select-all{
  background:var(--es-white); border:1.5px solid var(--es-aqua-600); color:var(--es-aqua-700);
  font-weight:600;
}
.vp-modal .vp-deselect-all,
.vp-modal .vp-clear-all{
  background:var(--es-white); border:1.5px solid var(--es-red-500); color:var(--es-red-700);
  font-weight:600;
}

/* Tier 2: the values grid keeps its scrollbar. overflow-y is `scroll`, not `auto`, so the list does not jump sideways as a search narrows it. */
.vp-modal .vp-list{
  display:grid; grid-template-columns:repeat(2, minmax(0,1fr));
  height:46vh; min-height:200px; overflow-y:scroll; overscroll-behavior:contain;
  border:1px solid var(--es-grey-100); border-radius:var(--radius-md); scrollbar-width:thin;
  /* The modal body is a flex column; without this the grid is squeezed instead of the body scrolling. */
  flex:0 0 auto;
}
.vp-modal .vp-row{
  display:flex; align-items:center; gap:11px; margin:0; padding:10px 14px;
  border-bottom:1px solid var(--es-grey-100); cursor:pointer;
  transition:background-color var(--es-dur) var(--es-ease);
}
.vp-modal .vp-row:hover{ background:var(--es-grey-50); }
/* Selection is never colour alone -- the tint is there so a ticked row survives peripheral vision. */
.vp-modal .vp-row--on{ background:var(--es-blue-tint); }
.vp-modal .vp-row input[type="checkbox"]{ flex:0 0 auto; margin:0; accent-color:var(--es-blue-800); }
.vp-modal .vp-code{
  flex:0 0 auto; min-width:66px; font-size:.75rem; font-weight:600; color:var(--es-blue-900);
}
.vp-modal .vp-label{ min-width:0; font-size:.8125rem; }
.vp-modal .vp-empty{
  padding:1rem; text-align:center; font-size:.8125rem; color:var(--es-text-muted);
}

.vp-modal .vp-draft{
  background:var(--es-surface-sunken); border:1px solid var(--es-grey-100);
  border-radius:var(--radius-md); padding:var(--space-3) 14px; flex:0 0 auto;
}
.vp-modal .vp-draft-head{
  display:flex; align-items:center; gap:10px; margin-bottom:var(--space-2);
  font:600 .8125rem/1 var(--es-font-sans); color:var(--es-blue-900);
}
.vp-modal .vp-clear-all{ margin-left:auto; }
.vp-modal .vp-draft-chips{ display:flex; flex-wrap:wrap; gap:6px; max-height:96px; overflow-y:auto; }
.vp-modal .vp-draft-empty{ font-size:.8125rem; color:var(--es-text-muted); }

.vp-modal .modal-footer{ gap:10px; }
.vp-modal .vp-footer-note{
  flex:1 1 auto; min-width:0; margin-right:auto;
  font-size:.75rem; color:var(--es-text-muted);
}
/* In a flex-end footer next to a note, buttons squeeze below their label width and the text wraps. */
.vp-modal .modal-footer .btn{ white-space:nowrap; flex-shrink:0; }

/* Folded into the existing card footer rather than a second floating bar: the footer is the AJAX insertion anchor, and .card is overflow:hidden, which stops position:sticky on a child. */
#pageForm .vp-total{
  margin-right:auto; font-size:.8125rem; color:var(--es-text-muted);
}

@media (max-width: 1199.98px){
  .vp-modal .vp-list{ grid-template-columns:minmax(0,1fr); }
}
@media (max-width: 767.98px){
  .value-picker .vp-edit{ margin-left:0; width:100%; }
  .vp-modal .modal-content{ height:92vh; }
  .vp-modal .vp-controls{ flex-wrap:wrap; }
}

/* Ported from URBI 2026-09-11. URBI numbers this block §15; renumbered to §16 here because
   eMis's §15 is the VALUE PICKER (B29), as is URBI's own §15 — the number is double-booked there. */
/* ============================================================ §16 list filter bar ============ */
/* A list screen's own filters, in a well directly above the grid: quick-find, then one dropdown
   per facet with a live record count against each value. Replaces the left-hand filter rail, so
   the grid takes the full page width. The per-column funnel inside the table (§9) is a different
   control and is untouched — the funnel narrows a column, this bar narrows the screen.
   Facets are <details>, so opening, selecting and applying all work with JavaScript off;
   es-filter-bar.js adds only one-open-at-a-time, outside-click close, and the quick-find. */
.es-fbar                      { display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-2);
                                padding:9px 14px; background:var(--es-surface-sunken);
                                border-bottom:.5px solid var(--es-border-subtle); }

/* A bar with no card to sit inside — the CRM support queue and dev board render their grids bare
   on purpose, and a grey bar on the grey page would have no edges. So it brings its own shell. */
.es-fbar--bare                { background:#fff; border:.5px solid var(--es-border-subtle);
                                border-radius:var(--radius-lg); margin-bottom:var(--space-3); }

/* Quick-find */
.es-fbar-find                 { position:relative; flex:0 1 300px; min-width:170px; }
/* A landing page's search: the right of its heading row, under the ribbon; full width on a phone. */
.es-page-search               { display:flex; align-items:center; gap:var(--space-2); margin-left:auto; flex:0 1 440px; min-width:0; }
.es-page-search .es-fbar-find { flex:1 1 auto; }
@media (max-width:575.98px) { .es-page-search { margin-left:0; flex-basis:100%; } }
.es-fbar-find > i             { position:absolute; left:11px; top:50%; transform:translateY(-50%);
                                font-size:var(--text-xs); color:var(--es-grey-400, #9F9F9F); pointer-events:none; }
.es-fbar-find > input         { width:100%; height:34px; box-sizing:border-box; padding:0 11px 0 30px;
                                border:1.5px solid var(--es-border-input, #E1E6EB); border-radius:var(--radius-sm);
                                background:#fff; font:400 13px var(--es-font-sans);
                                color:var(--es-grey-700, #4D4D4D); outline:none; }
.es-fbar-find > input:focus   { border-color:var(--es-accent); box-shadow:var(--es-shadow-focus-soft); }
/* Both boxes are type=search for the native clear button; Safari would otherwise round them. */
.es-fbar-find > input,
.es-fbar-search               { -webkit-appearance:none; appearance:none; }

/* Submit beside the find box, on a bar whose search runs on the server (a paged table, where a
   browser-side row filter would only ever search the page you are on). Deliberately the form's
   FIRST submit, so Enter in the box searches rather than firing a facet's Clear. */
.es-fbar-go                   { height:34px; padding:0 13px; flex:none; border-radius:var(--radius-sm);
                                border:1.5px solid var(--es-accent); background:var(--es-accent);
                                color:#fff; font:600 13px var(--es-font-sans); cursor:pointer;
                                white-space:nowrap; transition:opacity .12s var(--es-ease); }
.es-fbar-go:hover             { opacity:.86; }
.es-fbar-go:focus-visible     { box-shadow:var(--es-focus-ring); }

/* Facet trigger. Aqua once it carries a selection — the same language as the active-filter chips
   in §9; orange stays reserved for nav chrome. */
.es-fbar-facet                { position:relative; }
.es-fbar-facet > summary      { display:inline-flex; align-items:center; gap:7px; height:34px;
                                padding:0 11px; border:1.5px solid var(--es-border-input, #E1E6EB);
                                border-radius:var(--radius-sm); background:#fff; cursor:pointer; list-style:none;
                                white-space:nowrap; font:600 13px var(--es-font-sans);
                                color:var(--es-grey-700, #4D4D4D);
                                transition:background .12s var(--es-ease), border-color .12s var(--es-ease); }
.es-fbar-facet > summary::-webkit-details-marker { display:none; }
.es-fbar-facet > summary::marker { content:""; }
.es-fbar-facet > summary:hover{ background:var(--es-grey-50, #F1F2F7); border-color:var(--es-grey-300, #C7CCD4); }
.es-fbar-facet > summary:focus-visible { box-shadow:var(--es-focus-ring); border-color:var(--es-accent); }
.es-fbar-facet.is-on > summary{ border-color:var(--es-aqua-500, #00AEEF);
                                background:var(--es-aqua-50, #DFF4FC); color:var(--es-aqua-700, #0673A1); }
.es-fbar-caret                { font-size:9px; color:var(--es-grey-400, #9F9F9F);
                                transition:transform .14s var(--es-ease); }
.es-fbar-facet.is-on > summary .es-fbar-caret { color:var(--es-aqua-700, #0673A1); }
.es-fbar-facet[open] > summary .es-fbar-caret { transform:rotate(180deg); }
/* The count of what is selected, and the count of what a value would return. A count is a value
   the reader is comparing, not chrome, so it takes the strong ink everywhere — including on the
   aqua active chip, where the label stays aqua-700 and only the number goes dark. */
.es-fbar-n                    { font-variant-numeric:tabular-nums;
                                font-size:var(--text-2xs); font-weight:600; color:var(--es-text-strong); }
/* A single-select facet names its choice instead of counting it — one of two says which one. */
.es-fbar-pick                 { font-weight:600; color:var(--es-aqua-700, #0673A1); }

/* Panel. Chrome matches the funnel popover (§9) and reuses its .es-fm-* internals, but anchors to
   its own summary rather than being placed by script. */
.es-fbar-menu                 { position:absolute; z-index:1100; top:calc(100% + 6px); left:0;
                                width:320px; background:#fff; border-radius:12px;
                                border:.5px solid var(--es-border-subtle);
                                box-shadow:0 12px 32px rgba(10,26,47,.22); overflow:hidden;
                                font-family:var(--es-font-sans); color:var(--es-grey-700, #4D4D4D);
                                animation:esMenuIn .12s var(--es-ease); }
.es-fbar-menu.is-end          { left:auto; right:0; }
.es-fbar-menu .es-fm-list     { max-height:252px; }
.es-fbar-menu .es-fm-opt      { gap:9px; }
.es-fbar-menu .es-fm-opt .lbl { flex:1 1 auto; min-width:0; }
.es-fbar-menu .es-fm-opt .es-fbar-n { flex:0 0 auto; }
/* A pick list inside a form: wider, and a long option wraps instead of being cut. */
.es-fbar-facet[data-picks] .es-fbar-menu { width:min(440px, calc(100vw - 32px)); }
.es-fbar-facet[data-picks] .es-fm-opt .lbl { white-space:normal; }
.es-fbar-none                 { padding:14px 9px; text-align:center; font-size:var(--text-sm);
                                color:var(--es-text-muted); }

/* Row count — feedback on what the bar has done, so the quick-find is not silent. */
.es-fbar-count                { margin-left:auto; font:400 12px var(--es-font-sans);
                                color:var(--es-text-body); }
.es-fbar-count b              { font-variant-numeric:tabular-nums; font-weight:600;
                                color:var(--es-text-strong); }
/* .es-clear-all carries margin-left:auto for the in-table chip toolbar; here the count claims it. */
.es-fbar > .es-clear-all      { margin-left:0; }

/* The panel is position:absolute, so .card's overflow:hidden crops it at the card's bottom edge
   (same trap as the row-action flyout above). Release the clip only while a facet is open. */
.card:has(.es-fbar-facet[open]) { overflow:visible; }

@media (max-width:576px){
  .es-fbar-find               { flex:1 1 100%; }
  .es-fbar-menu               { width:min(320px, calc(100vw - 32px)); }
  .es-fbar-count              { margin-left:0; }
}

/* ============================================================ §17 section card grid ========== */
/* The navigation landing page of a module: every ribbon chip repeated as a large, readable card
   so the whole area is one glance and one click away. Currently used by App Config's index.php,
   which builds the cards from the same $sections array its ribbon.php renders the chips from —
   one list, two presentations, so a new section appears in both without being added twice.

   Deliberately NOT a .card: these are navigation targets, not content panels, and they carry the
   hover/press affordance of a button. The chrome (radius, hairline, shadow) still matches §2's
   card so the page reads as one family. */
.es-navgrid            { display:grid; gap:14px; grid-template-columns:repeat(auto-fill,minmax(248px,1fr)); }

.es-navcard            { position:relative; display:flex; align-items:flex-start; gap:var(--space-3);
                         padding:var(--space-4); min-height:96px; background:#fff; border-radius:.625rem;
                         border:.5px solid var(--es-border-subtle); box-shadow:var(--es-shadow-sm);
                         text-decoration:none; color:inherit;
                         transition:transform var(--es-dur) var(--es-ease),
                                    box-shadow var(--es-dur) var(--es-ease),
                                    border-color var(--es-dur) var(--es-ease); }
.es-navcard:hover      { transform:translateY(-2px); box-shadow:var(--es-shadow-md);
                         border-color:var(--es-blue-600); text-decoration:none; color:inherit; }
.es-navcard:active     { transform:none; box-shadow:var(--es-shadow-sm); }
.es-navcard:focus-visible { outline:none; box-shadow:var(--es-focus-ring); border-color:var(--es-accent); }

/* Icon plate. Tinted rather than solid so fifteen of them in a grid stay quiet; it takes the
   accent only on hover, which is what tells you which card the pointer is on. */
.es-navcard-icon       { flex:0 0 auto; display:grid; place-items:center; width:40px; height:40px;
                         border-radius:.5rem; background:var(--es-blue-tint);
                         color:var(--es-blue-800); font-size:17px;
                         transition:background var(--es-dur) var(--es-ease),
                                    color var(--es-dur) var(--es-ease); }
.es-navcard:hover .es-navcard-icon { background:var(--es-blue-800); color:#fff; }

.es-navcard-body       { min-width:0; }
.es-navcard-title      { display:block; font-size:.9375rem; font-weight:600;
                         color:var(--es-text-strong); line-height:1.3; }
.es-navcard-desc       { display:block; margin-top:3px; font-size:.78125rem; line-height:1.45;
                         color:var(--es-text-muted); }

/* Same badge vocabulary as the ribbon chip (§9b) — a count means the same thing in both places.
   Pinned to the top-right corner so it never pushes the title out of line. */
.es-navcard .es-tab-badge { position:absolute; top:10px; right:10px;
                            display:inline-flex; align-items:center; justify-content:center;
                            min-width:18px; height:18px; padding:0 6px; border-radius:var(--radius-pill);
                            font:600 11px/1 var(--es-font-sans); font-variant-numeric:tabular-nums; }

/* A long title would otherwise run under the pinned badge. Only the title needs the gap — the
   description sits below the badge and can use the full width. */
.es-navcard:has(.es-tab-badge) .es-navcard-title { padding-right:var(--space-8); }

/* The card for the page you are already on: still shown, so the grid is the complete list of the
   area, but flattened and non-interactive so it cannot be mistaken for somewhere to go. */
.es-navcard.is-current { background:var(--es-grey-50); border-style:dashed; box-shadow:none;
                         cursor:default; }
.es-navcard.is-current:hover { transform:none; box-shadow:none; border-color:var(--es-border-subtle); }
.es-navcard.is-current .es-navcard-icon { background:var(--es-grey-100); color:var(--es-grey-600); }
.es-navcard.is-current:hover .es-navcard-icon { background:var(--es-grey-100); color:var(--es-grey-600); }

@media (prefers-reduced-motion:reduce){
  .es-navcard,.es-navcard-icon { transition:none; }
  .es-navcard:hover            { transform:none; }
}

/* ================================================== A6 Phase 4: decision screen (from URBI) ====== */
/* Ported from URBI's esuite-bootstrap.css with urbi/enrolment/decision.php, which is the only page
   using them so far: the verification strip, the collapsible answer blocks and the answer a "Change"
   link lands on. Kept verbatim so the two products draw these the same way. */

/* Verification progress. One segment per verification still standing between an enrolment and being
   moved on. Segments rather than one filled bar: a percentage would say how many are done while hiding
   which. */
.es-vprogress                 { display:flex; gap:var(--space-2); width:100%; align-items:flex-end; }
.es-vprogress-item            { flex:1 1 0; min-width:0; display:flex; flex-direction:column; gap:5px; }
/* At the 11px floor in the muted text colour: URBI's 10px grey-400 fails the design rules' size and contrast. */
.es-vprogress-label           { font-size:.6875rem; font-weight:600; line-height:1.25; text-align:center;
                                letter-spacing:.03em; color:var(--es-text-muted);
                                overflow-wrap:anywhere; text-wrap:balance; }
.es-vprogress-seg             { display:block; height:8px; border-radius:var(--radius-pill);
                                background:var(--es-grey-100, #E1E6EB); }
.es-vprogress-seg--met        { background:var(--es-green-500, #27AC2A); }
.es-vprogress-seg--due        { background:var(--es-red-500, #DE1F1F); }

/* The overlay host, for two-column sub-tasks: lg is 800px and even xl only 1140. Capped so it does
   not stretch to nonsense on an ultrawide. decision.php asks for it via esOverlayHost.configure. */
.modal-dialog.modal-wide       { max-width:min(1600px, calc(100vw - 3rem)); }

/* Turned rather than swapped for another glyph, so open and shut are one element. */
.es-collapse-caret            { transition:transform .15s cubic-bezier(.2,0,0,1); }
[aria-expanded="true"] > .es-collapse-caret { transform:rotate(90deg); }

/* The answer a "Change" link landed on. Cells as well as the row: .table-striped paints
   `tbody tr > *`, which would cover a row background on every other one. */
.es-focus-answer,
.es-focus-answer > td         { animation:esFocusAnswer 2.4s cubic-bezier(.2,0,0,1) forwards; }
@keyframes esFocusAnswer      { 0%, 45% { background-color:var(--es-aqua-50, #DFF4FC); }
                                100%    { background-color:transparent; } }
@media (prefers-reduced-motion: reduce) {
    .es-focus-answer,
    .es-focus-answer > td     { animation:none; background-color:var(--es-aqua-50, #DFF4FC); }
}
/* ================================================== end A6 Phase 4 decision screen ================ */

/* ================================================== §17 record pages ============================= */
/* One frame for every record page: es_record_head, es_journey, es_facts and es_checks in esuite-components.php. */
.es-record-head               { display:flex; flex-direction:column; gap:6px; margin-bottom:var(--space-4); }
.es-record-crumbs             { display:flex; flex-wrap:wrap; align-items:center; gap:6px var(--space-2); font-size:.8125rem; color:var(--es-text-muted); }
.es-record-crumbs a           { font-weight:600; }
.es-record-crumb              { font-weight:600; color:var(--es-text-strong); }
.es-record-ref                { font-variant-numeric:tabular-nums; }
.es-record-title              { display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-2) 10px; }
.es-record-title h1           { margin:0; }
.es-record-actions            { display:flex; flex-wrap:wrap; gap:var(--space-2); margin-left:auto; }
.es-record-meta               { margin:0; font-size:.8125rem; color:var(--es-text-muted); }

/* Journey: the steps share the width, and the line into a step turns green once the step is reached. */
.es-journey                   { display:flex; margin:0; padding:var(--space-1) 0 0; list-style:none; overflow-x:auto; }
.es-journey-step              { position:relative; flex:1 1 0; min-width:104px; display:flex; flex-direction:column; align-items:center;
                                gap:3px; padding:0 var(--space-1); text-align:center; }
.es-journey-step + .es-journey-step::before { content:""; position:absolute; top:13px; left:calc(-50% + 18px); right:calc(50% + 18px);
                                height:2px; border-radius:var(--radius-pill); background:var(--es-grey-100); }
.es-journey-step.is-done::before,
.es-journey-step.is-current::before { background:var(--es-green-500); }
.es-journey-step.is-stopped::before { background:var(--es-red-500); }
.es-journey-dot               { display:inline-flex; align-items:center; justify-content:center; width:28px; height:28px; border-radius:50%;
                                background:var(--es-grey-100); color:var(--es-grey-600); font-size:.75rem; }
.is-done > .es-journey-dot    { background:var(--es-green-700); color:#fff; }
.is-current > .es-journey-dot { background:var(--es-blue-800); color:#fff; box-shadow:0 0 0 4px var(--es-blue-tint); }
.is-stopped > .es-journey-dot { background:var(--es-red-700); color:#fff; }
.es-journey-label             { font-size:.8125rem; font-weight:600; line-height:1.3; color:var(--es-text-strong); }
.is-todo > .es-journey-label  { font-weight:500; color:var(--es-text-muted); }
.es-journey-when,
.es-journey-note              { font-size:.75rem; line-height:1.35; color:var(--es-text-muted); }

/* Facts: label, value, and the one action that changes it. */
.es-facts-group               { padding:14px var(--space-4) 2px; }
.es-fact-list                 { margin:0; }
.es-fact                      { display:grid; grid-template-columns:minmax(110px, 32%) minmax(0, 1fr) auto; align-items:center;
                                gap:2px 14px; min-height:44px; padding:var(--space-2) var(--space-4); border-bottom:.5px solid var(--es-grey-100); }
.es-facts > .es-fact-list:last-child > .es-fact:last-child { border-bottom:0; }
.es-fact > dt                 { font-size:.8125rem; font-weight:600; color:var(--es-text-strong); }
.es-fact > dd                 { margin:0; min-width:0; font-size:.8125rem; color:var(--es-text-body); overflow-wrap:anywhere; }
.es-fact > dd.is-empty        { color:var(--es-text-muted); }
.es-fact > dd.es-fact-action  { justify-self:end; }
/* Stacked, label above value, wherever the list itself is narrower than 360px. */
.es-facts                     { container:es-facts / inline-size; }
@container es-facts (max-width: 359.98px) {
    .es-fact                  { grid-template-columns:minmax(0, 1fr) auto; row-gap:2px; }
    .es-fact > dt             { grid-column:1; grid-row:1; font-size:.75rem; font-weight:400; color:var(--es-text-muted); }
    .es-fact > dd:not(.es-fact-action) { grid-column:1; grid-row:2; color:var(--es-text-strong); }
    .es-fact > dd.is-empty    { color:var(--es-text-muted); }
    .es-fact > dd.es-fact-action { grid-column:2; grid-row:1 / span 2; }
}

/* Checks: the decision screen's rows, as a component. */
.es-check                     { display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-2) var(--space-3); }
.es-check-icon                { flex:none; width:22px; text-align:center; }
.es-checks .fa-circle-check   { transform:scale(1.5); transform-origin:center; }
.es-check-main                { flex:1 1 280px; min-width:0; display:flex; flex-wrap:wrap; align-items:baseline; gap:2px var(--space-4); }
.es-check-label               { flex:0 0 38%; min-width:160px; font-weight:600; color:var(--es-text-strong); }
.es-check-value               { flex:1 1 200px; min-width:0; font-size:.8125rem; color:var(--es-text-muted); }
.es-check.is-due .es-check-value { color:var(--es-orange-600); }
.es-check-action              { margin-left:auto; text-align:right; }
.es-checks-summary            { margin:0 0 6px; font-size:.75rem; font-weight:600; color:var(--es-text-muted); }

/* Small labelled actions on a record, side by side while there is room. */
.es-action-groups             { display:grid; grid-template-columns:repeat(auto-fit, minmax(240px, 1fr)); gap:var(--space-3) var(--space-6); }
.es-action-groups .es-eyebrow { margin-bottom:6px; }
/* A cell whose text may run to several lines: titles, notes, a status with its sub-status. */
.es-table td.es-wrap          { white-space:normal; min-width:12rem; overflow-wrap:break-word; }

/* Timeline: contact logged and changes made, latest first; the icon's tint says who started it. */
.es-timeline                  { list-style:none; margin:0; padding:0; }
.es-timeline-item             { display:flex; gap:var(--space-3); padding:10px var(--space-4); border-bottom:.5px solid var(--es-grey-100); }
.es-timeline-item:last-child  { border-bottom:0; }
.es-timeline-icon             { flex:none; display:inline-flex; align-items:center; justify-content:center; width:30px; height:30px;
                                border-radius:50%; font-size:.75rem; background:var(--es-surface-sunken); color:var(--es-grey-700); }
.es-timeline-icon.tone-aqua   { background:var(--es-aqua-50); color:var(--es-aqua-700); }
.es-timeline-icon.tone-blue   { background:var(--es-blue-tint); color:var(--es-blue-800); }
.es-timeline-icon.tone-green  { background:var(--es-green-50); color:var(--es-green-700); }
.es-timeline-icon.tone-orange { background:var(--es-orange-50); color:var(--es-orange-600); }
.es-timeline-icon.tone-red    { background:var(--es-red-50); color:var(--es-red-700); }
.es-timeline-body             { flex:1 1 auto; min-width:0; }
.es-timeline-head             { display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-1) var(--space-2); }
.es-timeline-title            { font-size:.8125rem; font-weight:600; color:var(--es-text-strong); }
.es-timeline-meta             { margin-left:auto; font-size:.75rem; color:var(--es-text-muted); }
.es-timeline-text             { margin:var(--space-1) 0 0; font-size:.8125rem; color:var(--es-text-body); overflow-wrap:anywhere; }
.es-timeline-empty            { margin:0; padding:var(--space-3) var(--space-4); font-size:.8125rem; color:var(--es-text-muted); }
/* ================================================== end §17 record pages ========================= */

/* ============================================================ §18 XML fragment view ========== */
/* A stored ILR fragment, drawn by ILR\Viewer\XmlTree. The values are what the page is read for, so
   they take the strong ink; tag names take the accent; punctuation and closing tags step back to
   muted, which still clears 4.5:1 on white and on the hover tint. */
.es-xml                       { border:.5px solid var(--es-border-subtle); border-radius:.625rem;
                                overflow:hidden; background:var(--es-white); }
.es-xml + .es-xml             { margin-top:1rem; }
.es-xml-head                  { display:flex; align-items:center; flex-wrap:wrap; gap:.5rem;
                                padding:.5rem .75rem; background:var(--es-row-stripe);
                                border-bottom:.5px solid var(--es-border-subtle); }
.es-xml-head > .fa-file-code  { color:var(--es-aqua-700, #0673A1); }
.es-xml-title                 { font-weight:600; color:var(--es-text-strong); }
.es-xml-sub                   { color:var(--es-text-muted); }
.es-xml-actions               { margin-left:auto; display:flex; flex-wrap:wrap; gap:.375rem; }

/* Left padding is the root's caret gutter. */
.es-xml-tree                  { margin:0; padding:.75rem 1rem .875rem 1.75rem; overflow-x:auto;
                                font:400 12px/1.7 var(--es-font-mono); color:var(--es-text-body); }
.es-xml-raw                   { padding-left:1rem; white-space:pre-wrap; }
.es-xml-line                  { white-space:pre-wrap; overflow-wrap:anywhere; }
.es-xml-p,
.es-xml-c,
.es-xml-cmt                   { color:var(--es-text-muted); }
.es-xml-t                     { color:var(--es-aqua-700, #0673A1); }
.es-xml-a                     { color:var(--es-blue-800); }
.es-xml-v                     { color:var(--es-text-strong); font-weight:500; }
/* What a code means, or an aim's title. A pill in the sans face so it cannot be mistaken for part
   of the XML; one line only, as a title runs to 254 characters, with the whole text on hover. */
.es-xml-n                     { display:inline-block; max-width:min(60ch, 100%); margin-left:.625rem;
                                padding:0 .5rem; border-radius:var(--radius-pill); vertical-align:middle;
                                overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
                                background:var(--es-grey-50, #F1F2F7); color:var(--es-text-muted);
                                font:400 12px/1.5 var(--es-font-sans); }
.es-xml-pair .es-xml-n        { max-width:28ch; margin-left:.375rem; }
.es-xml-node > summary:hover .es-xml-n { background:var(--es-white); }

/* One indent per level. The guide is an inset shadow, not a left border: a neutral 1px line, not the
   coloured rule that belongs to alerts. It darkens while its opening tag is hovered. */
.es-xml-kids                  { margin-left:.3125rem; padding-left:1.125rem;
                                box-shadow:inset 1px 0 0 var(--es-grey-100, #E1E6EB); }
/* 2px top and bottom lifts an opening tag to the 24px a target needs, as these sit one under another. */
.es-xml-node > summary        { position:relative; display:block; padding:2px 0; cursor:pointer;
                                list-style:none; border-radius:var(--radius-xs); }
.es-xml-node > summary::-webkit-details-marker { display:none; }
.es-xml-node > summary::marker{ content:""; }
.es-xml-node > summary:hover  { background:var(--es-row-stripe); }
.es-xml-node > summary:hover + .es-xml-kids { box-shadow:inset 1px 0 0 var(--es-grey-400, #9F9F9F); }
.es-xml-node > summary:focus-visible { outline:none; box-shadow:var(--es-focus-ring); }
.es-xml-node > summary::before{ content:""; position:absolute; left:-13px; top:8px;
                                border-style:solid; border-width:4px 0 4px 5px;
                                border-color:transparent transparent transparent var(--es-text-muted);
                                transition:transform var(--es-dur) var(--es-ease); }
.es-xml-node[open] > summary::before { transform:rotate(90deg); }

/* A shut block names its first few values, so one LearningDelivery can be told from the next. */
.es-xml-hint                  { display:none; }
.es-xml-node:not([open]) > summary > .es-xml-hint { display:inline; }
.es-xml-more                  { display:inline-block; margin:0 .625rem 0 .375rem; padding:0 .375rem;
                                line-height:1.4; border-radius:var(--radius-xs);
                                background:var(--es-grey-100, #E1E6EB); color:var(--es-grey-700, #4D4D4D); }
.es-xml-pair                  { margin-right:.875rem; font:400 11px var(--es-font-sans); color:var(--es-text-muted); }
.es-xml-pair b                { font:500 12px var(--es-font-mono); color:var(--es-text-strong); }

@media (prefers-reduced-motion: reduce) {
  .es-xml-node > summary::before { transition:none; }
}

/* ============================================================ §19 user menu ========== */
/* Last in the top bar: the user's initials and name open a navy panel of the account pages and Log out (views/account/userMenu.php). */
.es-user-menu { position:relative; display:flex; align-items:center; margin-left:var(--space-2); }
.es-user-menu-button { display:inline-flex; align-items:center; gap:var(--space-2); min-height:32px; padding:2px var(--space-3) 2px 2px;
                       border:0; border-radius:var(--radius-pill); background:rgba(255,255,255,.08); color:#fff; font:600 var(--text-sm) var(--es-font-sans); cursor:pointer; }
.es-user-menu-button:hover, .es-user-menu-button[aria-expanded="true"] { background:rgba(255,255,255,.16); }
.es-user-menu-name { max-width:180px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.es-user-menu-chevron { font-size:var(--text-xs); transition:transform var(--es-dur) var(--es-ease); }
.es-user-menu-button[aria-expanded="true"] .es-user-menu-chevron { transform:rotate(180deg); }
.es-user-menu-panel { position:absolute; top:calc(100% + 6px); right:0; z-index:1035; min-width:260px; max-width:min(320px, calc(100vw - 32px)); padding:6px;
                      background:var(--es-blue-900, #293F6D); border:1px solid rgba(255,255,255,.12); border-radius:var(--radius-lg); box-shadow:var(--es-shadow-md); }
.es-user-menu-panel[hidden] { display:none; }
.es-user-menu-who { display:flex; flex-direction:column; gap:2px; margin:0; padding:var(--space-2) var(--space-3); color:#fff; font-size:var(--text-sm); }
.es-user-menu-full { font-weight:600; overflow-wrap:anywhere; }
.es-user-menu-email { color:var(--text-on-navy-muted); font-size:var(--text-xs); overflow-wrap:anywhere; }
.es-user-menu-links { margin:0; padding:0; list-style:none; }
.es-user-menu-item { display:flex; align-items:center; gap:9px; width:100%; min-height:32px; padding:var(--space-2) var(--space-3); border:0; border-radius:var(--radius-sm);
                     background:none; color:var(--text-on-navy-muted); font-size:var(--text-sm); text-align:left; text-decoration:none; white-space:nowrap; cursor:pointer; }
.es-user-menu-item:hover { background:rgba(255,255,255,.12); color:#fff; }
/* The open page is filled as the bar's other menus fill theirs. */
.es-user-menu-item[aria-current="page"] { background:var(--es-aqua-700); color:#fff; font-weight:600; }
.es-user-menu-divider { margin:6px 0; border:0; border-top:1px solid rgba(255,255,255,.14); opacity:1; }
.es-user-menu-out { margin:0; }
/* Collapsed bar: the initials alone, the name kept for screen readers, and the panel under the bar, clear of the bookmark tab at the edge. */
@media (max-width: 991.98px) {
  .es-user-menu { position:static; }
  .es-user-menu-button { padding:2px; }
  .es-user-menu-name { position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }
  .es-user-menu-chevron { display:none; }
  .es-user-menu-panel { top:100%; left:14px; right:14px; max-width:none; border-radius:0 0 var(--radius-lg) var(--radius-lg); }
}
@media (prefers-reduced-motion: reduce) {
  .es-user-menu-chevron { transition:none; }
}

/* ============================================================ §19a user pill and notifications bell ========== */
/* The bell and the user menu share one navy pill at the end of the bar; each opens its own panel, right-aligned to the pill. */
.es-user-pill { position:relative; display:flex; align-items:center; gap:8px; height:42px; margin-left:var(--space-2); padding:0 14px 0 4px;
                border-radius:var(--radius-pill); background:var(--es-accent-press); }
.es-user-pill .es-user-menu { position:static; margin-left:0; }
.es-user-pill .es-user-menu-button { padding:0; background:transparent; font-size:var(--text-sm); }
.es-user-pill .es-user-menu-button:hover, .es-user-pill .es-user-menu-button[aria-expanded="true"] { background:transparent; opacity:.86; }
.es-user-pill .es-user-menu-chevron { font-size:var(--text-2xs); }
.es-bell { display:flex; align-items:center; }
.es-bell-button { position:relative; display:inline-flex; align-items:center; justify-content:center; width:32px; height:32px; padding:0; border:0;
                  border-radius:var(--radius-pill); background:var(--es-white); color:var(--es-blue-800); font-size:14px; line-height:1; cursor:pointer; }
.es-bell-button:hover { opacity:.86; }
.es-bell-button:active { color:var(--es-accent-press); }
.es-bell-button::after { content:""; position:absolute; inset:0; border-radius:inherit; pointer-events:none; }
.es-bell.is-new .es-bell-button::after { box-shadow:0 0 0 2px var(--es-red-500); animation:esBellGlow 1.8s var(--es-ease) 2; }
@keyframes esBellGlow {
  0%   { box-shadow:0 0 0 0 color-mix(in srgb, var(--es-red-500) 75%, transparent); }
  70%  { box-shadow:0 0 0 9px color-mix(in srgb, var(--es-red-500) 0%, transparent); }
  100% { box-shadow:0 0 0 0 color-mix(in srgb, var(--es-red-500) 0%, transparent); }
}
.es-bell-count { position:absolute; top:-5px; right:-6px; z-index:1; display:inline-flex; align-items:center; justify-content:center; min-width:18px; height:18px;
                 padding:0 4px; border:1.5px solid var(--es-accent-press); border-radius:var(--radius-pill); background:var(--es-red-500); color:var(--es-white);
                 font:600 var(--text-2xs) var(--es-font-sans); font-variant-numeric:tabular-nums; line-height:1; }
.es-bell-count[hidden] { display:none; }
.es-bell-panel { position:absolute; top:calc(100% + 6px); right:0; z-index:1035; width:min(360px, calc(100vw - 32px)); padding:8px; background:var(--es-white);
                 border:1px solid var(--es-grey-100); border-radius:var(--radius-lg); box-shadow:var(--es-shadow-lg); color:var(--es-text-body); text-align:left; }
.es-bell-panel[hidden] { display:none; }
.es-bell-head { display:flex; align-items:center; justify-content:space-between; gap:8px; padding:4px 8px 8px; }
.es-bell-title { margin:0; color:var(--es-text-strong); font:600 var(--text-sm) var(--es-font-sans); }
.es-bell-action { padding:4px 6px; border:0; border-radius:var(--radius-sm); background:none; color:var(--es-accent); font:600 var(--text-xs) var(--es-font-sans);
                  text-decoration:underline; cursor:pointer; }
.es-bell-action[hidden], .es-bell-note[hidden] { display:none; }
.es-bell-note { margin:0; padding:12px 8px; color:var(--es-text-muted); font-size:var(--text-sm); }
.es-bell-list { max-height:min(60vh, 420px); margin:0; padding:0; overflow-y:auto; list-style:none; }
.es-bell-link { display:flex; flex-direction:column; gap:2px; padding:8px; border-left:3px solid transparent; border-radius:var(--radius-sm); color:var(--es-text-body);
                text-decoration:none; }
.es-bell-link:hover { background:var(--es-blue-tint); }
.es-bell-item.is-unread .es-bell-link { border-left-color:var(--es-accent); }
.es-bell-item.is-unread .es-bell-subject { color:var(--es-text-strong); font-weight:600; }
.es-bell-subject { font-size:var(--text-sm); overflow-wrap:anywhere; }
.es-bell-meta { color:var(--es-text-muted); font-size:var(--text-xs); }
.es-bell-all { display:block; padding:8px; color:var(--es-accent); font-size:var(--text-sm); text-align:center; }
/* Collapsed bar: the pill stays beside the menu button and both panels open under the bar. */
@media (max-width: 991.98px) {
  .es-user-pill { position:static; }
  .es-bell-panel { top:100%; left:14px; right:14px; width:auto; border-radius:0 0 var(--radius-lg) var(--radius-lg); }
}
@media (prefers-reduced-motion: reduce) {
  .es-bell.is-new .es-bell-button::after { animation:none; }
}

/* ============================================================ §20 pin buttons and live region ========== */
/* Kept from the retired learner rail's stylesheet, which the head no longer loads: the top bar uses them. */
.es-pin-toggle {
    flex: 0 0 auto;
    border: 0;
    background: transparent;
    color: rgba(255, 255, 255, .4);
    padding: 6px 10px;
    cursor: pointer;
    font-size: .8125rem;
    border-radius: 6px;
    transition: color .15s cubic-bezier(.2, 0, 0, 1), background-color .15s cubic-bezier(.2, 0, 0, 1);
}
.es-pin-toggle:hover { color: #fff; background: rgba(255, 255, 255, .1); }
.es-pin-toggle.is-pinned,
.es-pin-toggle[aria-pressed="true"] { color: var(--es-aqua-500, #00AEEF); }
.es-pin-toggle .fa-thumbtack { transform: rotate(45deg); }
.es-pin-grip {
    flex: 0 0 auto;
    border: 0;
    background: transparent;
    color: rgba(255, 255, 255, .3);
    padding: 6px 4px 6px 8px;
    cursor: grab;
    font-size: .8125rem;
    opacity: 0;
    transition: opacity .12s cubic-bezier(.2, 0, 0, 1), color .12s cubic-bezier(.2, 0, 0, 1);
}
.es-pin-grip:hover { color: #fff; }
.es-pin-grip:active { cursor: grabbing; }
.es-pin-grip:focus-visible {
    outline: none;
    opacity: 1;
    box-shadow: 0 0 0 2px var(--es-blue-900, #293F6D), 0 0 0 4px #fff;
    border-radius: 4px;
}
/* Visually hidden: the top bar's live region for reorder announcements. */
.es-sr-only {
    position: absolute !important;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0);
    white-space: nowrap; border: 0;
}

/* ── Multi-select dropdown (es_multi_select, es-multiselect.js) ─────────────────
   A select-looking button naming what is ticked; its panel holds a checkbox per option, a search box once the
   list is long, and Clear / Done. The panel sits over what follows rather than pushing it down. */
.es-ms{ position:relative; }
.es-ms-control{ position:relative; }
.es-ms-toggle{ text-align:left; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.es-ms-menu{ position:absolute; z-index:1040; top:calc(100% + .25rem); left:0; right:0; min-width:16rem;
  background:#fff; border:1px solid var(--es-border-input); border-radius:var(--radius-md); padding:.5rem;
  box-shadow:var(--shadow-md); }
.es-ms-menu[hidden], .es-ms [data-ms-option][hidden], .es-ms-none[hidden]{ display:none; }
.es-ms-search{ margin-bottom:.5rem; }
.es-ms-list{ max-height:16rem; overflow-y:auto; margin:0; padding:.125rem .25rem; border:0; }
.es-ms-list .form-check{ margin-bottom:.25rem; }
.es-ms-foot{ display:flex; justify-content:flex-end; gap:.5rem; margin-top:.5rem; padding-top:.5rem; border-top:1px solid var(--es-grid-line); }

/* ── Tooltip (es_tip, es-tip.js) ─────────────────────────────────────────────────
   Shown while its label is hovered or its control has keyboard focus; the pointer can move onto it, and Escape
   hides it (WCAG 1.4.13). It sits beside the label with an info button that opens it on touch. */
.es-tip{ display:none; position:absolute; z-index:1060; bottom:calc(100% + .5rem); left:50%; transform:translateX(-50%);
  width:max-content; max-width:min(18rem, calc(100vw - 16px)); white-space:normal; text-align:left;
  background:var(--es-blue-900); color:#fff; font-size:.75rem; font-weight:400; line-height:1.35;
  padding:.4rem .6rem; border-radius:var(--radius-sm); }
.es-tip-host:hover > .es-tip,
.es-tip-host:focus-within > .es-tip,
.es-tip.is-open{ display:block; }
.es-tip-host{ position:relative; display:inline-flex; align-items:center; gap:.125rem; }
.es-tip-btn{ display:inline-flex; align-items:center; justify-content:center; width:24px; height:24px; padding:0; border:0; border-radius:50%;
  background:none; color:var(--es-text-muted); font-size:var(--text-sm); cursor:pointer; }
.es-tip-btn:hover{ color:var(--es-blue-800); }
.es-tip-dismissed .es-tip{ display:none !important; }
.es-segmented .form-check-label{ position:relative; }

/* An email signature shown as it will look, in a sandboxed frame (Your mailboxes, the record composer). */
.es-signature-preview{ display:block; width:100%; max-width:40rem; height:10rem; border:var(--border-hairline) solid var(--es-border-subtle); border-radius:var(--radius-sm); background:var(--surface-card); }
.es-signature-preview[hidden]{ display:none; }
