@charset "UTF-8";
/* ==========================================================================
   Class Recruitment — V2 DNN Skin Stylesheet
   --------------------------------------------------------------------------
   Built from typography-spec.html. Design tokens at the top, base layer,
   skin chrome (header + burger overlay + footer), DNN panes, modules.
   ========================================================================== */

/* ============ 1. DESIGN TOKENS ============ */

:root {
  /* Brand purples */
  --c-purple-deep:  #7b1fa2;
  --c-purple:       #8e24aa;
  --c-purple-light: #ba68c8;
  --c-purple-tint:  #f3e8f7;
  --c-purple-mist:  #faf5fb;
  --c-purple-dark:  #4a0e69;

  /* Accent ramps */
  --c-pink:       #d61671;  --c-pink-soft:  #fde4ef;  --c-pink-deep:  #a01057;
  --c-teal:       #00acc1;  --c-teal-soft:  #d6f1f5;  --c-teal-deep:  #006c7a;
  --c-green:      #43a047;  --c-green-soft: #dcefdd;  --c-green-deep: #2d6a30;
  --c-amber:      #ffa000;  --c-amber-soft: #ffeccd;  --c-amber-deep: #8a5500;
  --c-coral:      #ff6e40;  --c-coral-soft: #ffe2d6;  --c-coral-deep: #b34a25;
  --c-red:        #ed1b2d;  --c-red-soft:   #fde2e4;  --c-red-deep:   #8a0a17;
  --c-yellow-soft:#fff3a8;

  /* Functional */
  --c-success: var(--c-green);
  --c-warning: var(--c-amber);
  --c-error:   var(--c-red);
  --c-info:    var(--c-teal);

  /* Neutrals */
  --c-ink:         #1f1530;
  --c-ink-strong:  #110a1f;
  --c-ink-muted:   #5a4f66;
  --c-ink-subtle:  #8a8294;
  --c-line:        #ece8f0;
  --c-line-strong: #d8d2e0;
  --c-bg:          #ffffff;
  --c-bg-soft:     #faf8fc;
  --c-bg-tint:     #f5f1f8;

  /* Type */
  --font-display: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-body:    'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Fluid type scale */
  --t-display: clamp(56px, 7vw + 1rem, 80px);
  --t-h1:      clamp(40px, 4vw + 1rem, 56px);
  --t-h2:      clamp(28px, 2.5vw + 1rem, 40px);
  --t-h3:      24px;
  --t-h4:      20px;
  --t-h5:      17px;
  --t-h6:      14px;
  --t-lead:    20px;
  --t-body:    16px;
  --t-small:   14px;
  --t-micro:   12px;

  --lh-display: 1.05;
  --lh-tight:   1.1;
  --lh-snug:    1.25;
  --lh-normal:  1.6;
  --lh-relaxed: 1.7;

  /* Spacing 4-px scale */
  --s-1: 4px;   --s-2: 8px;   --s-3: 12px;  --s-4: 16px;
  --s-5: 24px;  --s-6: 32px;  --s-7: 48px;  --s-8: 64px;
  --s-9: 96px;  --s-10: 128px;

  /* Radii */
  --r-xs: 4px;  --r-sm: 8px;  --r-md: 14px;  --r-lg: 20px;  --r-xl: 28px;  --r-pill: 999px;

  /* Shadows (purple-tinted) */
  --shadow-xs: 0 1px 2px rgba(31,21,48,0.04);
  --shadow-sm: 0 2px 6px rgba(31,21,48,0.05), 0 1px 2px rgba(31,21,48,0.04);
  --shadow-md: 0 6px 18px rgba(123,31,162,0.08), 0 2px 4px rgba(31,21,48,0.04);
  --shadow-lg: 0 14px 40px rgba(123,31,162,0.12), 0 4px 10px rgba(31,21,48,0.05);
  --shadow-xl: 0 24px 60px rgba(123,31,162,0.18);
  --shadow-focus: 0 0 0 4px rgba(186,104,200,0.35);

  /* Layout */
  --container: 1200px;

  /* Motion */
  --ease:     cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 140ms;
  --dur:      220ms;
  --dur-slow: 420ms;

  /* Header */
  --header-h: 88px;
  --logo-h-desktop: 56px;
  --logo-h-mobile:  44px;
}

/* ============ 2. BASE RESET ============ */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: var(--lh-normal);
  color: var(--c-ink);
  background: var(--c-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
body.is-overlay-open { overflow: hidden; }
img, svg, video { max-width: 100%; height: auto; display: block; }
::selection { background: var(--c-purple-light); color: #fff; }

/* ============ 3. TYPOGRAPHY ============ */

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  color: var(--c-ink-strong);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: var(--lh-tight);
}

h1 {
  font-size: var(--t-h1);
  letter-spacing: -0.03em;
  line-height: 1.1;
  margin: 0 0 var(--s-5);
}
h2 {
  font-size: var(--t-h2);
  letter-spacing: -0.025em;
  line-height: 1.15;
  margin: var(--s-7) 0 var(--s-4);
}
h3 {
  font-size: var(--t-h3);
  letter-spacing: -0.02em;
  line-height: 1.2;
  margin: var(--s-6) 0 var(--s-3);
}
h4 {
  font-size: var(--t-h4);
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: var(--lh-snug);
  margin: var(--s-5) 0 var(--s-2);
}
h5 {
  font-size: var(--t-h5);
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.3;
  margin: var(--s-4) 0 var(--s-2);
}
h6 {
  font-size: var(--t-h6);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--c-purple-deep);
  line-height: 1.3;
  margin: 0 0 var(--s-2);
}

.display {
  font-family: var(--font-display);
  font-size: var(--t-display);
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: var(--lh-display);
  color: var(--c-ink-strong);
  margin: 0 0 var(--s-5);
}

p {
  font-size: var(--t-body);
  font-weight: 400;
  line-height: var(--lh-normal);
  margin: 0 0 var(--s-4);
}

.lead {
  font-size: var(--t-lead);
  line-height: var(--lh-normal);
  color: var(--c-ink-muted);
  font-weight: 400;
}

small, .small {
  font-size: var(--t-small);
  line-height: 1.55;
  color: var(--c-ink-muted);
}
.micro {
  font-size: var(--t-micro);
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.02em;
  color: var(--c-ink-subtle);
}
.eyebrow {
  display: inline-block;
  font-family: var(--font-display);
  font-size: var(--t-micro);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--c-purple-deep);
  margin-bottom: var(--s-3);
}

.muted   { color: var(--c-ink-muted); }
.subtle  { color: var(--c-ink-subtle); }

a {
  color: var(--c-purple-deep);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1.5px;
  transition: color var(--dur) var(--ease), text-decoration-thickness var(--dur) var(--ease);
}
/* :focus and :active are matched here deliberately, not just :hover. DNN core sets
   `a:active,a:focus,a:hover{color:var(--dnn-color-foreground-light,#222)}`, and the
   token bridge in section 15.1 maps that variable to --c-line-strong because DNN's
   other 19 uses of it are all borders. The theme already outranked DNN on :hover,
   but had no :focus/:active rule at all — leaving a focused or clicked link to take
   that near-white border colour and disappear against a light background. */
a:hover, a:focus, a:active { color: var(--c-purple); text-decoration-thickness: 2px; }
a:focus-visible { outline: none; box-shadow: var(--shadow-focus); border-radius: var(--r-xs); }

strong, b { font-weight: 600; color: var(--c-ink-strong); }
em, i     { font-style: italic; }

code, kbd, pre {
  font-family: var(--font-mono);
  font-size: 0.9em;
}
code {
  background: var(--c-bg-tint);
  color: var(--c-purple-deep);
  padding: 2px 6px;
  border-radius: var(--r-xs);
}
kbd {
  background: var(--c-bg);
  border: 1px solid var(--c-line-strong);
  border-bottom-width: 2px;
  padding: 2px 6px;
  border-radius: 6px;
  color: var(--c-ink);
  font-size: 0.85em;
}
mark { background: var(--c-yellow-soft); padding: 2px 6px; border-radius: 4px; color: var(--c-ink-strong); }

blockquote {
  margin: var(--s-6) 0;
  padding: var(--s-5) var(--s-6);
  border-left: 4px solid var(--c-purple-light);
  background: var(--c-purple-mist);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  font-family: var(--font-display);
  font-size: var(--t-lead);
  font-style: italic;
  line-height: 1.5;
  color: var(--c-ink);
}
blockquote cite {
  display: block;
  margin-top: var(--s-3);
  font-family: var(--font-body);
  font-size: var(--t-small);
  font-style: normal;
  color: var(--c-ink-muted);
}

hr { border: 0; height: 1px; background: var(--c-line); margin: var(--s-6) 0; }

ul, ol {
  font-size: var(--t-body);
  line-height: var(--lh-normal);
  margin: 0 0 var(--s-4);
  padding-left: 22px;
}
li { margin-bottom: var(--s-2); }
ul > li::marker { color: var(--c-purple); }
ol > li::marker { color: var(--c-purple-deep); font-weight: 600; }

dl { margin: 0 0 var(--s-4); }
dt { font-family: var(--font-display); font-weight: 600; color: var(--c-ink-strong); }
dd { margin: 0; color: var(--c-ink-muted); }

/* Opt-in two-column term/definition grid. Use only on dl elements that
   are semantically a label/value list — never on module-output dl tags. */
.dl-grid { display: grid; grid-template-columns: 140px 1fr; gap: var(--s-2) var(--s-4); }
.dl-grid dt { font-size: var(--t-small); }
.dl-grid dd { font-size: var(--t-small); }

figure { margin: 0 0 var(--s-5); background: var(--c-bg-soft); border-radius: var(--r-md); padding: var(--s-5); }
figcaption { font-size: 13px; font-style: italic; color: var(--c-ink-muted); margin-top: var(--s-3); text-align: center; }

table { width: 100%; border-collapse: collapse; font-size: var(--t-small); margin: 0 0 var(--s-5); }
table caption {
  text-align: left;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 600;
  color: var(--c-ink-muted);
  padding-bottom: var(--s-2);
  caption-side: top;
}
th {
  font-family: var(--font-display);
  font-size: var(--t-micro);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--c-ink-muted);
  text-align: left;
  padding: var(--s-3) var(--s-4);
  border-bottom: 1.5px solid var(--c-line-strong);
}
td { padding: 14px var(--s-4); border-bottom: 1px solid var(--c-line); color: var(--c-ink); }
tbody tr:hover { background: var(--c-bg-soft); }

/* ============ 4. LAYOUT ============ */

.class-container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--s-5);
}
.class-theme { min-height: 100vh; display: flex; flex-direction: column; }
.class-main  { flex: 1 1 auto; padding-block: var(--s-6) var(--s-8); }
.class-pane  { width: 100%; }

/* ContentPane is the main page area — constrain to container width like the header.
   BannerPane and FluidPane stay full-bleed so hero banners and full-width modules can
   reach the viewport edges if they want to. */
.class-pane--content {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--s-5);
}
.class-pane--banner { margin-bottom: var(--s-6); }
.class-pane--fluid  { margin-top:    var(--s-6); }

/* ============ 5. HEADER ============ */

.class-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255, 255, 255, 0.85);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--c-line);
}
.class-header__row {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  min-height: var(--header-h);
  padding-block: var(--s-3);
}
.class-header__logo { display: flex; align-items: center; flex-shrink: 0; }
.class-header__logo img,
.class-header__logo svg {
  height: var(--logo-h-desktop);
  width: auto;
}
@media (max-width: 720px) {
  .class-header__logo img,
  .class-header__logo svg { height: var(--logo-h-mobile); }
  :root { --header-h: 72px; }
}

/* Search */
.class-header__search { flex: 1 1 auto; min-width: 0; display: flex; justify-content: center; }
.class-search-toggle {
  display: none;
  background: var(--c-bg);
  border: 1.5px solid var(--c-line);
  width: 44px; height: 44px;
  border-radius: var(--r-pill);
  align-items: center;
  justify-content: center;
  color: var(--c-ink);
  cursor: pointer;
  transition: all var(--dur) var(--ease);
}
.class-search-toggle:hover { border-color: var(--c-purple-light); color: var(--c-purple-deep); }
.class-search-toggle:focus-visible { outline: none; box-shadow: var(--shadow-focus); }

.class-search-field {
  position: relative;
  width: 100%;
  max-width: 460px;
}
.class-search-field__icon {
  position: absolute;
  left: 18px; top: 50%;
  transform: translateY(-50%);
  color: var(--c-ink-subtle);
  pointer-events: none;
  z-index: 1;
}
.class-search-input,
.class-search-field input[type="text"],
.class-search-field input[type="search"] {
  width: 100%;
  font-family: var(--font-body);
  font-size: var(--t-body);
  color: var(--c-ink);
  background: var(--c-bg-soft);
  padding: 12px 18px 12px 48px;
  border: 1.5px solid var(--c-line);
  border-radius: var(--r-pill);
  transition: all var(--dur) var(--ease);
  -webkit-appearance: none; appearance: none;
}
.class-search-field input::placeholder { color: var(--c-ink-subtle); }
.class-search-field input:hover { border-color: var(--c-purple-light); }
.class-search-field input:focus {
  outline: none;
  background: var(--c-bg);
  border-color: var(--c-purple);
  box-shadow: var(--shadow-focus);
}

/* DNN renders the search clear button as .dnnSearchBoxClearText inside .searchInputContainer.
   DNN's own stylesheet (SearchSkinObjectPreview.css) uses selector specificity (0,2,1) and sets
   margin:7px with no top — placing the button below the input. We use a 3-class selector (0,3,1)
   to win and reset margin:0 + top:50% so the button overlays the right edge of the input.
   We do NOT set background: none so DNN's own clearText.png shows/hides via the dnnShow class. */
.class-search-field .searchInputContainer {
  position: relative;
}
.class-search-field .searchInputContainer a.dnnSearchBoxClearText {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 201; /* above cs-dropdown (z-index: 200) */
  width: 20px;
  height: 20px;
  margin: 0;
  cursor: pointer;
}
.class-search-field .searchInputContainer a.dnnSearchBoxClearText:hover { text-decoration: none; }

/*
   The "Search" button's missing magnifier.

   DNN's search skin object (admin/Skins/search.ascx) hardcodes CssClass="NormalTextBox"
   on its text box and applies whatever CssClass the skin passes to the OTHER three
   controls it renders — the two scope radio buttons and the `cmdSearch` LinkButton.
   So `CssClass="class-search-input"` from _header.ascx lands on the submit link, not
   on the input, and the link inherits the input rule's `padding-left: 48px` above.
   That 48px is the gutter the field's own SVG sits in — which is why the button shows
   an empty slot where an icon obviously belongs.

   Rather than claw the padding back and shift the button, fill the slot: same circle +
   handle path as .class-search-field__icon, same 18px, same --c-ink-subtle stroke, so
   the two icons in the header read as one set. `background-image` on its own (not the
   `background` shorthand) so the input rule's background-color survives.

   Two selectors because DNN's exact handling of CssClass on cmdSearch is compiled into
   DotNetNuke.dll and can't be read here: the class covers it if DNN replaces
   "SkinObject", the id-suffix selector covers it if DNN keeps "SkinObject" instead.
   Both match only the anchor — the text box is an <input>, so it can never match.
*/
.class-search-field a.class-search-input,
.class-search-field a[id$="cmdSearch"] {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a8294' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>");
  background-repeat: no-repeat;
  background-position: left 18px center;
  background-size: 18px 18px;
  /* Redundant when the input rule above is what put the gutter there, but the
     id-suffix selector has to stand on its own if it ever matches alone —
     otherwise the icon would sit on top of the word. */
  padding-left: 48px;
  text-decoration: none;
}
.class-search-field a.class-search-input:hover,
.class-search-field a[id$="cmdSearch"]:hover {
  border-color: var(--c-purple-light);
  text-decoration: none;
}

@media (max-width: 720px) {
  .class-search-toggle { display: inline-flex; }
  .class-header__search .class-search-field { display: none; }
  body.is-search-open .class-search-field {
    display: block;
    position: absolute;
    left: 0; right: 0; top: 100%;
    padding: var(--s-3) var(--s-5);
    background: var(--c-bg);
    border-bottom: 1px solid var(--c-line);
    z-index: 49;
    max-width: none;
  }
  body.is-search-open .class-search-toggle { background: var(--c-purple-tint); border-color: var(--c-purple-light); color: var(--c-purple-deep); }
}

/* Header CTAs — desktop-only action pills next to the burger.
   Hidden below 900px; accessible via burger overlay on mobile. */
.class-header__ctas {
  display: none;
  gap: var(--s-2);
  align-items: center;
  flex-shrink: 0;
}
@media (min-width: 900px) {
  .class-header__ctas { display: inline-flex; }
}
.class-header__cta {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: 10px 16px;
  border-radius: var(--r-pill);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-small);
  text-decoration: none;
  white-space: nowrap;
  transition: all var(--dur) var(--ease);
  border: 1.5px solid transparent;
}
.class-header__cta svg { width: 16px; height: 16px; }
.class-header__cta--primary {
  background: var(--c-purple-deep);
  color: #fff;
  box-shadow: 0 4px 12px rgba(123, 31, 162, 0.2);
}
.class-header__cta--primary:hover {
  background: var(--c-purple);
  color: #fff;
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: 0 6px 16px rgba(123, 31, 162, 0.28);
}
.class-header__cta--secondary {
  background: transparent;
  color: var(--c-purple-deep);
  border-color: var(--c-line-strong);
}
.class-header__cta--secondary:hover {
  background: var(--c-purple-mist);
  border-color: var(--c-purple-light);
  color: var(--c-purple-deep);
  text-decoration: none;
}

/* Burger */
.class-burger {
  position: relative;
  width: 48px; height: 48px;
  border-radius: var(--r-pill);
  background: var(--c-purple-deep);
  border: 1.5px solid var(--c-purple-deep);
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  cursor: pointer;
  flex-shrink: 0;
  transition: all var(--dur) var(--ease);
}
.class-burger:hover { background: var(--c-purple); border-color: var(--c-purple); }
.class-burger:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
.class-burger__bar {
  display: block;
  width: 18px; height: 2px;
  background: #fff;
  border-radius: var(--r-pill);
  transition: transform var(--dur) var(--ease), opacity var(--dur-fast) var(--ease);
}
@media (min-width: 721px) {
  .class-burger { width: 52px; height: 52px; }
  .class-burger__bar { width: 22px; }
}

/* ============ 6. OVERLAY ============ */

.class-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  background:
    radial-gradient(900px 600px at 80% 10%, rgba(186, 104, 200, 0.35), transparent 60%),
    radial-gradient(700px 500px at 10% 90%, rgba(123, 31, 162, 0.45), transparent 60%),
    linear-gradient(135deg, #1a0d2b 0%, #2a1042 40%, #110a1f 100%);
  color: #fff;
  opacity: 0;
  pointer-events: none;
  transform: translateY(-12px);
  transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease);
  display: flex;
  flex-direction: column;
  padding: var(--s-7) var(--s-5) var(--s-5);
  /* Clips the orbs below, the same way .class-hero clips its own. This box must NOT
     be the scroller: a clip is only invisible while the box doing it holds still, so
     clipping against a scrolling box cuts a hard line across the orbs at the initial
     viewport bottom the moment you scroll. Scrolling is on .class-overlay__scroll. */
  overflow: hidden;
}

body.is-overlay-open .class-overlay {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

/* The scrolling layer — everything the reader interacts with, so a long menu still
   scrolls on a short screen while the orbs stay pinned to the viewport behind it.
   overflow-x is pinned to hidden because setting only overflow-y would compute the
   other axis from visible to auto, and anything overflowing sideways would then put
   a horizontal scrollbar across the bottom of the window that reads as the page's. */
.class-overlay__scroll {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  min-height: 0;   /* a column flex item defaults to min-height:auto and won't scroll */
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
  overflow-y: auto;
}

/* Sized and offset to bleed past the overlay's edges — orb--1 alone hangs 80px off
   the right before classDrift translates it another 40px and scales it 6%. A
   transformed box contributes its transformed geometry to its scroll container's
   overflow, so while these sat inside the scrolling box they gave the menu a
   horizontal scrollbar whose thumb grew and shrank on the 18s animation loop, plus
   ~140px of phantom vertical scroll below the foot from orb--2's bottom:-100px.
   They are clipped by .class-overlay, which no longer scrolls. */
.class-overlay__orb {
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  opacity: 0.55;
  pointer-events: none;
  animation: classDrift 18s ease-in-out infinite;
}
.class-overlay__orb--1 { width: 520px; height: 520px; background: #ba68c8; top: -120px; right: -80px; animation-delay: 0s; }
.class-overlay__orb--2 { width: 420px; height: 420px; background: #7b1fa2; bottom: -100px; left: -60px; animation-delay: -6s; }
.class-overlay__orb--3 { width: 320px; height: 320px; background: #8e24aa; top: 35%; left: 45%; opacity: 0.35; animation-delay: -12s; }

@keyframes classDrift {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33%      { transform: translate(40px, -30px) scale(1.06); }
  66%      { transform: translate(-30px, 40px) scale(0.96); }
}

.class-overlay__close {
  position: absolute;
  top: var(--s-4); right: var(--s-5);
  width: 48px; height: 48px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.1);
  border: 1.5px solid rgba(255, 255, 255, 0.2);
  color: #fff;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: all var(--dur) var(--ease);
  z-index: 2;
}
.class-overlay__close:hover { background: rgba(255, 255, 255, 0.2); border-color: rgba(255, 255, 255, 0.4); }
.class-overlay__close:focus-visible { outline: none; box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.35); }

.class-overlay__nav { position: relative; flex: 1 1 auto; display: flex; align-items: center; justify-content: center; padding: var(--s-7) 0; z-index: 1; }
.class-overlay__list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--s-4); text-align: center; width: 100%; max-width: 560px; }
.class-overlay__item { margin: 0; }
/*
   ---- Overlay nav links: geometry and motion ----

   Colour is deliberately NOT set here — see the pin block below. Everything in
   this rule is layout, type and timing, all of which behave predictably.

   One gesture, one timing: --ease-out starts immediately and decelerates, and
   every animated property shares the same duration and curve so they move
   together.

   `will-change`/`backface-visibility` permanently promote the link to its own
   compositing layer. Without them the layer is created when the hover transform
   starts and destroyed when it ends, and that churn — not any colour rule — is
   one of the two things that can make the text shimmer pale for a frame at each
   end of the hover: the promoted layer is composited over three `filter: blur(80px)`
   orbs and a multi-stop gradient, and it can be presented for a frame before that
   backdrop has been recomposited behind it. The other candidate is the colour
   chain, handled by the pin below. Ten links is a trivial number of layers to keep
   alive.

   (The related antialiasing flip — subpixel on the document layer, greyscale on a
   composited one — cannot happen here: `body` already sets
   `-webkit-font-smoothing: antialiased` in section 2, so the whole page is
   greyscale-antialiased and promotion changes nothing.)
*/
.class-overlay__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(28px, 4vw, 44px);
  letter-spacing: -0.025em;
  text-decoration: none;
  padding: var(--s-2) var(--s-5);
  border-radius: var(--r-pill);
  background-color: transparent;
  border: 1.5px solid transparent;
  will-change: transform;
  backface-visibility: hidden;
  transition: color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}

/*
   ---- Overlay nav links: the colour pin ----

   Two rules, deliberately separated from the geometry above, and deliberately
   heavier than anything else that could touch these links.

   History: the menu resting colour was #fff with a purple-light hover, and the
   text flashed pale at both ends of the hover no matter how the easing or the
   duration were adjusted (three attempts). The overriding source was never
   identified from the stylesheets in this repo — nothing in skin.css, portal.css,
   DNN core or any module sheet targets .class-overlay__link a second time, and no
   JS touches colours. Rather than keep guessing, this pin is written so it does
   not need to know:

     · (0,3,1) / (0,4,1) plus !important — no realistic competitor reaches that,
       and every state of the link is marked so they still resolve against each
       other normally, by specificity, in the usual way.
     · :link and :visited are listed explicitly so an anchor cannot take a
       different colour depending on the visitor's history.
     · #fff appears at NEITHER endpoint any more. Even if some unseen rule were
       painting white, a colour transition can only interpolate between its own
       two endpoints — so a white frame is now structurally impossible rather
       than merely overridden.

   If you ever inspect the live page and find the real culprit, the !important
   flags here can go; the specificity alone will almost certainly still win.
*/
.class-overlay .class-overlay__list a.class-overlay__link,
.class-overlay .class-overlay__list a.class-overlay__link:link,
.class-overlay .class-overlay__list a.class-overlay__link:visited {
  color: var(--c-purple) !important;
}

/* Mouse and keyboard get the same state, so the menu behaves identically for both. */
.class-overlay .class-overlay__list a.class-overlay__link:hover,
.class-overlay .class-overlay__list a.class-overlay__link:focus-visible {
  color: var(--c-purple-light) !important;
  text-decoration: none;
  transform: translateY(-1px);
}

/*
   Current page. The marker is now carried entirely by the translucent pill and the
   heavier weight — the same idiom .class-overlay__sublink already uses — rather
   than by colour. That is on purpose: the colour pin above owns every link's text
   colour, and reintroducing #fff here would put a white endpoint back into the
   hover transition for exactly one item in the menu.
*/
.class-overlay__item.is-current > .class-overlay__link {
  font-weight: 700;
  background-color: rgba(255, 255, 255, 0.14);
  border-color: rgba(255, 255, 255, 0.28);
}

/*
   Hover on the current page's own link. Required: the rule above is (0,3,0) and
   outranks the plain :hover pill values, so without this the current item is the
   only entry in the menu whose pill ignores the cursor. Text colour comes from the
   pin (0,4,1), which outranks this (0,4,0).
*/
.class-overlay__item.is-current > .class-overlay__link:hover,
.class-overlay__item.is-current > .class-overlay__link:focus-visible {
  background-color: rgba(255, 255, 255, 0.22);
  border-color: rgba(255, 255, 255, 0.42);
  transform: translateY(-1px);
}
.class-overlay__sublist {
  list-style: none;
  padding: 0;
  margin: var(--s-2) 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  justify-content: center;
}
.class-overlay__sublink {
  font-family: var(--font-body);
  font-size: var(--t-small);
  text-decoration: none;
  padding: 4px 12px;
  border-radius: var(--r-pill);
  border: 1px solid rgba(255, 255, 255, 0.18);
  /* Same duration and curve as .class-overlay__link so the whole menu responds
     with one consistent gesture. Named properties rather than `all`, so the
     transition cannot accidentally pick up layout properties later. */
  transition: color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

/*
   Second-tier links take the SAME colour pair as the top level, pinned the same
   way and for the same reasons (see the top-level pin above). DNN decides whether
   a page lands in the top list or in a sublist, so pinning both tiers is what
   guarantees the admin entries read identically to the public ones wherever the
   page tree happens to put them.
*/
.class-overlay .class-overlay__sublist a.class-overlay__sublink,
.class-overlay .class-overlay__sublist a.class-overlay__sublink:link,
.class-overlay .class-overlay__sublist a.class-overlay__sublink:visited {
  color: var(--c-purple) !important;
}
.class-overlay .class-overlay__sublist a.class-overlay__sublink:hover,
.class-overlay .class-overlay__sublist a.class-overlay__sublink:focus-visible {
  color: var(--c-purple-light) !important;
  background-color: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.32);
}

/* The menu template marks the active child with .is-current on .class-overlay__subitem
   (see menus/header/RazorMenu.cshtml), but nothing styled it — so a second-tier page
   showed no active state whatsoever. Same pill idiom as the top level, scaled down,
   and like the top level it carries the marker without touching the text colour. */
.class-overlay__subitem.is-current > .class-overlay__sublink {
  font-weight: 600;
  background-color: rgba(255, 255, 255, 0.18);
  border-color: rgba(255, 255, 255, 0.38);
}

.class-overlay__ctas {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--s-3);
  padding: var(--s-4) 0;
  max-width: 360px;
  width: 100%;
  margin-inline: auto;
}
@media (min-width: 600px) { .class-overlay__ctas { flex-direction: row; max-width: 520px; } }

.class-overlay__foot {
  position: relative;
  z-index: 1;
  padding-top: var(--s-5);
  margin-top: var(--s-5);
  border-top: 1px solid rgba(255, 255, 255, 0.15);
  display: flex;
  gap: var(--s-4);
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  font-size: var(--t-small);
  color: rgba(255, 255, 255, 0.55);
}
.class-overlay__foot a { color: rgba(255, 255, 255, 0.75); text-decoration: none; transition: color var(--dur) var(--ease); }
.class-overlay__foot a:hover { color: #fff; }
.class-overlay__login, .class-overlay__user { font-size: var(--t-small); }

/* Burger turns into an X when overlay is open */
body.is-overlay-open .class-burger { background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.2); position: fixed; top: var(--s-3); right: var(--s-5); z-index: 65; }
body.is-overlay-open .class-burger__bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
body.is-overlay-open .class-burger__bar:nth-child(2) { opacity: 0; }
body.is-overlay-open .class-burger__bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ============ 7. BUTTONS ============ */

.class-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  font-family: var(--font-display);
  font-size: var(--t-body);
  font-weight: 600;
  line-height: 1;
  padding: 14px 24px;
  border-radius: var(--r-pill);
  border: 1.5px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: transform var(--dur-fast) var(--ease), background var(--dur) var(--ease), color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
  -webkit-tap-highlight-color: transparent;
  white-space: nowrap;
}
.class-btn:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
.class-btn:active { transform: translateY(1px); }

.class-btn--primary { background: var(--c-purple-deep); color: #fff; box-shadow: var(--shadow-md); }
.class-btn--primary:hover { background: var(--c-purple); color: #fff; box-shadow: var(--shadow-lg); text-decoration: none; }

.class-btn--secondary { background: var(--c-purple-tint); color: var(--c-purple-deep); }
.class-btn--secondary:hover { background: var(--c-purple-light); color: #fff; text-decoration: none; }

.class-btn--ghost { background: transparent; color: var(--c-purple-deep); border-color: var(--c-line-strong); }
.class-btn--ghost:hover { background: var(--c-purple-mist); border-color: var(--c-purple-light); text-decoration: none; }

.class-btn--invert { background: #fff; color: var(--c-purple-deep); }
.class-btn--invert:hover { background: var(--c-purple-tint); color: var(--c-purple-deep); text-decoration: none; }

.class-btn--ghost-light { background: transparent; color: #fff; border-color: rgba(255, 255, 255, 0.3); }
.class-btn--ghost-light:hover { background: rgba(255, 255, 255, 0.1); border-color: rgba(255, 255, 255, 0.6); color: #fff; text-decoration: none; }

.class-btn--sm { padding: 10px 18px; font-size: var(--t-small); }
.class-btn--lg { padding: 18px 32px; font-size: var(--t-lead); }
.class-btn--block { display: flex; width: 100%; }

/* ============ 8. FORMS ============ */

label {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-small);
  color: var(--c-ink);
  margin-bottom: var(--s-2);
}
input[type="text"], input[type="email"], input[type="tel"], input[type="search"],
input[type="password"], input[type="number"], input[type="url"], input[type="date"],
select, textarea {
  width: 100%;
  font-family: var(--font-body);
  font-size: var(--t-body);
  color: var(--c-ink);
  background: var(--c-bg);
  padding: 14px var(--s-4);
  border: 1.5px solid var(--c-line-strong);
  border-radius: var(--r-md);
  line-height: 1.4;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
  -webkit-appearance: none; appearance: none;
}
input::placeholder, textarea::placeholder { color: var(--c-ink-subtle); }
input:hover, select:hover, textarea:hover { border-color: var(--c-purple-light); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--c-purple);
  box-shadow: var(--shadow-focus);
}
textarea { min-height: 120px; resize: vertical; }
select {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235a4f66' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 16px center;
  background-size: 16px;
  padding-right: 44px;
}

/* ============ 9. BADGES & ACCENT BOXES ============ */

.class-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-radius: var(--r-pill);
  font-family: var(--font-display);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background: var(--c-purple-tint);
  color: var(--c-purple-deep);
  white-space: nowrap;
}
.class-badge::before { content: ""; width: 6px; height: 6px; border-radius: var(--r-pill); background: currentColor; }
.class-badge--practitioner { background: var(--c-teal-soft);   color: var(--c-teal-deep); }
.class-badge--leader       { background: var(--c-amber-soft);  color: var(--c-amber-deep); }
.class-badge--manager      { background: var(--c-purple-tint); color: var(--c-purple-deep); }
.class-badge--bank         { background: var(--c-pink-soft);   color: var(--c-pink-deep); }
.class-badge--apprentice   { background: var(--c-green-soft);  color: var(--c-green-deep); }
.class-badge--urgent       { background: var(--c-coral-soft);  color: var(--c-coral-deep); }

/* Tinted callout cards */
.class-tint-card {
  padding: var(--s-5);
  border-radius: var(--r-lg);
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}
.class-tint-card--purple { background: var(--c-purple-tint); color: var(--c-purple-deep); }
.class-tint-card--teal   { background: var(--c-teal-soft);   color: var(--c-teal-deep); }
.class-tint-card--pink   { background: var(--c-pink-soft);   color: var(--c-pink-deep); }
.class-tint-card--amber  { background: var(--c-amber-soft);  color: var(--c-amber-deep); }
.class-tint-card--green  { background: var(--c-green-soft);  color: var(--c-green-deep); }
.class-tint-card--coral  { background: var(--c-coral-soft);  color: var(--c-coral-deep); }

/* Accent-bordered feature boxes */
.class-feature {
  padding: var(--s-5);
  background: var(--c-bg-soft);
  border-radius: var(--r-lg);
  border-left: 4px solid var(--c-purple-deep);
}
.class-feature--purple { border-color: var(--c-purple-deep); }
.class-feature--teal   { border-color: var(--c-teal); }
.class-feature--pink   { border-color: var(--c-pink); }
.class-feature--amber  { border-color: var(--c-amber); }
.class-feature--green  { border-color: var(--c-green); }
.class-feature--coral  { border-color: var(--c-coral); }
.class-feature__icon {
  width: 48px; height: 48px;
  border-radius: var(--r-md);
  background: var(--c-purple-tint);
  color: var(--c-purple-deep);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: var(--s-4);
}
.class-feature--teal .class-feature__icon  { background: var(--c-teal-soft);  color: var(--c-teal-deep); }
.class-feature--pink .class-feature__icon  { background: var(--c-pink-soft);  color: var(--c-pink-deep); }
.class-feature--amber .class-feature__icon { background: var(--c-amber-soft); color: var(--c-amber-deep); }
.class-feature--green .class-feature__icon { background: var(--c-green-soft); color: var(--c-green-deep); }
.class-feature--coral .class-feature__icon { background: var(--c-coral-soft); color: var(--c-coral-deep); }

/* Notices */
.class-notice {
  padding: 14px 18px;
  border-radius: var(--r-md);
  display: flex;
  gap: var(--s-3);
  align-items: flex-start;
  font-size: var(--t-small);
  line-height: 1.5;
}
.class-notice strong { font-weight: 600; }
.class-notice--info    { background: var(--c-teal-soft);  color: var(--c-teal-deep); }
.class-notice--success { background: var(--c-green-soft); color: var(--c-green-deep); }
.class-notice--warn    { background: var(--c-amber-soft); color: var(--c-amber-deep); }
.class-notice--error   { background: var(--c-red-soft);   color: var(--c-red-deep); }
.class-notice--brand   { background: var(--c-purple-tint); color: var(--c-purple-deep); }

/* ============ 10. FOOTER ============ */

.class-footer {
  margin-top: 0;
  color: rgba(255, 255, 255, 0.85);
  background:
    radial-gradient(700px 400px at 80% -10%, rgba(186,104,200,0.25), transparent 65%),
    linear-gradient(135deg, #7b1fa2 0%, #4a0e69 100%);
}
.class-footer__inner {
  display: grid;
  grid-template-columns: 1.3fr 3fr;
  gap: var(--s-6);
  padding-block: var(--s-6) var(--s-5);
}
@media (max-width: 900px) {
  .class-footer__inner { grid-template-columns: 1fr; gap: var(--s-6); }
}
.class-footer__brand { display: flex; flex-direction: column; gap: var(--s-3); }
.class-footer__logo img, .class-footer__logo svg {
  height: 40px;
  width: auto;
  filter: brightness(0) invert(1);
}
.class-footer__tag {
  font-size: var(--t-small);
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.78);
  max-width: 36ch;
  margin: 0;
}
.class-footer__social {
  list-style: none;
  padding: 0;
  margin: var(--s-1) 0 0;
  display: flex;
  gap: var(--s-2);
}
.class-footer__social a {
  width: 32px; height: 32px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.08);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  text-decoration: none;
  transition: all var(--dur) var(--ease);
}
.class-footer__social a:hover { background: rgba(255, 255, 255, 0.18); transform: translateY(-1px); }
.class-footer__social a:focus-visible { outline: none; box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.35); }

/* Footer four-column nav (Razor template) */
.class-footer__nav { width: 100%; }
.class-footer__columns {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  column-gap: var(--s-4);
  row-gap: var(--s-4);
}
@media (max-width: 900px) { .class-footer__columns { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 540px) { .class-footer__columns { grid-template-columns: 1fr; } }
.class-footer__col { display: flex; flex-direction: column; gap: var(--s-1); }
.class-footer__col-head {
  font-family: var(--font-display);
  font-size: var(--t-small);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: #fff;
  margin: 0 0 var(--s-2);
}
.class-footer__col-head a { color: #fff; text-decoration: none; }
.class-footer__col-head a:hover { color: var(--c-purple-light); text-decoration: none; }
.class-footer__col-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
}
.class-footer__col-list a {
  font-size: var(--t-small);
  color: rgba(255, 255, 255, 0.75);
  text-decoration: none;
  transition: color var(--dur) var(--ease);
}
.class-footer__col-list a:hover { color: #fff; text-decoration: none; }
.class-footer__col-list li { margin: 0; }

/* Footer base strip */
.class-footer__base {
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  padding-block: var(--s-3);
}
.class-footer__base-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  flex-wrap: wrap;
  font-size: var(--t-micro);
  color: rgba(255, 255, 255, 0.55);
}
.class-footer__copy { color: rgba(255, 255, 255, 0.55); }
.class-footer__copy a { color: rgba(255, 255, 255, 0.7); text-decoration: none; }
.class-footer__legal {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  gap: var(--s-3);
  flex-wrap: wrap;
}
.class-footer__legal a {
  font-size: var(--t-micro);
  color: rgba(255, 255, 255, 0.7);
  text-decoration: none;
  transition: color var(--dur) var(--ease);
}
.class-footer__legal a:hover { color: #fff; }

/* ============ 11. DNN PANES / EDIT MODE ============ */
/* Soft styling for empty edit-mode panes so they don't break the visual flow */
.class-pane:empty { display: none; }
.DnnModule { margin-bottom: var(--s-5); }
.DnnModule:last-child { margin-bottom: 0; }
.DnnLeftPane, .DnnRightPane, .DnnContentPane { padding: 0; }

/* Module title (when set to be visible) */
.DnnModule .DnnContainer h2.Head,
.DnnModule .DnnContainer h2.Title { font-size: var(--t-h3); margin-bottom: var(--s-4); }

/* ============ 12. MODULE HOOKS — JobAdmin / Registration / FAQ ============ */
/*
  The three custom modules each ship their own Module.css under
  ~/DesktopModules/{Module}/css/. The skin's job is to set the brand
  base so anything those CSS files don't explicitly style inherits
  sensible brand values. The selectors below give the modules a
  light skin-level pass for buttons, inputs and cards.
*/

/* --- JobAdmin --- */
.jobadmin .ja-input, .jobadmin .ja-select { border-radius: var(--r-md); }

/* `:not(.ja-admin)` excludes the JobAdmin ADMIN screens deliberately — do not drop it.
   This hook is a brand *fallback* for markup Module.css doesn't style. On the admin
   screens Module.css DOES style .ja-btn (the 2026-08-24 admin brand pass: ghost purple
   secondary, filled primary), and because the skin loads at Priority 500 — after the
   module CSS at Priority 10 — at an identical (0,2,0) specificity this rule silently
   won the rest state while Module.css's `.ja-admin .ja-btn:hover` at (0,3,0) still won
   the hover colour. Net effect: white-on-deep-purple at rest flipping to
   purple-on-purple (unreadable) on hover, and Save/Cancel rendering identically.
   `:not(.ja-admin)` adds no specificity of its own beyond its argument, so this stays
   at (0,2,0) and the PUBLIC job pages (.jobadmin-summary, .jobadmin-public,
   .ja-alert-signup, .ja-unsub, .jobadmin-featured — none of which carry .ja-admin)
   render exactly as before. */
.jobadmin:not(.ja-admin) .ja-btn {
  background: var(--c-purple-deep); color: #fff;
  border: 0; padding: 12px 22px; border-radius: var(--r-pill);
  font-family: var(--font-display); font-weight: 600; cursor: pointer;
  transition: background var(--dur) var(--ease);
}
/* `color` is restated here on purpose: without it the hover state leaves the label
   colour to whatever else wins the cascade, which is precisely how the admin buttons
   ended up with purple text on a purple fill. */
.jobadmin:not(.ja-admin) .ja-btn:hover { background: var(--c-purple); color: #fff; }
.jobadmin .ja-link { color: var(--c-purple-deep); }
.jobadmin .ja-card {
  display: flex; flex-direction: column; gap: var(--s-3);
  padding: var(--s-5); background: var(--c-bg);
  border: 1px solid var(--c-line); border-radius: var(--r-lg);
  text-decoration: none; color: inherit;
  transition: all var(--dur) var(--ease);
}
.jobadmin .ja-card:hover { border-color: var(--c-purple-light); box-shadow: var(--shadow-md); transform: translateY(-2px); text-decoration: none; }
.jobadmin .ja-card__title { font-family: var(--font-display); font-weight: 700; font-size: var(--t-h4); color: var(--c-ink-strong); }
.jobadmin .ja-card__meta { font-size: var(--t-small); color: var(--c-ink-muted); }
.jobadmin .ja-card__cta { font-family: var(--font-display); font-weight: 600; color: var(--c-purple-deep); }
.jobadmin .ja-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--s-4); }
.jobadmin .ja-badges { display: flex; flex-wrap: wrap; gap: 6px; }

/* Job badge variants — soft accent tints from the brand palette so each pill
   type is visually distinct at a glance. Same soft-tint + deep-text pairing
   as the rest of the accent system in the moodboard. Module.css defines
   empty placeholders for these classes; the skin fills them in.

   Sector   → brand purple (category — the most important meta)
   Contract → amber          (permanent / temporary / bank etc.)
   Location → teal           (geographic, calm)
   Salary   → green          (money / growth)                                  */

.jobadmin .ja-badge {
  border: 1px solid transparent;
  font-family: var(--font-body);
  font-weight: 500;
  letter-spacing: 0;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}

.jobadmin .ja-badge--sector   { background: var(--c-purple-tint); color: var(--c-purple-deep); }
.jobadmin .ja-badge--contract { background: var(--c-amber-soft);  color: var(--c-amber-deep); }
.jobadmin .ja-badge--location { background: var(--c-teal-soft);   color: var(--c-teal-deep); }
.jobadmin .ja-badge--salary   { background: var(--c-green-soft);  color: var(--c-green-deep); }

/* Subtle lift on card hover — pills intensify a touch so the card feels alive */
.jobadmin .ja-card:hover .ja-badge--sector   { background: #ecd6f3; }
.jobadmin .ja-card:hover .ja-badge--contract { background: #ffe1b3; }
.jobadmin .ja-card:hover .ja-badge--location { background: #c4ebef; }
.jobadmin .ja-card:hover .ja-badge--salary   { background: #cae5cc; }

/* JobDetails (.cr-*) */
.jobadmin-public .cr-job { display: grid; grid-template-columns: 1fr; gap: var(--s-6); }
.jobadmin-public .cr-job-hero { display: grid; grid-template-columns: 2fr 1fr; gap: var(--s-6); align-items: start; }
@media (max-width: 900px) { .jobadmin-public .cr-job-hero { grid-template-columns: 1fr; } }
.jobadmin-public .cr-job-title { font-family: var(--font-display); font-size: var(--t-h1); line-height: 1.1; color: var(--c-ink-strong); margin: 0 0 var(--s-4); }
.jobadmin-public .cr-job-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: var(--s-3); }
.jobadmin-public .cr-chip { display: inline-flex; align-items: center; padding: 4px 12px; border-radius: var(--r-pill); background: var(--c-bg-tint); font-size: var(--t-small); color: var(--c-ink-muted); }
.jobadmin-public .cr-chip--qualification { background: var(--c-teal-soft); color: var(--c-teal-deep); }
.jobadmin-public .cr-job-salary { font-family: var(--font-display); font-weight: 700; font-size: var(--t-h3); color: var(--c-purple-deep); margin: var(--s-3) 0; }
.jobadmin-public .cr-card { background: var(--c-bg); border: 1px solid var(--c-line); border-radius: var(--r-lg); padding: var(--s-5); margin-bottom: var(--s-5); }
.jobadmin-public .cr-card--sticky { position: sticky; top: calc(var(--header-h) + var(--s-4)); }
.jobadmin-public .cr-h2 { font-size: var(--t-h3); margin: 0 0 var(--s-3); }
.jobadmin-public .cr-h3 { font-size: var(--t-h4); margin: var(--s-4) 0 var(--s-2); }
.jobadmin-public .cr-field { margin-bottom: var(--s-4); }
.jobadmin-public .cr-label { font-family: var(--font-display); font-weight: 600; font-size: var(--t-small); display: block; margin-bottom: var(--s-2); }
.jobadmin-public .cr-input { width: 100%; padding: 12px var(--s-4); border: 1.5px solid var(--c-line-strong); border-radius: var(--r-md); font-size: var(--t-body); }
.jobadmin-public .cr-check { display: inline-flex; align-items: center; gap: var(--s-2); cursor: pointer; font-size: var(--t-small); }
.jobadmin-public .cr-btn { padding: 14px 24px; border-radius: var(--r-pill); border: 0; font-family: var(--font-display); font-weight: 600; cursor: pointer; background: var(--c-bg-tint); color: var(--c-purple-deep); }
.jobadmin-public .cr-btn--primary { background: var(--c-purple-deep); color: #fff; }
.jobadmin-public .cr-btn--primary:hover { background: var(--c-purple); }
.jobadmin-public .cr-muted { color: var(--c-ink-muted); font-size: var(--t-small); }
.jobadmin-public .cr-hr { border: 0; border-top: 1px solid var(--c-line); margin: var(--s-5) 0; }
.jobadmin-public .cr-contact { display: flex; gap: var(--s-3); align-items: center; }
.jobadmin-public .cr-contact__photo { width: 56px; height: 56px; border-radius: var(--r-pill); object-fit: cover; }
.jobadmin-public .cr-back-link { display: inline-flex; gap: 6px; font-size: var(--t-small); color: var(--c-ink-muted); margin-bottom: var(--s-3); text-decoration: none; }
.jobadmin-public .cr-back-link:hover { color: var(--c-purple-deep); }

/* JobAdmin pager */
.jobadmin .ja-pager { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: var(--s-3); margin-top: var(--s-5); padding-top: var(--s-4); border-top: 1px solid var(--c-line); }
.jobadmin .ja-pager__summary { font-size: var(--t-small); color: var(--c-ink-muted); }
.jobadmin .ja-pager__links a { padding: 6px 12px; border-radius: var(--r-sm); color: var(--c-purple-deep); text-decoration: none; }
.jobadmin .ja-pager__links a:hover { background: var(--c-purple-tint); }

/* --- Registration --- */
.registration-wizard { background: var(--c-bg); }
.registration-page { padding-block: var(--s-5); }
.registration-progress { margin-bottom: var(--s-5); }
.registration-step-label { font-family: var(--font-display); font-size: var(--t-small); color: var(--c-ink-muted); display: block; margin-bottom: var(--s-2); }
.registration-progress-bar { height: 6px; background: var(--c-bg-tint); border-radius: var(--r-pill); overflow: hidden; }
.registration-progress-fill { height: 100%; background: linear-gradient(90deg, var(--c-purple-deep), var(--c-purple-light)); border-radius: var(--r-pill); transition: width var(--dur-slow) var(--ease); }

.registration-section-title { font-size: var(--t-h3); margin: var(--s-5) 0 var(--s-3); }
.registration-intro { padding: var(--s-4); background: var(--c-bg-soft); border-radius: var(--r-md); font-size: var(--t-small); margin-bottom: var(--s-5); }
.registration-notice { background: var(--c-amber-soft); color: var(--c-amber-deep); padding: var(--s-3) var(--s-4); border-radius: var(--r-md); }

.registration-field { margin-bottom: var(--s-4); }
.registration-field label { font-family: var(--font-display); font-weight: 600; font-size: var(--t-small); margin-bottom: var(--s-2); display: block; }
.req { color: var(--c-error); font-weight: 700; }
.registration-input, .registration-input-short, .registration-input-date { width: 100%; padding: 12px var(--s-4); border: 1.5px solid var(--c-line-strong); border-radius: var(--r-md); font-size: var(--t-body); transition: border-color var(--dur) var(--ease); }
.registration-input:focus { outline: none; border-color: var(--c-purple); box-shadow: var(--shadow-focus); }
.registration-input-short { max-width: 240px; }
.registration-input-date { max-width: 200px; }
.registration-readonly { padding: 10px var(--s-4); background: var(--c-bg-soft); border-radius: var(--r-md); display: inline-block; }
.registration-radio { display: flex; gap: var(--s-4); }
.registration-radio label { font-family: var(--font-body); font-weight: 400; cursor: pointer; }
.registration-conditional { background: var(--c-purple-mist); border-left: 3px solid var(--c-purple-light); padding: var(--s-4); border-radius: 0 var(--r-md) var(--r-md) 0; margin-bottom: var(--s-4); }
.registration-question-block { padding-bottom: var(--s-4); margin-bottom: var(--s-4); border-bottom: 1px dashed var(--c-line); }
.registration-question-block:last-child { border-bottom: 0; }
.registration-declaration-text { font-size: var(--t-small); line-height: 1.7; color: var(--c-ink-muted); }
.registration-errors { background: var(--c-red-soft); color: var(--c-red-deep); padding: var(--s-4); border-radius: var(--r-md); margin-bottom: var(--s-4); }
.registration-success-panel { background: var(--c-green-soft); color: var(--c-green-deep); padding: var(--s-5); border-radius: var(--r-md); margin-bottom: var(--s-4); }
.registration-access-panel { background: var(--c-amber-soft); color: var(--c-amber-deep); padding: var(--s-5); border-radius: var(--r-md); margin-bottom: var(--s-4); }
.registration-grid { width: 100%; border-collapse: collapse; font-size: var(--t-small); }
.registration-grid th, .registration-grid td { padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--c-line); text-align: left; }
.registration-subform { background: var(--c-bg-soft); padding: var(--s-5); border-radius: var(--r-md); margin: var(--s-4) 0; }
.registration-subform-actions { display: flex; gap: var(--s-2); margin-top: var(--s-3); }
.registration-nav { display: flex; gap: var(--s-3); justify-content: space-between; padding-top: var(--s-5); border-top: 1px solid var(--c-line); margin-top: var(--s-5); }
.registration-btn, .registration-btn-submit { background: var(--c-purple-deep); color: #fff; padding: 14px 24px; border-radius: var(--r-pill); border: 0; font-family: var(--font-display); font-weight: 600; cursor: pointer; }
.registration-btn:hover { background: var(--c-purple); }
.registration-btn-secondary { background: var(--c-purple-tint); color: var(--c-purple-deep); padding: 14px 24px; border-radius: var(--r-pill); border: 0; font-family: var(--font-display); font-weight: 600; cursor: pointer; }
.registration-btn-link, .registration-btn-link-edit { background: transparent; color: var(--c-purple-deep); border: 0; padding: 6px 10px; cursor: pointer; font-family: var(--font-display); font-weight: 600; }
.registration-btn-link:hover, .registration-btn-link-edit:hover { text-decoration: underline; }

/* --- FAQ --- */

/* Filter bar */
.faq-display .faq-filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  align-items: center;
  padding: var(--s-3) var(--s-4);
  background: var(--c-purple-mist);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  margin-bottom: var(--s-5);
}
.faq-display .faq-filter-bar label { margin: 0; font-size: var(--t-small); font-weight: 600; color: var(--c-ink-muted); }
.faq-display .faq-filter-search,
.faq-display .faq-filter-select {
  padding: 10px var(--s-3);
  border: 1.5px solid var(--c-line-strong);
  border-radius: var(--r-pill);
  background: var(--c-bg);
  font-size: var(--t-small);
  min-width: 200px;
}
.faq-display .faq-filter-search:focus,
.faq-display .faq-filter-select:focus { outline: none; border-color: var(--c-purple); box-shadow: var(--shadow-focus); }
.faq-display .faq-btn {
  padding: 10px 18px;
  border-radius: var(--r-pill);
  background: var(--c-bg);
  border: 1.5px solid var(--c-line-strong);
  cursor: pointer;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-small);
  color: var(--c-ink);
  transition: all var(--dur) var(--ease);
}
.faq-display .faq-btn:hover { border-color: var(--c-purple-light); color: var(--c-purple-deep); }
.faq-display .faq-btn--primary { background: var(--c-purple-deep); color: #fff; border-color: var(--c-purple-deep); }
.faq-display .faq-btn--primary:hover { background: var(--c-purple); border-color: var(--c-purple); color: #fff; }

/* Category */
.faq-display .faq-category { margin-bottom: var(--s-6); }
.faq-display .faq-category-title {
  font-family: var(--font-display);
  font-size: var(--t-h3);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--c-ink-strong);
  padding-bottom: var(--s-2);
  border-bottom: 1px solid var(--c-line);
  margin: 0 0 var(--s-4);
}

/* List + items — explicit overrides so the base dl rules don't grid the items */
.faq-display .faq-list {
  display: block;
  grid-template-columns: none;
  gap: 0;
  margin: 0;
  padding: 0;
}
.faq-display .faq-item {
  display: block;
  background: var(--c-bg);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  margin-bottom: var(--s-2);
  overflow: hidden;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.faq-display .faq-item:hover { border-color: var(--c-purple-light); }
.faq-display .faq-item.is-open {
  border-color: var(--c-purple);
  box-shadow: var(--shadow-sm);
}

/* Question */
.faq-display .faq-question {
  display: block;
  font-family: var(--font-display);
  font-size: var(--t-body);
  font-weight: 600;
  color: var(--c-ink-strong);
  background: transparent;
  margin: 0;
  padding: var(--s-4) var(--s-7) var(--s-4) var(--s-5);
  cursor: pointer;
  user-select: none;
  position: relative;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
}
/* Override the FAQ Module's "+ " before-pseudo so our chevron is the sole indicator */
.faq-display .faq-question::before { content: none !important; }
.faq-display .faq-question::after {
  content: "";
  position: absolute;
  right: var(--s-5); top: 50%;
  width: 10px; height: 10px;
  border-right: 2px solid var(--c-purple-deep);
  border-bottom: 2px solid var(--c-purple-deep);
  transform: translateY(-70%) rotate(45deg);
  transition: transform var(--dur) var(--ease);
}
.faq-display .faq-item.is-open .faq-question::after {
  transform: translateY(-30%) rotate(-135deg);
}
.faq-display .faq-question:hover {
  background: var(--c-purple-mist);
  color: var(--c-purple-deep);
}
.faq-display .faq-item.is-open .faq-question {
  background: var(--c-purple-mist);
  color: var(--c-purple-deep);
}

/* Answer */
.faq-display .faq-answer {
  display: block;
  height: 0;
  overflow: hidden;
  margin: 0;
  background: var(--c-bg);
}
.faq-display .faq-answer-inner {
  display: block;
  padding: var(--s-2) var(--s-5) var(--s-4);
  font-size: var(--t-body);
  line-height: var(--lh-normal);
  color: var(--c-ink-muted);
}

/* Empty state */
.faq-display .faq-empty {
  padding: var(--s-5);
  background: var(--c-bg-soft);
  border-radius: var(--r-md);
  text-align: center;
  color: var(--c-ink-muted);
  font-style: italic;
}

/* ============ 13. PAGE LAYOUT UTILITIES ============ */
/*
   Reusable primitives for building content pages. Every content page —
   Home, Client, Candidate, Contact, Team — composes from these.

   .class-section        — padded page section (spacing + optional background)
   .class-fullbleed      — break out of container to viewport edges
   .class-container--sm  — narrow (720px) container for text-forward content
   .class-container--lg  — wide (1400px) container for image-heavy layouts
   .class-grid           — responsive card grid (2/3/4 column)
   .class-media          — image + text side by side
   .class-hero           — reusable hero pattern (gradient + text + CTAs)
   .class-panel          — reusable card panel with brand background variants
*/

/* Section wrapper — the workhorse for stacking content on any page */
.class-section {
  padding-block: var(--s-8);
  position: relative;
}
.class-section--sm { padding-block: var(--s-6); }
.class-section--md { padding-block: var(--s-7); }
.class-section--lg { padding-block: var(--s-9); }
.class-section--xl { padding-block: var(--s-10); }
.class-section--flush { padding-block: 0; }

/* Section background variants — from the moodboard rhythm system */
.class-section--soft   { background: var(--c-bg-soft); }
.class-section--mist   { background: var(--c-purple-mist); }
.class-section--tint   { background: var(--c-purple-tint); }
.class-section--brand  {
  color: #fff;
  background:
    radial-gradient(700px 400px at 20% 20%, rgba(186,104,200,0.25), transparent 60%),
    radial-gradient(600px 350px at 90% 80%, rgba(214,22,113,0.15), transparent 60%),
    linear-gradient(135deg, #7b1fa2 0%, #4a0e69 100%);
}
.class-section--brand h1, .class-section--brand h2, .class-section--brand h3,
.class-section--brand h4, .class-section--brand h5 { color: #fff; }
.class-section--brand p, .class-section--brand .lead { color: rgba(255, 255, 255, 0.85); }
.class-section--dark {
  color: #fff;
  background: linear-gradient(135deg, #1a0d2b 0%, #2a1042 100%);
}
.class-section--dark h1, .class-section--dark h2, .class-section--dark h3 { color: #fff; }
.class-section--dark p, .class-section--dark .lead { color: rgba(255, 255, 255, 0.8); }

/* Full-bleed — for use INSIDE a constrained container (ContentPane).
   Breaks the element out to the viewport width, then internal .class-container
   re-constrains its children to the design width. This is THE utility that
   lets an entire page composition sit inside a single ContentPane and still
   have full-bleed hero and CTA bands. */
.class-fullbleed {
  width: 100vw;
  max-width: 100vw;
  margin-inline: calc(50% - 50vw);
  /* When the viewport has a scrollbar, 100vw includes it — avoid H-scroll: */
  padding-right: 0;
}

/* Container variants */
.class-container--sm { max-width: 720px; }
.class-container--lg { max-width: 1400px; }
.class-container--reading { max-width: 640px; }  /* max ~66 characters per line */

/* Section headers — the eyebrow + h2 + lead pattern that opens most sections */
.class-section-head {
  max-width: 720px;
  margin: 0 auto var(--s-6);
  text-align: center;
}
.class-section-head--left { margin-left: 0; text-align: left; }
.class-section-head h2 { margin: var(--s-2) 0 var(--s-3); }
.class-section-head .lead { color: var(--c-ink-muted); margin: 0; }

/* Responsive card grids — the go-to for stacking cards, benefits, features */
.class-grid { display: grid; gap: var(--s-4); grid-template-columns: 1fr; }
.class-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.class-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.class-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.class-grid--auto {
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.class-grid--gap-sm { gap: var(--s-3); }
.class-grid--gap-lg { gap: var(--s-6); }

@media (max-width: 900px) {
  .class-grid--3, .class-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 600px) {
  .class-grid--2, .class-grid--3, .class-grid--4 { grid-template-columns: 1fr; }
}

/* Media object — image left, text right (or reverse). For Client/Candidate
   propositions paired with imagery, About sections, testimonial highlights. */
.class-media {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-6);
  align-items: center;
}
@media (min-width: 720px) {
  .class-media { grid-template-columns: 1fr 1fr; }
  .class-media--reverse .class-media__figure { order: 2; }
  .class-media--narrow-figure { grid-template-columns: 5fr 7fr; }
  .class-media--wide-figure   { grid-template-columns: 7fr 5fr; }
}
.class-media__figure {
  margin: 0;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--c-bg-soft);
  aspect-ratio: 4 / 3;
}
.class-media__figure img,
.class-media__figure svg { width: 100%; height: 100%; object-fit: cover; display: block; }
.class-media__body h2, .class-media__body h3 { margin-top: 0; }

/* Hero pattern — reusable across all content pages */
.class-hero {
  position: relative;
  overflow: hidden;
  padding: var(--s-9) 0 var(--s-8);
  color: #fff;
  background:
    radial-gradient(1000px 600px at 80% 10%, rgba(186,104,200,0.35), transparent 60%),
    radial-gradient(800px 500px at 10% 90%, rgba(123,31,162,0.45), transparent 60%),
    linear-gradient(135deg, #1a0d2b 0%, #4a0e69 45%, #7b1fa2 100%);
}
.class-hero__inner { position: relative; z-index: 2; }
.class-hero__eyebrow {
  display: inline-block;
  font-family: var(--font-display);
  font-size: var(--t-micro);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: rgba(255, 255, 255, 0.75);
  margin-bottom: var(--s-4);
}
.class-hero__title {
  font-family: var(--font-display);
  font-size: clamp(40px, 5.5vw, 72px);
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 1.02;
  margin: 0 0 var(--s-5);
  background: linear-gradient(135deg, #ffffff 0%, #ba68c8 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.class-hero__lead {
  font-size: var(--t-lead);
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.85);
  max-width: 58ch;
  margin: 0 0 var(--s-6);
}

/* Italic accent word inside a hero title, with a hand-drawn squiggle
   underline. Use like:
     <h1 class="class-hero__title">Nursery jobs, <span class="class-hero__title-accent">done right<svg class="class-hero__title-squiggle" ...>...</svg></span>.</h1>
*/
.class-hero__title-accent {
  display: inline-block;
  position: relative;
  font-style: italic;
  font-weight: 500;
}
.class-hero__title-squiggle {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.14em;
  width: 100%;
  height: 0.24em;
  color: #ba68c8;
  overflow: visible;
}

.class-hero__ctas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
}

/*
   Hero CTAs are always on a dark ground — .class-hero is a purple gradient, and the
   home hero additionally sits on a photo behind that gradient (see the .home-hero
   rule in Portals/0/portal.css). The buttons themselves come from the page's HTML
   module content, which lives in DNN's HtmlText table rather than in this repo, so
   which .class-btn--* variant any given hero uses cannot be checked here — and at
   least one of them is using a light-background variant, which is how "Hire staff"
   ended up purple-on-purple and unreadable.

   So rather than name a variant: every hero CTA gets white text, and the two
   light-background variants are additionally re-cast as their dark-background
   sibling (.class-btn--ghost-light) so their borders and hover fills match.

   .class-btn--invert is the one deliberate exception. It is a solid white pill, its
   purple text is correct and readable on it, and it is almost certainly what the
   working "Find work" button uses — forcing white text onto it would make it
   invisible. :not() takes the specificity of its argument, so these are (0,3,1).
*/
.class-hero__ctas a.class-btn:not(.class-btn--invert),
.class-hero__ctas a.class-btn:not(.class-btn--invert):link,
.class-hero__ctas a.class-btn:not(.class-btn--invert):visited,
.class-hero__ctas a.class-btn:not(.class-btn--invert):hover,
.class-hero__ctas a.class-btn:not(.class-btn--invert):focus {
  color: #fff !important;
  text-decoration: none;
}
.class-hero__ctas a.class-btn--ghost,
.class-hero__ctas a.class-btn--secondary {
  background: transparent;
  border-color: rgba(255, 255, 255, 0.3);
}
.class-hero__ctas a.class-btn--ghost:hover,
.class-hero__ctas a.class-btn--secondary:hover {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.6);
}

/* Embedded search bar for hero — glassy pill, icon + input + button on one row */
.class-hero__search {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 6px 6px 6px 20px;
  background: rgba(255, 255, 255, 0.12);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1.5px solid rgba(255, 255, 255, 0.22);
  border-radius: var(--r-pill);
  max-width: 560px;
  margin: 0 0 var(--s-6);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.class-hero__search:focus-within {
  background: rgba(255, 255, 255, 0.18);
  border-color: rgba(255, 255, 255, 0.5);
  box-shadow: 0 0 0 4px rgba(186, 104, 200, 0.35);
}
/*
   Force any <label> inside the hero search to be visually hidden while
   remaining accessible to screen readers. Scoped selector (specificity 0,2,1)
   beats the generic `label { display: block; ... }` rule that was leaving
   the "Search jobs" label visible inside the pill.
*/
.class-hero__search > label,
.class-hero__search label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
  font-size: 0;
  line-height: 0;
}

.class-hero__search .class-hero__search-icon {
  color: rgba(255, 255, 255, 0.75);
  flex-shrink: 0;
  width: 20px;
  height: 20px;
}

/*
   Scoped under .class-hero__search so specificity (0,2,0) beats the generic
   form input rule (`input[type="search"]`, 0,1,1) — which was winning before
   and forcing the input to full width with white background + border.
   Also covers plain `input[type="search"]` inside the pill in case an editor
   ever strips the class.
*/
.class-hero__search .class-hero__search-input,
.class-hero__search input[type="search"],
.class-hero__search input[type="text"] {
  flex: 1 1 auto;
  min-width: 0;
  width: auto;
  background: transparent;
  border: 0;
  color: #fff;
  font-family: var(--font-body);
  font-size: var(--t-body);
  padding: 10px 4px;
  border-radius: 0;
  outline: none;
  box-shadow: none;
  -webkit-appearance: none;
  appearance: none;
}
.class-hero__search .class-hero__search-input::placeholder,
.class-hero__search input[type="search"]::placeholder,
.class-hero__search input[type="text"]::placeholder { color: rgba(255, 255, 255, 0.6); }
.class-hero__search .class-hero__search-input:focus,
.class-hero__search input[type="search"]:focus,
.class-hero__search input[type="text"]:focus {
  outline: none;
  box-shadow: none;
  border: 0;
  background: transparent;
}
.class-hero__search .class-hero__search-input::-webkit-search-cancel-button,
.class-hero__search .class-hero__search-input::-webkit-search-decoration { -webkit-appearance: none; }

/*
   Button styling — clean base rules in the skin. If DNN Common / Bootstrap
   ever wins the cascade over these, the fix goes in portal.css (which loads
   last via _includes.ascx and always wins). See portal.css for the current
   home hero button overrides.
*/
.class-hero__search button.class-hero__search-btn,
.class-hero__search > button,
.class-hero__search button[type="button"],
.class-hero__search button[type="submit"] {
  background: #fff;
  color: var(--c-purple-deep);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-body);
  line-height: 1;
  padding: 12px 22px;
  border: 0;
  border-radius: var(--r-pill);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--dur) var(--ease), transform var(--dur-fast) var(--ease), color var(--dur) var(--ease);
  flex-shrink: 0;
  box-shadow: none;
  text-decoration: none;
  -webkit-appearance: none;
  appearance: none;
}
.class-hero__search button.class-hero__search-btn:hover,
.class-hero__search > button:hover {
  background: var(--c-purple-tint);
  color: var(--c-purple-deep);
}
.class-hero__search button.class-hero__search-btn:active,
.class-hero__search > button:active { transform: translateY(1px); }
.class-hero__search button.class-hero__search-btn:focus-visible,
.class-hero__search > button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(186, 104, 200, 0.5);
}

/* Split hero — text column on left, image column on right. Stacks on mobile. */
.class-hero--split .class-hero__inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-6);
  align-items: center;
}
@media (min-width: 900px) {
  .class-hero--split .class-hero__inner {
    grid-template-columns: 6fr 5fr;
    gap: var(--s-7);
  }
  .class-hero--split .class-hero__title { font-size: clamp(36px, 4.5vw, 60px); }
  .class-hero--split .class-hero__lead { max-width: 46ch; }
}
.class-hero__figure {
  margin: 0;
  border-radius: var(--r-xl);
  overflow: hidden;
  background: rgba(255, 255, 255, 0.06);
  aspect-ratio: 5 / 4;
  box-shadow:
    0 20px 60px rgba(26, 13, 43, 0.4),
    0 0 0 1px rgba(255, 255, 255, 0.08);
  position: relative;
  z-index: 2;
}
.class-hero__figure img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 800ms var(--ease-out);
}
.class-hero__figure:hover img { transform: scale(1.02); }
/* Subtle overlay so the image feels part of the hero's colour world, not stuck on top */
.class-hero__figure::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(135deg, rgba(123, 31, 162, 0.15) 0%, transparent 50%, rgba(214, 22, 113, 0.1) 100%);
  pointer-events: none;
}

@media (max-width: 720px) {
  .class-hero { padding: var(--s-7) 0 var(--s-6); }
  .class-hero__search-btn { padding: 10px 16px; font-size: var(--t-small); }
  .class-hero__figure { aspect-ratio: 4 / 3; }
}

/* Drifting orbs — decorative gradient blobs for hero and CTA sections */
.class-hero__orb, .class-panel__orb {
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  opacity: 0.55;
  pointer-events: none;
  z-index: 1;
  animation: classHeroDrift 22s ease-in-out infinite;
}
@keyframes classHeroDrift {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33%      { transform: translate(40px, -30px) scale(1.06); }
  66%      { transform: translate(-30px, 40px) scale(0.96); }
}

/* Panel — a reusable content card with brand background variants */
.class-panel {
  padding: var(--s-6);
  background: #fff;
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
}
.class-panel--soft { background: var(--c-bg-soft); border-color: transparent; }
.class-panel--mist { background: var(--c-purple-mist); border-color: transparent; }
.class-panel--tint { background: var(--c-purple-tint); border-color: transparent; }
.class-panel--brand {
  color: #fff;
  background: linear-gradient(135deg, #7b1fa2 0%, #4a0e69 100%);
  border: 0;
}
.class-panel--brand h2, .class-panel--brand h3 { color: #fff; }
.class-panel--brand p { color: rgba(255, 255, 255, 0.85); }

/* Stat block — a headline number + label. For trust strips, KPIs. */
.class-stat { text-align: center; padding: var(--s-3); }
.class-stat__number {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(28px, 3vw, 44px);
  font-weight: 800;
  letter-spacing: -0.03em;
  color: var(--c-purple-deep);
  line-height: 1;
  margin-bottom: var(--s-2);
}
.class-stat__label {
  font-size: var(--t-small);
  color: var(--c-ink-muted);
  line-height: 1.4;
}
.class-section--brand .class-stat__number { color: #fff; }
.class-section--brand .class-stat__label  { color: rgba(255, 255, 255, 0.8); }

/* ============ LEGACY CLASS ALIASES ============ */
/*
   The hero primitives used to be prefixed .home-hero__* (in portal.css).
   They were promoted to reusable .class-hero__* in skin.css so every page's
   hero can use them. These aliases keep any HTML that still uses the old
   .home-hero__* names working — so you can update DNN HTML modules at your
   leisure without a broken site in the interim. Safe to remove once every
   HTML fragment on every page is using .class-hero__* prefixes.
*/

.home-hero { /* alias — inherits everything from .class-hero via HTML class stacking */ }
.home-hero__inner       { /* handled by .class-hero__inner if both classes are on the element */ }

/* Root-level alias: any element with .home-hero WITHOUT .class-hero also gets hero styling. */
.home-hero:not(.class-hero) {
  position: relative;
  overflow: hidden;
  padding: var(--s-9) 0 var(--s-8);
  color: #fff;
  background:
    radial-gradient(1000px 600px at 80% 10%, rgba(186,104,200,0.35), transparent 60%),
    radial-gradient(800px 500px at 10% 90%, rgba(123,31,162,0.45), transparent 60%),
    linear-gradient(135deg, #1a0d2b 0%, #4a0e69 45%, #7b1fa2 100%);
}
.home-hero:not(.class-hero) .home-hero__inner { position: relative; z-index: 2; }

.home-hero__eyebrow {
  display: inline-block;
  font-family: var(--font-display);
  font-size: var(--t-micro);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: rgba(255, 255, 255, 0.75);
  margin-bottom: var(--s-4);
}
.home-hero__title {
  font-family: var(--font-display);
  font-size: clamp(44px, 6vw, 80px);
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 1.02;
  margin: 0 0 var(--s-5);
  background: linear-gradient(135deg, #ffffff 0%, #ba68c8 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.home-hero__lead {
  font-size: var(--t-lead);
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.85);
  max-width: 58ch;
  margin: 0 0 var(--s-6);
}

/* Search bar — same visual as .class-hero__search */
.home-hero__search {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 6px 6px 6px 20px;
  background: rgba(255, 255, 255, 0.12);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1.5px solid rgba(255, 255, 255, 0.22);
  border-radius: var(--r-pill);
  max-width: 560px;
  margin: 0 0 var(--s-6);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.home-hero__search:focus-within {
  background: rgba(255, 255, 255, 0.18);
  border-color: rgba(255, 255, 255, 0.5);
  box-shadow: 0 0 0 4px rgba(186, 104, 200, 0.35);
}
/* Same label-hide rule for the legacy .home-hero__search alias */
.home-hero__search > label,
.home-hero__search label {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
  font-size: 0; line-height: 0;
}
.home-hero__search .home-hero__search-icon { color: rgba(255, 255, 255, 0.75); flex-shrink: 0; width: 20px; height: 20px; }
.home-hero__search .home-hero__search-input,
.home-hero__search input[type="search"],
.home-hero__search input[type="text"] {
  flex: 1 1 auto;
  min-width: 0;
  width: auto;
  background: transparent;
  border: 0;
  color: #fff;
  font-family: var(--font-body);
  font-size: var(--t-body);
  padding: 10px 4px;
  border-radius: 0;
  outline: none;
  box-shadow: none;
  -webkit-appearance: none;
  appearance: none;
}
.home-hero__search .home-hero__search-input::placeholder,
.home-hero__search input[type="search"]::placeholder,
.home-hero__search input[type="text"]::placeholder { color: rgba(255, 255, 255, 0.6); }
.home-hero__search .home-hero__search-input:focus,
.home-hero__search input[type="search"]:focus,
.home-hero__search input[type="text"]:focus {
  outline: none; box-shadow: none; border: 0; background: transparent;
}
.home-hero__search .home-hero__search-input::-webkit-search-cancel-button,
.home-hero__search .home-hero__search-input::-webkit-search-decoration { -webkit-appearance: none; }
.home-hero__search button.home-hero__search-btn,
.home-hero__search > button,
.home-hero__search button[type="button"],
.home-hero__search button[type="submit"] {
  background: #fff;
  color: var(--c-purple-deep);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-body);
  line-height: 1;
  padding: 12px 22px;
  border: 0;
  border-radius: var(--r-pill);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--dur) var(--ease);
  flex-shrink: 0;
  box-shadow: none;
  text-decoration: none;
  -webkit-appearance: none;
  appearance: none;
}
.home-hero__search button.home-hero__search-btn:hover,
.home-hero__search > button:hover {
  background: var(--c-purple-tint);
  color: var(--c-purple-deep);
}

.home-hero__ctas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
}

/* Orbs */
.home-hero__orb {
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  opacity: 0.55;
  pointer-events: none;
  z-index: 1;
  animation: classHeroDrift 22s ease-in-out infinite;
}
.home-hero__orb--1 { width: 520px; height: 520px; background: #ba68c8; top: -120px; right: -60px; }
.home-hero__orb--2 { width: 420px; height: 420px; background: #7b1fa2; bottom: -100px; left: -60px; animation-delay: -8s; }
.home-hero__orb--3 { width: 280px; height: 280px; background: #d61671; top: 40%; left: 60%; opacity: 0.3; animation-delay: -14s; }

@media (max-width: 720px) {
  .home-hero:not(.class-hero) { padding: var(--s-7) 0 var(--s-6); }
  .home-hero__search-btn { padding: 10px 16px; font-size: var(--t-small); }
}

/* ============ REUSABLE PAGE SECTIONS ============ */

/* Accreditations / trust strip — a row of accreditation logos with a small
   eyebrow above. Can be dropped into any page. Add / remove items in the
   HTML — the grid auto-fits to whatever's there. */
.class-accred {
  padding: var(--s-6) 0;
  border-bottom: 1px solid var(--c-line);
}
.class-accred__eyebrow {
  font-family: var(--font-display);
  font-size: var(--t-micro);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--c-ink-subtle);
  text-align: center;
  margin: 0 0 var(--s-4);
}
.class-accred__grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--s-5) var(--s-6);
}
.class-accred__item { margin: 0; padding: 0; display: inline-flex; align-items: center; }
.class-accred__logo {
  height: 48px;
  width: auto;
  max-width: 160px;
  object-fit: contain;
  filter: grayscale(0.4) opacity(0.85);
  transition: filter var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.class-accred__item:hover .class-accred__logo {
  filter: grayscale(0) opacity(1);
  transform: translateY(-1px);
}
@media (max-width: 720px) {
  .class-accred__logo { height: 40px; }
  .class-accred__grid { gap: var(--s-4); }
}

/* Scroll cue — playful "look down" arrow that smooth-scrolls to a target */
.class-scrollcue {
  padding: var(--s-6) 0;
  text-align: center;
}
.class-scrollcue__link {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-3);
  color: var(--c-purple-deep);
  text-decoration: none;
  transition: color var(--dur) var(--ease);
  padding: var(--s-3) var(--s-4);
}
.class-scrollcue__link:hover { color: var(--c-purple); text-decoration: none; }
.class-scrollcue__link:hover .class-scrollcue__arrow { transform: translateY(4px); }
.class-scrollcue__label {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-body);
  border-bottom: 1.5px solid currentColor;
  padding-bottom: 2px;
}
.class-scrollcue__arrow {
  width: 32px;
  height: 42px;
  transition: transform var(--dur) var(--ease);
  animation: classScrollBob 2.4s ease-in-out infinite;
}
@keyframes classScrollBob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(6px); }
}
@media (prefers-reduced-motion: reduce) {
  .class-scrollcue__arrow { animation: none; }
}

/* Team strip — a row of consultant cards. Not the full team page;
   just enough to build trust and link out. */
.class-team-strip {
  padding: var(--s-8) 0;
  background: var(--c-bg-soft);
  border-radius: var(--r-xl);
  margin: var(--s-6) 0;
  padding-inline: var(--s-5);
}
.class-team-strip__head {
  max-width: 640px;
  margin: 0 auto var(--s-7);
  text-align: center;
}
.class-team-strip__head h2 {
  font-size: clamp(28px, 3vw, 40px);
  letter-spacing: -0.025em;
  margin: var(--s-2) 0 var(--s-3);
}
.class-team-strip__head .lead { color: var(--c-ink-muted); margin: 0; }

.class-team-strip__grid {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--s-6);
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--s-5);
}
@media (max-width: 900px) { .class-team-strip__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 480px) { .class-team-strip__grid { grid-template-columns: 1fr; } }

.class-team__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: var(--s-4);
  background: #fff;
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  text-align: center;
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.class-team__item:hover {
  border-color: var(--c-purple-light);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.class-team__photo {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  object-fit: cover;
  margin-bottom: var(--s-3);
  background: linear-gradient(135deg, var(--c-purple-light), var(--c-purple-deep));
  border: 3px solid #fff;
  box-shadow: 0 4px 12px rgba(31, 21, 48, 0.08);
}
.class-team__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--t-h5);
  color: var(--c-ink-strong);
}
.class-team__role {
  font-size: var(--t-small);
  color: var(--c-ink-muted);
  margin-bottom: var(--s-2);
}
.class-team__dial {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--t-small);
  color: var(--c-purple-deep);
  text-decoration: none;
  padding: 4px 12px;
  border-radius: var(--r-pill);
  background: var(--c-purple-tint);
  transition: background var(--dur) var(--ease);
}
.class-team__dial:hover { background: var(--c-purple-light); color: #fff; text-decoration: none; }

.class-team-strip__foot { text-align: center; }

/* Floating action button — persistent contact affordance bottom-right.
   Appears after a delay set via data-delay on the .class-fab element.
   Dismissible via the X button. Handled in skin.js. */
.class-fab {
  position: fixed;
  bottom: var(--s-5);
  right: var(--s-5);
  z-index: 100;
  display: flex;
  align-items: flex-end;
  gap: var(--s-3);
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
  pointer-events: none;
}
.class-fab.is-visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.class-fab.is-dismissed { display: none; }

.class-fab__bubble {
  background: #fff;
  border-radius: 16px;
  padding: 12px 16px;
  box-shadow: 0 6px 24px rgba(31, 21, 48, 0.15), 0 2px 6px rgba(31, 21, 48, 0.06);
  font-size: var(--t-small);
  color: var(--c-ink-strong);
  max-width: 240px;
  line-height: 1.4;
  margin-bottom: 6px;
  position: relative;
}
.class-fab__bubble::after {
  content: "";
  position: absolute;
  bottom: 12px;
  right: -6px;
  width: 12px;
  height: 12px;
  background: #fff;
  transform: rotate(45deg);
}
.class-fab__hello { font-family: var(--font-display); font-weight: 500; }

.class-fab__cta {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: linear-gradient(135deg, #7b1fa2 0%, #4a0e69 100%);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  box-shadow: 0 10px 30px rgba(123, 31, 162, 0.35), 0 4px 12px rgba(31, 21, 48, 0.15);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
  flex-shrink: 0;
}
.class-fab__cta:hover {
  transform: translateY(-2px) scale(1.05);
  box-shadow: 0 14px 40px rgba(123, 31, 162, 0.45), 0 6px 16px rgba(31, 21, 48, 0.2);
  color: #fff;
  text-decoration: none;
}
.class-fab__cta:focus-visible {
  outline: none;
  box-shadow: 0 0 0 4px rgba(186, 104, 200, 0.5), 0 10px 30px rgba(123, 31, 162, 0.35);
}

.class-fab__dismiss {
  position: absolute;
  top: -8px;
  right: 52px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: #fff;
  border: 1px solid var(--c-line);
  color: var(--c-ink-muted);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: all var(--dur) var(--ease);
  z-index: 1;
}
.class-fab__dismiss:hover {
  border-color: var(--c-purple-light);
  color: var(--c-purple-deep);
  transform: scale(1.1);
}

@media (max-width: 720px) {
  .class-fab { bottom: var(--s-4); right: var(--s-4); }
  .class-fab__bubble { display: none; }
  .class-fab__cta { width: 52px; height: 52px; }
  .class-fab__dismiss { right: 44px; }
}

/* ============ 14. UTILITIES ============ */

.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
.text-center { text-align: center; }
.bg-soft   { background: var(--c-bg-soft); }
.bg-mist   { background: var(--c-purple-mist); }
.bg-tint   { background: var(--c-purple-tint); }
.bg-brand  { background: linear-gradient(135deg, #7b1fa2 0%, #4a0e69 100%); color: #fff; }
.bg-brand h1, .bg-brand h2, .bg-brand h3 { color: #fff; }
.bg-brand p, .bg-brand .lead { color: rgba(255, 255, 255, 0.85); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
  html { scroll-behavior: auto; }
}

/* ============ 15. DNN CORE UI — DIALOGS, POPUPS & ACCOUNT FORMS ============ */
/*
  Everything above styles our own pages and modules. DNN's own chrome — the
  login popup, the confirm/alert dialogs, the register and password forms — is
  rendered by the framework, so none of it was reached by this stylesheet and it
  fell through to DNN's stock sheet at
  Resources/Shared/stylesheets/dnndefault/10.0.0/default.css.

  Four layers, in increasing specificity:

    15.1  Token bridge   DNN 10's core CSS READS --dnn-* custom properties and
                         never defines them anywhere — every use supplies an
                         inline fallback, e.g. var(--dnn-color-primary,#3792ed).
                         Defining them here therefore re-skins core buttons,
                         links, radii, dialogs and validation states with no
                         override and no specificity fight. This is the cheapest
                         lever by a wide margin: prefer adding a token here over
                         writing a new selector further down.

    15.2  Dialog chrome  .dnnFormPopup is the wrapper class on BOTH the confirm
                         and alert dialogs ($.fn.dnnConfirm / $.dnnAlert, in
                         Resources/Shared/scripts/dnn.jquery.js) and the iframe
                         modal behind the login popup (js/dnn.modalpopup.js), so
                         one set of rules covers both.

    15.3  DNN forms      A light pass — colour and type only — on .dnnForm at
                         large, plus the shared action-button classes.

    15.4  Account forms  The visitor-facing login/register/password screens,
                         which is what actually renders inside the popup iframe.

  Out of scope on purpose: the Persona Bar (the DNN admin UI) ships its own
  bundled React stylesheet and cannot be reached from a skin stylesheet.
*/

/* ---- 15.1 DNN token bridge ---- */

:root {
  /* Brand */
  --dnn-color-primary:            var(--c-purple);
  --dnn-color-primary-light:      var(--c-purple-light);
  --dnn-color-primary-dark:       var(--c-purple-deep);
  --dnn-color-primary-contrast:   #ffffff;
  /* DNN composes rgba() shadows from these, so they must be raw channel
     numbers rather than colours. Keep in step with --c-purple (#8e24aa). */
  --dnn-color-primary-r: 142;
  --dnn-color-primary-g: 36;
  --dnn-color-primary-b: 170;

  --dnn-color-secondary:          var(--c-pink);
  --dnn-color-secondary-light:    #f06ca6; /* literal: no --c-pink-light token */
  --dnn-color-secondary-dark:     var(--c-pink-deep);
  --dnn-color-secondary-contrast: #ffffff;

  --dnn-color-tertiary:           var(--c-teal);
  --dnn-color-tertiary-dark:      var(--c-teal-deep);
  --dnn-color-tertiary-contrast:  #ffffff;

  /* Ink. Despite the name, DNN uses -foreground-light almost exclusively as a
     BORDER colour, so it maps to our line token, not to a lighter ink. */
  --dnn-color-foreground:          var(--c-ink);
  --dnn-color-foreground-light:    var(--c-line-strong);
  --dnn-color-foreground-dark:     var(--c-ink-strong);
  --dnn-color-foreground-contrast: #ffffff;
  /* raw channels, keep in step with --c-ink (#1f1530) */
  --dnn-color-foreground-r: 31;
  --dnn-color-foreground-g: 21;
  --dnn-color-foreground-b: 48;

  --dnn-color-background:          var(--c-bg);
  --dnn-color-background-dark:     var(--c-bg-tint);
  --dnn-color-background-contrast: var(--c-ink);

  --dnn-color-neutral:          var(--c-ink-muted);
  --dnn-color-neutral-light:    var(--c-bg-tint);
  --dnn-color-neutral-dark:     var(--c-ink-subtle);
  --dnn-color-neutral-contrast: #ffffff;

  /* Functional — reuse the accent ramps so DNN's own messages read like our badges */
  --dnn-color-danger:           var(--c-red);
  --dnn-color-danger-dark:      var(--c-red-deep);
  --dnn-color-danger-contrast:  #ffffff;
  --dnn-color-success:          var(--c-green);
  --dnn-color-success-dark:     var(--c-green-deep);
  --dnn-color-success-contrast: #ffffff;
  --dnn-color-warning:          var(--c-amber);
  --dnn-color-warning-dark:     var(--c-amber-deep);
  /* amber is far too light to carry white text — ink instead */
  --dnn-color-warning-contrast: var(--c-ink-strong);
  --dnn-color-info:             var(--c-teal);
  --dnn-color-info-dark:        var(--c-teal-deep);
  --dnn-color-info-contrast:    #ffffff;
  /* raw channels, keep in step with --c-teal (#00acc1) */
  --dnn-color-info-r: 0;
  --dnn-color-info-g: 172;
  --dnn-color-info-b: 193;

  --dnn-controls-radius: var(--r-sm);
  --dnn-base-font-size:  var(--t-body);
}

/* ---- 15.2 Dialog chrome: confirm dialogs + the login/modal popup ---- */

/* The scrim. DNN's own rule is a single class (0,1,0); this file loads at
   Priority 500, after DNN core, so it wins on order without !important. */
.ui-widget-overlay {
  background: rgba(31, 21, 48, 0.55);
  opacity: 1;
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}

/* The dialog card. Padding moves off the box and onto the three inner regions
   so the header/footer rules can span the full width.
   Deliberately NOT overflow:hidden — DNN parks the modal's control cluster
   (.dnnModalCtrl) outside the box, and clipping would swallow the close button
   before the rule below pulls it back inside. */
.dnnFormPopup,
.dnnFormPopup.ui-dialog {
  padding: 0;
  background: var(--c-bg);
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xl);
  font-family: var(--font-body);
  color: var(--c-ink);
}

.dnnFormPopup .ui-dialog-titlebar {
  position: relative;
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--c-line);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  background: var(--c-purple-mist);
  font-family: var(--font-display);
  font-size: var(--t-h5);
  font-weight: 700;
  color: var(--c-ink-strong);
}
.dnnFormPopup .ui-dialog-title { float: none; }

/* dnnConfirm/dnnAlert build their dialogs with draggable:false, so the move
   cursor DNN sets on every titlebar is a lie there. Progressive enhancement —
   engines without :has() simply keep the inherited cursor. */
.dnnFormPopup:has(.dnnDialog) .ui-dialog-titlebar { cursor: default; }

/* Body. These two selectors hit the SAME element for a confirm dialog (the
   .dnnDialog div is what jQuery UI turns into .ui-dialog-content), so the
   second must stay after the first: iframes get no padding, text does. */
.dnnFormPopup .ui-dialog-content { padding: 0; }
.dnnFormPopup .dnnDialog {
  padding: var(--s-5);
  font-family: var(--font-body);
  font-size: var(--t-body);
  line-height: var(--lh-normal);
  color: var(--c-ink);
}

.dnnFormPopup .ui-dialog-buttonpane {
  margin: 0;
  padding: var(--s-4) var(--s-5);
  border-top: 1px solid var(--c-line);
  background: var(--c-bg-soft);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}
.dnnFormPopup .ui-dialog-buttonset {
  float: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--s-3);
}

/*
  Titlebar close for the confirm/alert dialogs.

  The selector has to carry `div.ui-dialog-titlebar >` to outrank DNN core's

      div.ui-dialog-titlebar > .ui-dialog-titlebar-close { top:-30px; right:-30px; … }

  which is (0,2,1) and beat the plainer `.dnnFormPopup .ui-dialog-titlebar-close`
  at (0,2,0) — that is what parked this button 30px outside the card's top-right
  corner. Matching DNN's own shape brings us to (0,3,1) and wins.

  The `>` also scopes this correctly for free: the modal's close button is wrapped
  in .dnnModalCtrl, so it is not a direct child of the titlebar and keeps its own
  treatment further down.

  dnnConfirm writes the literal string "Close" into this button (dnn.jquery.js).
  We keep that text in the DOM as the accessible name and hide it visually, then
  paint the same purple glyph the modal's controls use, so every popup in the site
  closes via an identical affordance.
*/
.dnnFormPopup div.ui-dialog-titlebar > .ui-dialog-titlebar-close {
  --ctrl-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234a0e69' stroke-width='2.5' stroke-linecap='round'><path d='M6 6l12 12M18 6L6 18'/></svg>");
  position: absolute;
  top: 50%;
  right: var(--s-4);
  bottom: auto;
  left: auto;
  transform: translateY(-50%);
  display: block;
  width: 28px;
  height: 28px;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: var(--r-pill);
  background-color: transparent;
  background-image: var(--ctrl-icon);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 14px 14px;
  /* keeps the "Close" text as the accessible name while showing the glyph */
  text-indent: -9999em;
  overflow: hidden;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out);
}
/*
  Longhands only — never the `background` shorthand. The shorthand resets
  background-position to 0 0, which is precisely what made the glyph slide up and
  to the left out of the button on hover while DNN's sprite was still in play.
*/
.dnnFormPopup div.ui-dialog-titlebar > .ui-dialog-titlebar-close:hover,
.dnnFormPopup div.ui-dialog-titlebar > .ui-dialog-titlebar-close:focus-visible {
  background-color: var(--c-purple-tint);
  background-image: var(--ctrl-icon);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 14px 14px;
  transform: translateY(-50%);
}
/* jQuery UI ships an icon span inside the close button; the glyph is ours */
.dnnFormPopup .ui-dialog-titlebar-close .ui-icon,
.dnnFormPopup .ui-dialog-titlebar-close .ui-button-icon-space { display: none; }

/* The iframe modal's control cluster. DNN parks it OUTSIDE the card at
   top/right:-30px and paints the buttons with PNG sprites whose URLs resolve
   relative to DNN's own stylesheet. Bring it inside the card and draw both
   icons inline so they carry brand colour and stay crisp at any DPI. */
.dnnFormPopup .dnnModalCtrl {
  top: var(--s-3);
  right: var(--s-3);
  width: auto;
  height: auto;
  display: inline-flex;
  gap: var(--s-1);
  padding: 4px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.92);
  box-shadow: var(--shadow-sm);
}
/* Each button names its own glyph once, in a variable. The geometry rule below
   then applies to every state without repeating the SVG, which is what lets the
   hover state re-assert the full background cheaply — see the note there. */
.dnnFormPopup .dnnModalCtrl .ui-dialog-titlebar-close {
  --ctrl-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234a0e69' stroke-width='2.5' stroke-linecap='round'><path d='M6 6l12 12M18 6L6 18'/></svg>");
}
.dnnFormPopup .dnnModalCtrl a.dnnToggleMax {
  --ctrl-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234a0e69' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><path d='M4 9V4h5M20 15v5h-5M20 9V4h-5M4 15v5h5'/></svg>");
}

/*
  Maximised: show a "restore" glyph (arrows pointing inward) instead of the
  outward-pointing maximise one.

  DNN gives us no hook for this — dnn.modalpopup.js keeps the maximised flag
  purely in jQuery data ($('#iPopUp').data('isMaximized')) and never touches the
  DOM, which is why the icon never changed. Section 7 of skin.js mirrors that
  flag onto .is-maximized here. Because the icon travels through --ctrl-icon,
  this single re-declaration covers the resting, hover and focus states at once.
*/
.dnnFormPopup .dnnModalCtrl.is-maximized a.dnnToggleMax {
  --ctrl-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234a0e69' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><path d='M9 4v5H4M15 4v5h5M15 20v-5h5M9 20v-5H4'/></svg>");
}

.dnnFormPopup .dnnModalCtrl .ui-dialog-titlebar-close,
.dnnFormPopup .dnnModalCtrl a.dnnToggleMax {
  position: static;
  float: none;
  transform: none;
  width: 28px;
  height: 28px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: var(--r-pill);
  background-color: transparent;
  background-image: var(--ctrl-icon);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 14px 14px;
  text-indent: -9999em;
  transition: background-color var(--dur-fast) var(--ease-out);
}

/*
  Hover and keyboard focus.

  This MUST re-assert the whole background, not just the colour. DNN's own hover
  rules for these two buttons sit at the same specificity as this one (0,4,0) and
  use the `background` shorthand plus an explicit background-position — 8px 4px on
  close, 10px 2px on maximise. Any longhand left unset here therefore falls through
  to DNN's, and those offsets are measured against a 30x18 sprite, not our 28x28
  button: the glyph jumped up 3px (close) and 5px (maximise) on hover, and the
  shorthand swapped our inline SVG back to DNN's grey PNG at the same time.

  Pinning image, position, repeat and size keeps the buttons perfectly still and
  leaves background-color as the only thing that actually changes.
*/
.dnnFormPopup .dnnModalCtrl .ui-dialog-titlebar-close:hover,
.dnnFormPopup .dnnModalCtrl .ui-dialog-titlebar-close:focus-visible,
.dnnFormPopup .dnnModalCtrl a.dnnToggleMax:hover,
.dnnFormPopup .dnnModalCtrl a.dnnToggleMax:focus-visible {
  background-color: var(--c-purple-tint);
  background-image: var(--ctrl-icon);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 14px 14px;
  transform: none;
}

/* ---- 15.3 DNN forms: light global pass + shared action buttons ---- */
/*
  Colour and type only. DNN's float-based label column is deliberately left
  alone at this level: the admin screens (module settings, page settings) are
  dense two-column forms that depend on it. The stacked layout is scoped to the
  account forms in 15.4, which is what visitors actually see.
*/
.dnnForm { font-family: var(--font-body); color: var(--c-ink); }
.dnnForm legend {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--c-ink-strong);
}
.dnnForm .dnnFormItem { margin-bottom: var(--s-4); }
.dnnFormLabel,
.dnnLabel {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--c-ink);
}

/* Validation and info messages — same soft-tint + deep-text pairing as .class-badge */
.dnnFormMessage {
  display: block;
  margin-bottom: var(--s-4);
  padding: var(--s-3) var(--s-4);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  font-size: var(--t-small);
  line-height: var(--lh-normal);
}
.dnnFormMessage.dnnFormError,
.dnnFormMessage.dnnFormValidationSummary {
  background: var(--c-red-soft);
  border-color: rgba(237, 27, 45, 0.25);
  color: var(--c-red-deep);
}
.dnnFormMessage.dnnFormSuccess {
  background: var(--c-green-soft);
  border-color: rgba(67, 160, 71, 0.25);
  color: var(--c-green-deep);
}
.dnnFormMessage.dnnFormWarning {
  background: var(--c-amber-soft);
  border-color: rgba(255, 160, 0, 0.3);
  color: var(--c-amber-deep);
}
.dnnFormMessage.dnnFormInfo {
  background: var(--c-teal-soft);
  border-color: rgba(0, 172, 193, 0.25);
  color: var(--c-teal-deep);
}

/*
  Action buttons. DNN uses these three classes for every button it renders —
  dialog button panes, login, register, admin forms — so shaping them once here
  is what makes the whole framework read as ours. Matches .class-btn.
  The buttonpane selector is included so jQuery UI's own .ui-button styling
  (specificity 0,1,0) is outranked rather than merely outordered.
*/
.dnnPrimaryAction, a.dnnPrimaryAction, button.dnnPrimaryAction,
.dnnSecondaryAction, a.dnnSecondaryAction, button.dnnSecondaryAction,
.dnnTertiaryAction, a.dnnTertiaryAction, button.dnnTertiaryAction,
.dnnFormPopup .ui-dialog-buttonpane button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-width: 0;
  margin: 0;
  padding: 12px 22px;
  font-family: var(--font-display);
  font-size: var(--t-small);
  font-weight: 600;
  line-height: 1;
  text-align: center;
  text-decoration: none;
  border: 1.5px solid transparent;
  border-radius: var(--r-pill);
  cursor: pointer;
  transition: transform var(--dur-fast) var(--ease), background var(--dur) var(--ease), color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.dnnPrimaryAction:active, .dnnSecondaryAction:active, .dnnTertiaryAction:active,
.dnnFormPopup .ui-dialog-buttonpane button:active { transform: translateY(1px); }
.dnnPrimaryAction:focus-visible, .dnnSecondaryAction:focus-visible, .dnnTertiaryAction:focus-visible,
.dnnFormPopup .ui-dialog-buttonpane button:focus-visible { outline: none; box-shadow: var(--shadow-focus); }

.dnnPrimaryAction, a.dnnPrimaryAction, button.dnnPrimaryAction,
.dnnFormPopup .ui-dialog-buttonpane button.dnnPrimaryAction {
  background: var(--c-purple-deep);
  border-color: var(--c-purple-deep);
  color: #fff;
  box-shadow: var(--shadow-md);
}
.dnnPrimaryAction:hover, a.dnnPrimaryAction:hover, button.dnnPrimaryAction:hover,
.dnnFormPopup .ui-dialog-buttonpane button.dnnPrimaryAction:hover {
  background: var(--c-purple);
  border-color: var(--c-purple);
  color: #fff;
  box-shadow: var(--shadow-lg);
  text-decoration: none;
}

.dnnSecondaryAction, a.dnnSecondaryAction, button.dnnSecondaryAction,
.dnnFormPopup .ui-dialog-buttonpane button.dnnSecondaryAction {
  background: var(--c-purple-tint);
  border-color: transparent;
  color: var(--c-purple-deep);
}
.dnnSecondaryAction:hover, a.dnnSecondaryAction:hover, button.dnnSecondaryAction:hover,
.dnnFormPopup .ui-dialog-buttonpane button.dnnSecondaryAction:hover {
  background: var(--c-purple-light);
  color: #fff;
  text-decoration: none;
}

/* Tertiary, and the cancel button dnnConfirm tags on its "No" option */
.dnnTertiaryAction, a.dnnTertiaryAction, button.dnnTertiaryAction,
.dnnFormPopup .ui-dialog-buttonpane button.dnnConfirmCancel {
  background: transparent;
  border-color: var(--c-line-strong);
  color: var(--c-ink-muted);
}
.dnnTertiaryAction:hover, a.dnnTertiaryAction:hover, button.dnnTertiaryAction:hover,
.dnnFormPopup .ui-dialog-buttonpane button.dnnConfirmCancel:hover {
  background: var(--c-bg-tint);
  border-color: var(--c-purple-light);
  color: var(--c-purple-deep);
  text-decoration: none;
}

.dnnPrimaryAction[disabled], .dnnSecondaryAction[disabled], .dnnTertiaryAction[disabled],
.dnnPrimaryAction[disabled]:hover, .dnnSecondaryAction[disabled]:hover, .dnnTertiaryAction[disabled]:hover {
  background: var(--c-bg-tint);
  border-color: var(--c-line-strong);
  color: var(--c-ink-subtle);
  box-shadow: none;
  cursor: not-allowed;
  transform: none;
}

/* ---- 15.4 Account forms: login, register, password ---- */
/*
  Scope note: these are the visitor-facing account screens —
  DesktopModules/AuthenticationServices/DNN/Login.ascx renders .dnnLoginService,
  DesktopModules/Admin/Security/Register.ascx renders .dnnRegistrationForm.
  Everything here is intentionally NOT applied to .dnnForm at large, so admin
  screens keep the dense layout their editors expect.
*/
.dnnLoginService,
.dnnRegistrationForm,
.dnnPasswordReset {
  max-width: 460px;
  margin-inline: auto;
}

/* Stack the labels. DNN floats them into a 32%-wide right-aligned column, which
   is unreadable at popup width.
   display:block matters as much as the float reset: DNN's account markup is
   inconsistent — the username and password captions sit in a <div class="dnnLabel">
   (already block) but the remember-me and button rows use a bare
   <span class="dnnFormLabel">, and width:100% is silently dropped on an inline
   box. Without this the row's left edge depends on inline/float interaction
   rather than being pinned to the column. */
.dnnLoginService .dnnFormLabel, .dnnLoginService .dnnLabel,
.dnnRegistrationForm .dnnFormLabel, .dnnRegistrationForm .dnnLabel,
.dnnPasswordReset .dnnFormLabel, .dnnPasswordReset .dnnLabel {
  display: block;
  float: none;
  width: 100%;
  margin: 0 0 var(--s-2);
  padding: 0;
  text-align: left;
}
.dnnLoginService .dnnFormLabel > span, .dnnLoginService .dnnLabel > span,
.dnnRegistrationForm .dnnFormLabel > span, .dnnRegistrationForm .dnnLabel > span,
.dnnPasswordReset .dnnFormLabel > span, .dnnPasswordReset .dnnLabel > span {
  text-align: left;
}

/* DNN emits spacer labels purely to fill its 32%-wide float column, and they come
   in two flavours. lblLoginRememberMe and lblLogin render genuinely empty — the
   "Remember Login" caption belongs to the checkbox itself, not to the label — so
   :empty removes them outright. This is what keeps the remember-me row flush with
   the inputs above it; the float reset alone is not enough, because a stray
   32%-wide spacer indents everything that follows it on the row. */
.dnnLoginService .dnnFormLabel:empty,
.dnnRegistrationForm .dnnFormLabel:empty,
.dnnPasswordReset .dnnFormLabel:empty { display: none; }

/* The other flavour holds a literal &nbsp;, so :empty cannot see it. :has() is a
   progressive enhancement here — the layout is already correct without it, this
   only closes up a blank row above the Register / Forgot password links. */
.dnnLoginService .dnnFormLabel:has(+ .dnnLoginActions),
.dnnLoginService .dnnFormLabel:has(+ .dnnPrimaryAction) { display: none; }

.dnnLoginService .dnnFormItem,
.dnnRegistrationForm .dnnFormItem,
.dnnPasswordReset .dnnFormItem { margin-bottom: var(--s-4); }

/*
  Remember me. Two things to keep in mind if this is ever touched again:

  1. It MUST stay scoped. DNN core carries `.dnnFormLabel + span` at specificity
     (0,1,1), which matches this exact element and forces display:inline-block.
     A bare `.dnnLoginRememberMe` is only (0,1,0) and loses that fight, taking
     the alignment and gap down with it. The descendant selector makes it (0,2,0).
  2. display:flex, not inline-flex — as a block-level box it starts its own line
     at the column's left edge no matter what the preceding spacer span does,
     which is what keeps the checkbox aligned with the inputs above.
*/
.dnnLoginService .dnnLoginRememberMe {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0;
  font-size: var(--t-small);
  color: var(--c-ink-muted);
}
.dnnLoginService .dnnLoginRememberMe input[type="checkbox"] {
  flex: 0 0 auto;
  width: auto;
  margin: 0;
  accent-color: var(--c-purple);
}
.dnnLoginService .dnnLoginRememberMe label {
  display: inline;
  margin: 0;
  font-family: var(--font-body);
  font-weight: 500;
}

/* Link rows: "Register" / "Forgot password" under the login button, and the
   register form's own button row. */
.dnnLoginActions { display: block; }
.dnnLoginActions ul,
ul.dnnActions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin: 0;
  padding: 0;
  list-style: none;
}
ul.dnnActions { margin-top: var(--s-5); }
.dnnLoginActions li,
ul.dnnActions li { margin: 0; }

.dnnSocialRegistration,
.dnnLoginService .dnnSocialRegistration { margin-bottom: var(--s-4); }

.dnnCaptcha img {
  display: inline-block;
  border: 1px solid var(--c-line-strong);
  border-radius: var(--r-sm);
}

/* ---- 15.5 The popup document itself ---- */
/*
  The login popup is an iframe of a real DNN page, skinned by popUpSkin.ascx
  rather than default.ascx. That document has no header or footer, so it needs
  the breathing room a bare dialog would otherwise lack — DNN's stock
  _default/popUpSkin.ascx hardcodes a white body for the same reason.
  .class-popup is our own wrapper, added in popUpSkin.ascx; it is the only
  reliable hook, because DNN only classes the iframe body on narrow viewports
  (dnn.modalpopup.js adds .dnnFormPopupMobileView there).
*/
.class-popup {
  padding: var(--s-5);
  background: var(--c-bg);
}
.class-popup .DnnModule { margin-bottom: 0; }
body.dnnFormPopupMobileView .class-popup { padding: var(--s-4); }

/*
  Exemption for the one popup screen that is viewport-locked rather than
  flow-laid-out — see section 15.6 for the full story. In short: EditHtml.ascx's
  inline script sets `$('body, html').css('overflow','hidden')` and then sizes its
  content pane to exactly $(window).height() minus the action bar, so the screen is
  built to fill the iframe precisely. Padding on this wrapper makes the document
  taller than a viewport that can no longer scroll, and the bottom of it — the
  Save / Cancel bar — simply disappears.

  MUST stay after the mobile-view rule above: :has() takes the specificity of its
  most specific argument, so this is (0,2,0), a tie with
  `body.dnnFormPopupMobileView .class-popup`, and order is what decides it.

  This needs :has() (Chrome/Edge 105, Safari 15.4, Firefox 121 — all 2022-23).
  The rules in 15.6 are plain selectors and do the load-bearing work; they shrink
  the bar enough that it stays readable even if this one rule never matches.
*/
.class-popup:has(.dnnEditHtml) { padding: 0; }

@media (max-width: 600px) {
  .class-popup { padding: var(--s-4); }
  .dnnFormPopup .ui-dialog-titlebar,
  .dnnFormPopup .ui-dialog-buttonpane { padding-left: var(--s-4); padding-right: var(--s-4); }
  .dnnFormPopup .dnnDialog { padding: var(--s-4); }
  .dnnFormPopup .ui-dialog-buttonset { justify-content: stretch; }
  .dnnFormPopup .ui-dialog-buttonpane button { flex: 1 1 auto; }
}

/* ---- 15.6 "Edit Content": the one viewport-locked popup screen ---- */
/*
  DesktopModules/HTML/EditHtml.ascx is laid out like an app window, not like a
  document, and it is the only DNN screen in the site that is. Its inline script:

      $('.ehCurrentContent').height($(window).height() - $('.ehActions').height() - …);
      $('body, html').css('overflow', 'hidden');

  measures the action bar, gives the editor pane whatever is left of the iframe
  viewport, and then switches scrolling off entirely. DesktopModules/HTML/edit.css
  pins that bar at a hardcoded `.ehActions { height: 60px }`.

  So this screen has a hard height budget and no scrollbar to absorb a mistake.
  Every pixel the theme adds above or inside the bar pushes the Save / Cancel
  buttons past the bottom of a viewport that cannot scroll to them. Three of our
  rules were doing exactly that, for about 72px in total against a 60px bar:

    · .class-popup's 24px wrapper padding      (handled in 15.5)
    · ul.dnnActions' 24px top margin           (15.4 — for the register form)
    · .dnnForm .dnnFormItem's 16px bottom margin + our taller pill buttons and
      full-size select                          (15.3 and section 8)

  This section is therefore a set of opt-outs, not a restyle. Colour, type and
  shape all still come from 15.3, so the bar still reads as ours; only the
  geometry reverts to something that fits in 60px.

  Note what is NOT here: the bar's contents are deliberately left top-aligned
  rather than centred in the 60px. Centring looks marginally tidier but spends
  half the slack below the buttons, which is the half that gets clipped first if
  the :has() rule in 15.5 ever fails to match. Top-aligned, the buttons survive
  even then.
*/

/* 15.4's spacing above the register form's button row. Inside a fixed-height bar
   it is pure overflow. */
.dnnEditHtml ul.dnnActions { margin-top: 0; }

/* 15.3's form-item spacing. Harmless in the scrollable editor pane above; in the
   bar it is 16px the bar does not have. Scoped to .ehActions for that reason. */
.dnnEditHtml .ehActions .dnnFormItem { margin-bottom: 0; }

/* Our pill buttons are 12px/22px — roughly 10px taller than the stock DNN button
   the 60px was measured against. */
.dnnEditHtml .ehActions .dnnPrimaryAction,
.dnnEditHtml .ehActions .dnnSecondaryAction,
.dnnEditHtml .ehActions .dnnTertiaryAction { padding: 8px 18px; }

/* edit.css draws the disabled "Edit" link by hand (square corners, its own 9px
   bottom margin) rather than reusing .dnnSecondaryAction. Match it to the buttons
   beside it and drop the margin. (0,3,1) clears edit.css's (0,2,1). */
.dnnEditHtml .ehActions a.aspNetDisabled {
  margin-bottom: 0;
  padding: 8px 18px;
  border-radius: var(--r-pill);
  border-color: var(--c-line-strong);
}

/* The render-mode dropdown. Section 8's global control padding (14px, plus a 44px
   right gutter for the chevron) makes this ~51px on its own. edit.css already
   overrides width and margin, so only the vertical metrics need trimming. */
.dnnEditHtml .ehActions .dnnFormItem select {
  padding: 6px 30px 6px var(--s-3);
  font-size: var(--t-small);
  background-position: right 10px center;
  background-size: 14px;
}
