/* ============================================================================
   PEF — site stylesheet.

   ONE FILE, deliberately. This was seven (tokens, base, fonts, buttons,
   header, surfaces, transparent-header), which was seven render-blocking
   requests for 20KB of CSS. They were split because they began life as
   separate Elementor Custom Code snippets; as theme files there is no reason
   for the split, and their load order was load-bearing, which a single file
   makes structural rather than something functions.php has to enforce.

   Enqueued at priority 999 so it lands AFTER Elementor's generated CSS.
   That is not optional. Elementor emits its global classes as
   `.elementor .foo{...}` — specificity (0,2,0), the same as most rules here —
   and equal specificity is broken by source order. Load this first and the
   is-hidden-mobile repair, the coloured-surface heading ink and every header
   override silently invert.

   Paired with pef-behaviour.js (footer-loaded) and the Elementor Variables
   panel, which owns the palette, spacing, type scale, radii and button
   padding. See section 1 for what is NOT in the panel and why.

   CONTENTS
     1  Tokens .................. the remainder that cannot be an Elementor variable
     2  Metric-matched fallbacks  @font-face, to stop the nav reflowing on load
     3  Header shell ............ sticky, elevation, logo, mobile-hide repair
     4  Mega menu — shared ...... titles, hub items, chevron
     5  Mega menu — desktop ..... >=1200: two columns + feature image
     6  Mega menu — compact ..... <=1199: full-screen panel, accordion rows
     7  Footer .................. link and social hover, mobile accordion
     8  Buttons ................. the remainder; the system lives in Elementor
     9  Coloured surfaces ....... heading ink on a coloured band
     10 Transparent header ...... driven by Page Settings -> Header
     11 Reduced motion .......... one block, everything the site animates
   ========================================================================= */


/* ============================================================================
   1. TOKENS
   ----------------------------------------------------------------------------
   MOST TOKENS LIVE IN ELEMENTOR, not here. Site Settings -> Variables holds
   the palette, the spacing steps, the flat type scale, the radii, border
   width, button padding and the font families. Elementor emits them as
   :root{--label:value} into the kit CSS and the global classes reference them
   by id, so renaming a variable updates every class that uses it.

   DO NOT REDEFINE AN ELEMENTOR VARIABLE HERE. This file is enqueued long
   after the kit CSS, so anything restated here silently overrides the
   Variables panel and makes it inert. That has now happened twice: first with
   42 tokens on the original pass, then with four type-scale steps
   (--text-display-lg/md, --text-editorial-lg/md) that survived the cleanup
   because their values happened to match. Nothing looked wrong; editing them
   in Elementor simply did nothing.

   WHAT REMAINS BELOW, and why each one cannot be an Elementor variable:
     - Anything that changes at a breakpoint. Elementor emits :root once, with
       no media queries, so a value that ramps across viewports has to live in
       CSS: --gutter-page, --display-xl-ramp, --pef-hdr-h.
     - Unitless ratios (line-height, tracking, font-weight). The size variable
       type expects a unit.
     - Multi-part values: easing curves, the crest radius geometry, shorthand
       rules, the chevron artwork.
     - ch-based measures.
     - Compositions of other tokens (the approved pairs).
   ========================================================================= */
:root{

  /* -- Breakpoint-dependent --------------------------------------------
     Page gutter. ONE formula, previously retyped into eight rules — the
     header bar, the footer's three bands, the mega-menu panel, the mobile
     toggle, the mobile panel and the section wrapper. Everything on the page
     aligns to the logo because they all resolve to this.
       >=1025px : 51 -> 100 across 1025 -> 1440
       <=1024px : 20 ->  51 across  390 -> 1024  (see the media query below) */
  --gutter-page:clamp(51px, calc(51px + 49 * (100vw - 1025px) / 415), 100px);

  /* Hero display type, per Figma: 96 / 68 / 44. Named --display-xl-ramp, not
     --text-display-xl: the Elementor variable `text-display-xl` points AT
     this one, and a variable whose value referenced its own name would be
     self-referential and therefore invalid. This is the only step in the type
     scale needing two ramps, which is why it cannot live in the panel. */
  --display-xl-ramp:clamp(68px, calc(68px + 28 * (100vw - 1025px) / 415), 96px);

  /* Header height. THE single source of truth for it. Read by header-bar's
     own min-height (set on the global class as var(--pef-hdr-h)), by the
     mobile toggle and panel, and by --section-pad-top-hero, so the bar and
     everything that has to clear it cannot drift apart.
     pef-behaviour.js used to measure the bar and publish a second property,
     --pef-header-h. It agreed with this token at every breakpoint on every
     test, so it was two names for one number and has been removed. */
  --pef-hdr-h:106px;


  /* -- Fluid type that is not breakpoint-switched but is still a clamp ----
     (--text-display-lg/md and --text-editorial-lg/md are NOT here. They are
     Elementor variables; see the warning above.) */


  /* -- Unitless ratios -------------------------------------------------- */
  --display-lh:0.78;   --display-tracking:0em;
  --editorial-lh:0.95; --editorial-tracking:-0.02em;
  --body-lh:1.2;       --body-lh-long:1.5;
  --ui-lh:0.9;         --ui-tracking:0.02em;
  --ui-tracking-sm:0.06em;  /* 13px eyebrows carry more tracking than 15px UI */

  --weight-body:400; --weight-body-strong:700; --weight-display:800;

  /* -- Measures --------------------------------------------------------- */
  --measure:62ch;
  --measure-narrow:44ch;

  /* -- Shape geometry -- derived from the logo crest: a square whose lower
     half is a half-circle. Only correct on a square frame. --------------- */
  --crest:0 0 50% 50% / 0 0 100% 100%;
  --crest-up:50% 50% 0 0 / 100% 100% 0 0;
  --smile:0 0 9999px 9999px;
  --arch:9999px 9999px 0 0;
  --rule:1px solid var(--border-hairline);
  --shadow-none:none;   /* the brand builds depth with flat colour, never shadow */

  /* -- Artwork ---------------------------------------------------------
     The design-system chevron (11 x 5.5), drawn as a mask so it takes
     currentColor. Used by the mega-menu dropdown icon and the footer
     accordion; it was previously typed out four times (each site needs both
     the -webkit- and standard property). viewBox is cropped to the artwork —
     with the full 0 0 24 24 box, `contain` leaves ~44% of the width empty and
     the glyph renders about half size. */
  --icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='5.25 8.25 13.5 7.5'%3E%3Cpath d='M6 9l6 6 6-6' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");

  /* The CTA arrow, drawn rather than typed: Aptos Narrow Bold has no U+2197. */
  /* Card links point east: they go to another page on this site. */
  --icon-arrow-e:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M2.5 8h11M9 3.5 13.5 8 9 12.5' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");

  --icon-arrow-ne:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='1.5 1.5 9 9'%3E%3Cpath d='M2.6 9.4 9.4 2.6M4.3 2.6h5.1v5.1' fill='none' stroke='%23000' stroke-width='2.1' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");

  /* -- Motion -- brisk, never bouncy. Colours change, geometry does not. -- */
  --ease-out:cubic-bezier(0.22,0.61,0.36,1);
  --ease-expo:cubic-bezier(.16,1,.3,1);   /* the reveal/slide curve used site-wide */
  --dur-fast:120ms;   /* hover, colour swaps */
  --dur-base:220ms;   /* reveals, menu open */
  --dur-slow:420ms;
  --hover-lift:none;
  --press-scale:0.98;

  /* -- Mega menu. Deliberately slower and gentler than the tokens above, and
     the one place on the site that opts out of --ease-expo.
     --ease-expo front-loads hard — half the distance in the first ~11% of the
     time — which at 400ms reads as a snap followed by a crawl. That snap is
     the thing being fixed, so the menu uses plain CSS `ease` instead.
     --dur-menu-lag is the offset between the panel's surface and its contents.
     It is what makes the dropdown read as two layers unfolding rather than one
     block appearing, and it is the single biggest contributor to the feel.
     A hub-to-hub swap needs no duration of its own: it is the close motion and
     the open motion run at the same time, on the two panels involved. -- */
  --ease-menu:cubic-bezier(.25,.1,.25,1);   /* == CSS `ease` */
  --dur-menu:400ms;
  --dur-menu-lag:200ms;

  /* -- Approved pairs -- two colours per execution, every pair reversible.
     Compositions of the Elementor colour variables, not new values. Figma:
     "Every pair measures 2.9:1 to 3.4:1: display type only, never body copy."
     The homepage hero is primary reversed — lime ground, green display. */
  --pair-primary-bg:var(--pef-lime);      --pair-primary-fg:var(--pef-green);
  --pair-secondary-a-bg:var(--pef-lilac); --pair-secondary-a-fg:var(--pef-orange);
  --pair-secondary-b-bg:var(--pef-blue);  --pair-secondary-b-fg:var(--pef-lilac);
  --pair-tertiary-bg:var(--pef-lime);     --pair-tertiary-fg:var(--pef-blue);
  --pair-restricted-bg:var(--pef-black);  --pair-restricted-fg:var(--pef-white);
}

/* Below the desktop breakpoint the gutter ramps 20 -> 51 across 390 -> 1024,
   and the hero display type ramps 44 -> 68 over the same span. Both switch at
   1024, Elementor's tablet breakpoint, where the global classes switch too. */
@media (max-width:1024px){
  :root{
    --gutter-page:clamp(20px, calc(20px + 31 * (100vw - 390px) / 634), 51px);
    --display-xl-ramp:clamp(44px, calc(44px + 24 * (100vw - 390px) / 634), 68px);
  }
}

/* The header bar is shorter on mobile only. */
@media (max-width:767px){
  :root{--pef-hdr-h:64px;}
}


/* ============================================================================
   2. METRIC-MATCHED FALLBACKS
   ----------------------------------------------------------------------------
   To stop the nav reflowing when Adobe Fonts lands.

   The problem: font-family and font-size never change during load — both are
   already "aptos-narrow" at 15px. What changes is which font is drawn. Until
   the Typekit file arrives the browser uses plain sans-serif, which is 22%
   WIDER than Aptos Narrow (measured: 624px vs 512px for the same string),
   because Aptos Narrow is condensed and the fallback is not. Every nav label
   then snaps narrower at once, which reads as the type changing size and cost
   0.058 of layout shift.

   The fix: wrap the local fallback in an @font-face and scale it with
   size-adjust so it occupies almost exactly the same width as the real face.
   The percentages are measured, not guessed — real width / Arial width at the
   weights each family is actually used at:
     aptos-narrow 700 : 511.7 / 624.0 = 82%
     aptos 400        : 569.0 / 632.2 = 90%
   A separate 700 face is declared so bold text maps to real Arial Bold rather
   than a synthesised bold, which would be wider again and undo the match.

   These faces used to be slotted in by a second stylesheet that restated
   font-family on six selectors purely to append the fallback. The full stack
   is now written into the original declaration in each case, so there is one
   place per element rather than two, and no ordering requirement between them.
   ANY NEW RULE THAT NAMES A FONT MUST NAME THE FALLBACK TOO.
   ========================================================================= */
@font-face{
  font-family:"aptos-narrow-fb";
  src:local("Arial"),local("Helvetica Neue"),local("Liberation Sans");
  size-adjust:82%;
  font-weight:400;
  font-style:normal;
}
@font-face{
  font-family:"aptos-narrow-fb";
  src:local("Arial Bold"),local("Arial-BoldMT"),local("Helvetica Neue Bold"),local("Liberation Sans Bold");
  size-adjust:82%;
  font-weight:700;
  font-style:normal;
}
@font-face{
  font-family:"aptos-fb";
  src:local("Arial"),local("Helvetica Neue"),local("Liberation Sans");
  size-adjust:90%;
  font-weight:400;
  font-style:normal;
}
@font-face{
  font-family:"aptos-fb";
  src:local("Arial Bold"),local("Arial-BoldMT"),local("Helvetica Neue Bold"),local("Liberation Sans Bold");
  size-adjust:90%;
  font-weight:700;
  font-style:normal;
}


/* ============================================================================
   3. HEADER SHELL
   ========================================================================= */
.elementor-location-header{position:sticky;top:0;z-index:100;}

/* Figma NavBar: Scroll=Top carries no elevation; Scroll=Scrolled adds
   Elevation/Header (drop-shadow #31352D14, offset 0 1, radius 3). The
   header-bar global class applies the shadow at all times, so it is cleared
   at rest and reinstated once the is-scrolled hook fires.
   ONE rule for this. It was previously declared in three places — twice here
   under competing selectors and again in the transparent-header file — with
   two of the three carrying !important at each other. */
.elementor-location-header .header-bar{
  position:relative;
  box-shadow:none;
  transition:box-shadow .2s ease;
}
.elementor-location-header.is-scrolled .header-bar{
  box-shadow:0 1px 3px 0 rgba(49,53,45,.08);
}

/* The button treatments set `display:inline-flex` on .btn with no media
   query. That matches .elementor .is-hidden-mobile at equal specificity but
   lands later in source order, so it was defeating the mobile hide and the
   Apply button stayed in the bar. Utility class wins. */
@media (max-width:767px){
  .elementor .is-hidden-mobile{display:none !important;}
}

/* The logo is an inline SVG with a viewBox and no width attribute, so its
   min-content width is 0. As a shrinkable flex item any header overflow
   collapses it to nothing (which is exactly what the rule above caused). */
.elementor-location-header a.logo{flex-shrink:0;}


/* ============================================================================
   4. MEGA MENU — SHARED
   ----------------------------------------------------------------------------
   Two Elementor internals govern this widget:
   1. Never give .e-n-menu-content padding or a border. Elementor leaves that
      wrapper in flow when the panel is closed and hides only the inner
      container, so anything that gives it height becomes an invisible
      click-blocker across the page. It does take .e-active itself when open,
      so open-only styling is keyed off that and stays safe.
   2. Each panel container carries data-tab-index (set via the element's
      Attributes prop) — activateTab() filters on it, so without it the panel
      never receives .e-active and cannot open.
   The title rules need the .elementor-location-header .e-n-menu prefix to
   outrank the widget's own typography, which otherwise forces 16px/24px.
   ========================================================================= */
.elementor-location-header .e-n-menu .e-n-menu-title-text{font-family:"aptos-narrow","aptos-narrow-fb",sans-serif;font-weight:700;font-size:15px;line-height:.9;letter-spacing:.02em;text-transform:uppercase;color:#31352D;display:block;}

/* Mobile browsers paint a translucent tap flash over a control when it is
   touched, and Site Settings gives every <button> a 9999px radius, so it
   landed as a dark pill behind the MENU label and behind each chevron.
   Suppressed only on controls that already answer a tap in their own right —
   the toggle relabels itself MENU/CLOSE and slides the panel, the chevrons
   rotate and expand a row — so nothing is left with no feedback at all. Links
   and the CTA buttons deliberately keep theirs, since for them the tap flash
   is the only acknowledgement before the page changes. */
.e-n-menu-toggle,
.e-n-menu-dropdown-icon,
.footer-eyebrow{
  -webkit-tap-highlight-color:transparent;
}

/* Hub link items — Figma NavDropdown "Item" (4144:17):
   Label/Tag  = Aptos Narrow Bold, 15px (--text-ui-md), line-height .9, 0.3px tracking, uppercase
   Body/UI    = Aptos Regular,     14px (--text-body-sm), line-height 1.2, no tracking
   4px between the two, 12px padding each side of the row, and the divider is
   the full-strength charcoal hairline rather than a tint. Item height 58. */
.e-n-menu .mm-t{display:block;font-family:"aptos-narrow","aptos-narrow-fb",sans-serif;font-weight:700;font-size:15px;line-height:.9;letter-spacing:.02em;text-transform:uppercase;color:#31352D;}
.e-n-menu .mm-d{display:block;font-family:"aptos","aptos-fb",sans-serif;font-weight:400;font-size:14px;line-height:1.2;letter-spacing:0;color:#31352D;margin-block-start:4px;}
.mega-panel .elementor-icon-list-item{break-inside:avoid;}
.mega-panel .elementor-icon-list-item > a{display:block;padding-block:12px;border-block-end:1px solid #31352D;text-decoration:none;}
.mega-panel .elementor-icon-list-item > a:hover .mm-t{color:#14A14D;}

/* Elementor's caret icons swapped for the design-system chevron (11 x 5.5).
   Elementor sets an explicit height:24px on the button, which would drive the
   row past its 77px spec — height:auto lets the row keep its size, and the
   32/32 padding sits on the title link and the button rather than on the row
   so both are full-row-height touch targets. */
.e-n-menu-dropdown-icon svg{display:none;}
.elementor-location-header .e-n-menu .e-n-menu-dropdown-icon{
  background:none;border:0;cursor:pointer;padding:0;line-height:0;
  display:flex;align-items:center;justify-content:flex-end;
  height:auto;flex:0 0 auto;
}
.e-n-menu-dropdown-icon .e-n-menu-dropdown-icon-opened,
.e-n-menu-dropdown-icon .e-n-menu-dropdown-icon-closed{display:inline-flex;align-items:center;height:5.5px;}
.e-n-menu-dropdown-icon .e-n-menu-dropdown-icon-closed::after,
.e-n-menu-dropdown-icon .e-n-menu-dropdown-icon-opened::after{
  content:'';width:11px;height:5.5px;background-color:#31352D;
  -webkit-mask:var(--icon-chevron) center/contain no-repeat;
  mask:var(--icon-chevron) center/contain no-repeat;
}

/* THE CHEVRON CANNOT BE ANIMATED IN PLACE, and this is the third attempt at it.
   Elementor ships TWO caret spans, -opened and -closed, and swaps which one is
   display:none. No single element's transform ever changes, so a transition on
   either span -- or on their ::after, which is what used to be declared here --
   can never fire. Both spans have to stay in the DOM: their
   .elementor-screen-only text is the "Open X" / "Close X" announcement.

   The second attempt rotated the BUTTON, the one node that survives the swap.
   That works at >=1200, where the button box IS the 11 x 5.5 chevron. It cannot
   work at <=1199, where the button is a 44 x 69.5 touch target with the chevron
   at its inline end: rotating about the button's centre flings the caret across
   the row, and rotating about the caret's centre takes the TOUCH TARGET with
   it, 33px to the right and half of it past the screen edge -- so the control
   that collapses the row moves out from under the finger that just opened it.
   A transform moves the hit box, not just the paint.

   So script wraps the two spans in one .pef-chev at load (pef-behaviour.js).
   That wrapper is the only node that both survives the swap AND is exactly the
   chevron's own box, so transform-origin:center is right at every viewport and
   nothing that takes a tap ever moves. If the script does not run the chevron
   simply does not animate; nothing else depends on the wrapper. */
.e-n-menu-dropdown-icon .pef-chev{
  display:inline-flex;align-items:center;
  transition:transform var(--dur-menu) var(--ease-menu);
}
.e-n-menu-dropdown-icon[aria-expanded="true"] .pef-chev{transform:rotate(180deg);}
/* aria-expanded stays true for the whole script-driven collapse, so without
   this the caret would still be pointing up while its row rolled shut -- the
   same trap as the MENU/CLOSE label in section 6. */
.e-n-menu-item:has(.e-n-menu-content.pef-collapsing) .e-n-menu-dropdown-icon .pef-chev{transform:none;}


/* ============================================================================
   5. MEGA MENU — DESKTOP (>=1200)
   ----------------------------------------------------------------------------
   Two link columns + crest-masked feature image.
   Figma NavDropdown: 1240 content = 884 columns + 56 gap + 300 feature.
   The crest mask is a square top with a pill bottom, so it is plain
   border-radius rather than an SVG mask.

   The panel's inner content tracks the site container, --container (1440 in
   Site Settings), centred inside the bar's gutter. Capping the panel at that
   width + both gutters and centring it reproduces the header and footer
   alignment at every viewport, and reads the kit variable so it follows if
   the site width is ever changed. Deliberately no 100vw: that includes the
   scrollbar, which would sit the menu a few px right of everything else.
   The white surface stays full-bleed by living on .e-n-menu-content.e-active,
   and the panel's own shadow is dropped so the capped panel does not read as
   a floating card over it — the brand rules allow no shadows anyway.

   VERTICAL: Elementor anchors the dropdown to the menu TITLE (top:100%),
   which leaves it floating inside the header bar and clipping the logo. It is
   pushed down by --pef-menu-drop, measured in script as the distance from the
   menu heading's bottom to the header bar's bottom. That distance is not a
   constant — 38.3px on a one-row nav, 23.5px where the nav wraps to two rows
   — hence measuring rather than hard-coding. The heading gets an invisible
   bridge across the gap so travelling from a hub label down to the panel
   keeps the pointer inside .e-n-menu; it only exists while a panel is open
   and only spans the nav labels, so it never covers the CTAs.

   THE MENU BREAKPOINT IS 1200 AND IS STATED IN THREE PLACES: this block, the
   <=1199 block below, and pef-behaviour.js. Media queries cannot read a
   custom property, so it cannot be tokenised — if it changes, change all three.
   ========================================================================= */
@media (min-width:1200px){
  /* Elementor puts a 5px margin-inline-start on the toggle, and the label sits
     in a title with 16px side padding, so the chevron drifted 13px from its
     own label — nearly half the distance to the NEXT label, which is why it
     read as unattached. Figma's desktop NavBar carries no chevron at all, so
     there is no spec gap to copy; 4px groups it with its label. */
  /* The 4px is a MARGIN rather than padding so the button box is exactly the
     11 x 5.5 chevron. That was originally what made rotating the button itself
     viable here and nowhere else; the rotation has since moved to the .pef-chev
     wrapper (section 4) so it works at every viewport, but the margin stays
     because closing the gap is what it was always for. */
  .elementor-location-header .e-n-menu .e-n-menu-dropdown-icon{
    margin-inline-start:4px;
    padding-inline-start:0;
  }

  /* Hub label indicator. Grows from the left on the way in and collapses to
     the right on the way out — the origin flips between the two rules, which
     is what keeps it a continuous wipe rather than a rubber-band back.
     2px offset 4px is the design system's own TextLink hover rule (4241:185),
     already used by btn-text and the footer links; the reference draws 1px,
     but matching our own system beats matching the reference.
     It sits on the label span, not the title container, so it spans the words
     and not the clamp(8px,...,16px) side padding.
     currentColor, so section 10's transparent-header inversion carries it to
     white with no second rule.
     Fires on :hover as well as on open. That is deliberate and is half the fix
     for the dead dwell — the bar now answers the pointer on the first frame,
     before the script has decided whether to open anything. */
  .elementor-location-header .e-n-menu .e-n-menu-title-text{position:relative;}
  .elementor-location-header .e-n-menu .e-n-menu-title-text::after{
    content:'';position:absolute;
    inset-inline:0;inset-block-start:calc(100% + 4px);
    height:2px;background:currentColor;
    transform:scaleX(0);transform-origin:100% 50%;
    transition:transform var(--dur-menu) var(--ease-menu);
  }
  .e-n-menu-item:hover .e-n-menu-title-text::after,
  .e-n-menu-item:has(.e-n-menu-content.e-active) .e-n-menu-title-text::after{
    transform:none;transform-origin:0 50%;
  }

  /* Tighten the nav as the bar runs out of room, 1400 down to 1200.

     At 1440 the bar spends 619px on the menu: 384 of actual label, 75 of
     chevron, and 160 of padding — 16px either side of five titles. That
     padding is the cheapest thing to give back. Below 1400 it ramps 16 -> 8,
     freeing 80px, and the logo gap ramps 56 -> 32 for another 24px. Roughly
     104px of headroom by 1200, which is where the mobile menu takes over.

     Ramped rather than stepped so nothing jumps at a single width, and capped
     at the Figma values above 1400 so the design is untouched at full size. */
  .elementor-location-header .e-n-menu .e-n-menu-title{
    padding-inline:clamp(8px, calc(8px + 8 * (100vw - 1200px) / 200), 16px);
  }
  .elementor-location-header .nav-left{
    gap:clamp(32px, calc(32px + 24 * (100vw - 1200px) / 200), 56px);
  }

  /* pef-exit rides alongside .e-active everywhere the OPEN surface is described,
     because during the exit Elementor has already taken .e-active away. See the
     close block below for why the exit is stamped rather than inferred. */
  .e-n-menu-content.e-active,
  .e-n-menu-content.pef-exit{
    top:calc(100% + var(--pef-menu-drop, 0px)) !important;
    background:#FFFFFF;
    border-block-start:1px solid rgba(49,53,45,.14);
  }
  /* The invisible bridge that used to span --pef-menu-drop is gone. It existed
     only so a HOVER could travel from a hub label down to the panel without
     leaving .e-n-menu; the menu opens on click now, so the panel no longer
     cares where the pointer is — and left in place the bridge would swallow
     the click-outside that closes it. */
  .e-n-menu-heading{position:relative;}
  /* Panel padding is owned here, not by the mega-panel global class: the
     class cannot express the gutter ramp (it would have to hard-code the
     desktop half of the clamp, which is then wrong below 1025). The class
     carries only what it can state honestly — surface, direction, width. */
  .elementor-location-header .e-n-menu .e-n-menu-content > .mega-panel{
    padding:var(--space-6) var(--gutter-page) var(--space-7) !important;
    max-width:calc(var(--container) + 200px);
    margin-inline:auto;
    box-shadow:none;
    background:transparent;
  }
  .mega-panel.e-active,
  .mega-panel.pef-exit{display:flex !important;flex-direction:row !important;gap:56px;align-items:flex-start;}
  .mega-panel > .elementor-widget-icon-list{flex:1 1 auto;min-width:0;}
  .mega-panel .elementor-icon-list-items{columns:2;column-gap:56px;}
  .mega-panel > .e-image-base{
    flex:0 0 300px;width:300px;height:300px;object-fit:cover;
    border-radius:var(--smile);align-self:flex-start;
  }

  /* ---- Open motion: TWO LAYERS, OFFSET ------------------------------------
     The surface and its contents are animated as separate layers, with the
     contents lagging by --dur-menu-lag. That offset is the whole effect: the
     white unrolls from under the header, and only once it is on its way does
     the content settle into it. Animated together — which is what this did
     before — the panel reads as one block appearing, however long you give it.

     The surface stays a CLIP rather than a fade. Fading a white sheet over
     live page content lets the hero type ghost through it; clipping never
     shows a partially transparent surface at all.

     NOTHING here transitions `display`. Elementor opens a panel by writing an
     inline `display: var(--display)`, and a transition on display turns that
     step into a discrete transition of its own: the panel sat at display:block
     for ~80ms on first open, laying the feature image out under the links
     before the flex rule took hold, so the image visibly jumped into place.

     Timings are stated as tokens because pef-behaviour.js has to hold the exit
     open for exactly as long as this takes — see CLOSE_ANIM there. */
  .mega-panel{
    --display:flex;
  }
  .e-n-menu-content{
    clip-path:inset(0 0 100% 0);
    transition:clip-path var(--dur-menu) var(--ease-menu);
  }
  .e-n-menu-content.e-active{clip-path:inset(0 0 0 0);}

  /* The travel lives on the contents, not on the panel. It used to be a 6px
     settle on .mega-panel, with the links fading on top, which the old comment
     rightly called two competing motions — so the panel is now a static box and
     the links and image are the only things that move. 20px, matching the
     reference: enough to read as arriving, not so far it looks thrown. */
  .mega-panel .elementor-icon-list-item,
  .mega-panel > .e-image-base{
    opacity:0;
    transform:translateY(-20px);
    transition:opacity var(--dur-menu) var(--ease-menu),
               transform var(--dur-menu) var(--ease-menu);
  }
  .mega-panel.e-active .elementor-icon-list-item,
  .mega-panel.e-active > .e-image-base{
    opacity:1;transform:none;
    transition-delay:var(--dur-menu-lag);
  }

  /* NO STAGGER, deliberately. There was a 28ms-per-link one here. On top of
     the 200ms layer offset it pushed the eighth link out past 800ms, and it is
     what forced the hub swap below to be a hard cut — links mid-stagger cannot
     be crossfaded. The offset above does the layering on its own.
     --pef-li was read only by that rule and is no longer set in the script.

     ---- Close: the same two layers, in the opposite order -------------------
     Contents leave immediately, the surface follows --dur-menu-lag behind, so
     the panel empties before it rolls up instead of the clip guillotining a
     full set of links.

     THE EXIT IS STAMPED ON THE PANEL (pef-exit), NOT KEYED ON .e-active.
     Elementor drops .e-active and sets display:none in the same tick, and on
     its own click-outside path it does so without telling us — measured at 2ms
     after our class landed. Anything that needed .e-active to survive the close
     therefore never played. pef-exit keeps the panel rendered and animates it
     out independently, so Elementor is free to close by any route it likes.
     display:flex !important beats Elementor's inline display:none: an important
     author rule outranks a non-important inline one. */
  .e-n-menu-content.pef-exit{
    display:flex;
    clip-path:inset(0 0 100% 0);
    transition-delay:var(--dur-menu-lag);
  }
  .mega-panel.pef-exit .elementor-icon-list-item,
  .mega-panel.pef-exit > .e-image-base{
    opacity:0;transform:translateY(-20px);
    transition-delay:0s;
  }

  /* ---- Hub swap: a true cross-fade over a surface that holds still --------
     Each hub owns a separate wrapper, so moving between hubs is really a close
     plus an open, and BOTH panels are animated at once — the outgoing one
     leaves while the incoming one arrives, which is the motion the reference
     runs and what makes a swap read as one gesture rather than a cut.

     Measured on ekodeck.com.au, swapping hub A for hub B:
       outgoing contents  opacity 1 -> 0, translateY 0 -> -20px, 0-400ms
       incoming contents  opacity 0 -> 1, translateY -20px -> 0, 200-600ms
     which is exactly our close motion and our open motion, run together. So
     neither is restated here: the outgoing panel carries pef-exit and uses the
     close rules above, the incoming one carries .e-active and uses the open
     rules. This block only has to stop the two SURFACES from animating.

     Both wrappers are open at once during the swap. THE ORDER THEY PAINT IN IS
     THE WHOLE TRICK, and getting it wrong is silent: every wrapper carries the
     same z-index (2147483620, Elementor's) and the same opaque white, and the
     incoming panel is LATER IN THE DOM — so left alone it paints straight over
     the outgoing one and hides the entire fade-out. The contents were measured
     animating correctly while the screen showed ~200ms of blank white, because
     computed styles cannot see one element covering another. Check pixels.

     So during a swap the exiting panel is lifted one above the incoming one and
     has its surface taken away: the INCOMING panel supplies the white, which
     holds still because every panel is the same 372px (the 300px feature image
     sets it), and the outgoing contents fade out on top of it in full view.
     Its border goes too — two 1px hairlines at rgba(...,.14) stacked would read
     as one darker line for the length of the swap.
     The outgoing panel is held fully open throughout, because letting its clip
     retract would cut its contents away mid-fade. The incoming one opens with
     no wipe, or the white re-animates on every hub. */
  .e-n-menu.pef-swapping .e-n-menu-content{
    transition-duration:0s !important;
    transition-delay:0s !important;
  }
  .e-n-menu.pef-swapping .e-n-menu-content.pef-exit{
    clip-path:inset(0 0 0 0);
    background:transparent;
    border-block-start-color:transparent;
    z-index:2147483621;
  }
}


/* ============================================================================
   6. MEGA MENU — COMPACT (<=1199)
   ----------------------------------------------------------------------------
   Full-screen panel, Figma MobileMenu 4079:65.
   ========================================================================= */
@media (max-width:1199px){
  /* Figma's mobile menu is links only — no feature image. */
  .mega-panel > .e-image-base{display:none;}

  /* Sentence-case body type for the labels, and the MENU/CLOSE toggle drawn
     in ::after content. */
  .e-n-menu .mega-panel .mm-t{font-family:"aptos","aptos-fb",sans-serif;font-weight:400;font-size:16px;line-height:1.5;letter-spacing:0;text-transform:none;color:#31352D;}
  .e-n-menu .mm-d{display:none;}

  .elementor-location-header .e-n-menu-toggle,
  .elementor-location-header .e-n-menu-toggle:hover,
  .elementor-location-header .e-n-menu-toggle:focus,
  .elementor-location-header .e-n-menu-toggle:active,
  .elementor-location-header .e-n-menu-toggle[aria-expanded="true"]{
    background:none !important;border:0;box-shadow:none;
  }
  /* The toggle sits inside the menu widget on the left of the bar, and every
     e-con ancestor is position:relative — so it is pinned with position:fixed
     against the sticky header rather than absolutely.
     inset-inline-end is var(--gutter-page), NOT a copy of the mobile half of
     that clamp. It used to be the copy, which meant that between 1025 and
     1199 — where the menu is compact but the gutter is still on its DESKTOP
     ramp — the toggle sat up to 20.5px inboard of the logo it was supposed to
     line up with. */
  .elementor-location-header .e-n-menu-toggle{
    display:flex;
    align-items:center;
    justify-content:flex-end;
    padding:0;cursor:pointer;
    position:fixed;
    inset-block-start:0;
    height:var(--pef-hdr-h);
    inset-inline-end:var(--gutter-page);
    z-index:101;
  }
  .elementor-location-header .e-n-menu-toggle .e-n-menu-toggle-icon{display:none;}
  /* MENU and CLOSE cross-fade in place.
     CLOSE is kept IN FLOW so the button is always exactly as wide as the
     longer of the two words, and MENU is absolutely positioned over it. Do not
     be tempted to put both in one grid cell instead: Elementor sets `display`
     on this button at equal specificity and loads after this file, so
     display:grid silently loses the cascade, the two words lay out side by
     side, the button doubles to 82px, MENU shifts left of its position and the
     box overlaps the Donate button and steals its taps. Flow-plus-absolute
     does not care what `display` ends up being. */
  .elementor-location-header .e-n-menu-toggle::before,
  .elementor-location-header .e-n-menu-toggle::after{
    color:#31352D;
    font-family:"aptos-narrow","aptos-narrow-fb",sans-serif;
    font-weight:700;font-size:15px;line-height:.9;letter-spacing:.02em;
    transition:opacity .18s ease;
  }
  .elementor-location-header .e-n-menu-toggle::before{content:'CLOSE';opacity:0;}
  .elementor-location-header .e-n-menu-toggle::after{
    content:'MENU';
    position:absolute;
    inset-inline-end:0;
    inset-block-start:50%;
    transform:translateY(-50%);
    opacity:1;
  }
  .elementor-location-header .e-n-menu-toggle[aria-expanded="true"]::before{opacity:1;}
  .elementor-location-header .e-n-menu-toggle[aria-expanded="true"]::after{opacity:0;}

  /* Closing holds aria-expanded true for the whole 300ms panel slide, so
     keying the label only off that attribute left the button reading CLOSE
     until the panel had gone and MENU did not finish returning for ~480ms
     after the tap. The closing class swaps the word back at the START of the
     exit, so the label and the panel move as one gesture. Four classes, so it
     outranks the aria-expanded rules above. */
  .elementor-location-header .e-n-menu.pef-menu-closing .e-n-menu-toggle::before{opacity:0;}
  .elementor-location-header .e-n-menu.pef-menu-closing .e-n-menu-toggle::after{opacity:1;}

  /* Donate stays in the bar at all times, so the bar keeps clear of the
     pinned toggle. */
  .elementor-location-header .header-nav{padding-inline-end:74px;}

  /* The full-screen panel.
     CRITICAL: this is what the panel looks like OPEN, but it cannot be applied
     only when open — display:flex !important would then override Elementor's
     hidden state and leave a full-screen white sheet over the whole site with
     the menu shut, swallowing every tap. So the box is always built, and
     open/closed is expressed with clip-path plus visibility and pointer-events,
     which is also what makes it animatable: there is no display toggle to
     fight. Closed it is fully clipped, invisible, inert and out of the
     accessibility tree.

     TWO LAYERS, ONE LAG -- the same construction as the desktop panel, and the
     whole of what makes either of them feel considered. The white surface wipes
     down over --dur-menu; its contents follow --dur-menu-lag behind it, so the
     panel reads as a sheet being drawn over the page with the menu arriving on
     it rather than as one flat box appearing. Closing reverses the order for
     free: contents out first, surface up after them.

     The 45ms-per-row stagger this replaces is deliberately gone. Measured, it
     put the last row 501ms out from the tap, and a six-step ramp down an 844px
     screen reads as six events rather than one gesture. The reference
     (ekodeck.com.au, measured at 390) staggers nothing at all -- its whole
     mobile panel moves as a single layer over 400ms -- and the desktop panel
     here dropped its own stagger for the same reason. Rows travelling together
     IS the group moving. --pef-i / --pef-ri / --pef-n were read only by those
     rules and are no longer set in script. */
  .elementor-location-header .e-n-menu-wrapper{
    position:fixed !important;
    inset-block-start:var(--pef-hdr-h) !important;
    inset-inline:0 !important;
    inset-block-end:0 !important;
    width:auto !important;
    max-width:none !important;
    background:#FFFFFF !important;
    display:flex !important;
    flex-direction:column !important;
    overflow-y:auto;
    padding:0 var(--gutter-page) 12px;
    clip-path:inset(0 0 100% 0);
    visibility:hidden;
    pointer-events:none;
    transition:clip-path var(--dur-menu) var(--ease-menu),
               visibility 0s linear calc(var(--dur-menu) + var(--dur-menu-lag));
  }
  .elementor-location-header .e-n-menu:has(.e-n-menu-toggle[aria-expanded="true"]) .e-n-menu-wrapper{
    clip-path:inset(0 0 0 0);
    visibility:visible;
    pointer-events:auto;
    transition:clip-path var(--dur-menu) var(--ease-menu), visibility 0s;
  }
  /* Closing is script-driven. aria-expanded flips the instant Elementor is
     told to close, which stops the :has() rule matching, so the panel would
     jump shut with nothing left to animate. The surface waits --dur-menu-lag so
     the rows are already gone before it starts travelling. */
  .elementor-location-header .e-n-menu.pef-menu-closing .e-n-menu-wrapper{
    clip-path:inset(0 0 100% 0) !important;
    transition-delay:var(--dur-menu-lag) !important;
  }

  /* The contents layer: every row and the relocated Apply CTA, moving as one.
     They start 12px high and settle DOWN through the descending surface -- the
     same direction as the wipe, which is what reads as being revealed by it
     rather than arriving independently of it. Matches the desktop panel, whose
     links come from -20px under the same curtain. */
  .e-n-menu-item{
    opacity:0;
    transform:translateY(-12px);
    transition:opacity var(--dur-menu) var(--ease-menu),
               transform var(--dur-menu) var(--ease-menu);
  }
  .elementor-location-header .e-n-menu:has(.e-n-menu-toggle[aria-expanded="true"]) .e-n-menu-item{
    opacity:1;transform:none;
    transition-delay:var(--dur-menu-lag);
  }
  .elementor-location-header .e-n-menu.pef-menu-closing .e-n-menu-item{
    opacity:0 !important;transform:translateY(-12px) !important;
    transition-delay:0s !important;
  }

  /* Figma pins both CTAs to the foot of the open menu because the 390 bar has
     no room for Apply. Donate is deliberately NOT relocated — it stays in the
     header bar so giving is reachable at every moment, menu open or shut — so
     only Apply moves down, and this reverses the is-hidden-mobile that hides
     it in the bar. The live node is moved rather than duplicated, so there is
     still exactly one Apply button for the client to edit. */
  .elementor-location-header .pef-cta-in-menu{
    display:flex !important;
    align-items:center;justify-content:center;
    margin-block-start:auto;
    margin-block-end:12px;
    width:100%;
    min-height:44px;
    box-sizing:border-box;
    opacity:0;
    transform:translateY(-12px);
    transition:opacity var(--dur-menu) var(--ease-menu),
               transform var(--dur-menu) var(--ease-menu);
  }
  .elementor-location-header .e-n-menu:has(.e-n-menu-toggle[aria-expanded="true"]) .pef-cta-in-menu{
    opacity:1;transform:none;
    transition-delay:var(--dur-menu-lag);
  }
  .elementor-location-header .e-n-menu.pef-menu-closing .pef-cta-in-menu{
    opacity:0 !important;transform:translateY(-12px) !important;
    transition-delay:0s !important;
  }

  /* Elementor ships full-viewport-width rows and a 16px inset on the title;
     both are overridden so rows align to the panel gutter. Figma: 32/32
     padding on a 77px row, solid hairline per row, none on the last. */
  .e-n-menu-heading{flex-direction:column;width:100%;align-items:stretch;flex:0 0 auto;}
  .e-n-menu-item{width:100% !important;max-width:100%;box-sizing:border-box;border-block-end:1px solid #31352D;}
  .e-n-menu-item:last-child{border-block-end:0;}
  .e-n-menu-title{display:flex;align-items:center;justify-content:space-between;width:100%;max-width:100%;box-sizing:border-box;padding:0 !important;border-block-end:0;}
  .e-n-menu-title-container{flex:1 1 auto;text-decoration:none;display:flex;align-items:center;padding:32px 0;}
  .elementor-location-header .e-n-menu .e-n-menu-dropdown-icon{padding:32px 0 32px 12px;min-width:44px;margin-inline-start:0;}

  /* Accordion expand -- two layers again, so a row opens the way the panel
     does and the whole menu speaks at one pace. A row has no fixed height, so
     the SURFACE is the grid 0fr-to-1fr technique rather than max-height
     guesswork; the panel needs min-height:0 and overflow:hidden for the track
     to actually compress it. The links inside are the CONTENTS and follow
     --dur-menu-lag behind, travelling down out of the row's own top edge.

     THREE ways a row closes, and only one of them was ever handled:
       pef-collapsing -- the user tapped the open row's own chevron. Script
         holds the click for the full animation, so Elementor has not closed
         anything yet and the panel is still displayed.
       pef-exit -- the user tapped a DIFFERENT row. Elementor closes this one
         itself and stamps display:none INLINE on the panel, which measured as
         a hard snap: the previous row vanished in the same frame the next one
         was asked for, with no animation at all. The class keeps it rendered
         -- an !important author rule beats a non-important inline one -- so it
         can roll up while the new row opens. Same construction as the desktop
         hub-to-hub swap, for exactly the same reason.
       neither -- reduced motion, or script that never ran. The base rule still
         applies: instant at :reduce, a plain 0fr transition otherwise.
     Both stamped cases sequence like everything else: contents out first,
     surface --dur-menu-lag behind them. */
  .e-n-menu-content{
    display:grid !important;
    grid-template-rows:0fr;
    transition:grid-template-rows var(--dur-menu) var(--ease-menu);
  }
  .e-n-menu-content.e-active{grid-template-rows:1fr;}
  .e-n-menu-content > .mega-panel{min-height:0;overflow:hidden;}

  .e-n-menu-content .mega-panel .elementor-icon-list-item{
    opacity:0;
    transform:translateY(-8px);
    transition:opacity var(--dur-menu) var(--ease-menu),
               transform var(--dur-menu) var(--ease-menu);
  }
  .e-n-menu-content.e-active .mega-panel .elementor-icon-list-item{
    opacity:1;transform:none;
    transition-delay:var(--dur-menu-lag);
  }
  /* After the .e-active rules, deliberately: both carry the same specificity,
     and for the one tick before Elementor drops .e-active these have to win on
     source order or the exit never starts. */
  .e-n-menu-content.pef-collapsing,
  .e-n-menu-content.pef-exit{
    grid-template-rows:0fr;
    transition-delay:var(--dur-menu-lag);
  }
  .e-n-menu-content.pef-exit > .mega-panel{display:flex !important;}
  .e-n-menu-content.pef-collapsing .mega-panel .elementor-icon-list-item,
  .e-n-menu-content.pef-exit .mega-panel .elementor-icon-list-item{
    opacity:0;transform:translateY(-8px);
    transition-delay:0s;
  }

  /* Children: Body/Default 16px sentence case, indented 12px, 4px gap.
     Figma's 32px of breathing space under the children sits on the LIST, not
     the panel. On the panel it was outside the clipped box, so a collapsing
     row bottomed out at 32px and hung there until the script closed it — a
     visible snap at the end of every collapse, the same trap as the footer
     accordion's 18px. It needs the extra specificity and !important because
     Elementor's icon-list stylesheet resets the list's padding to 0 at equal
     weight and loads after this file. */
  .elementor .mega-panel{--display:flex;padding:0 0 0 12px !important;box-shadow:none !important;border-block-start:0 !important;transform:none;}
  .e-n-menu-content .mega-panel .elementor-icon-list-items{
    columns:auto;display:flex;flex-direction:column;gap:4px;
    padding-block-end:32px !important;
  }
  .mega-panel .elementor-icon-list-item > a{border-block-end:0;padding:0;}
}


/* ============================================================================
   7. FOOTER
   ----------------------------------------------------------------------------
   Link and social hover, then the mobile accordion.

   Figma TextLink (4241:185) draws three states: Default, Hover and Focus.
   Hover is a colour swap PLUS an underline — var(--rule-thick) 2px, offset by
   var(--space-1) 4px. The Hover variant is 4px taller than Default in the
   file, which is that underline.

   Figma draws it green-on-white, swapping to charcoal. The footer is the
   inverse — white on green — so the swap goes to lime, the paired accent for
   that ground (4.33:1 on the green). The underline is what actually carries
   the state: white and lime are only 1.13:1 apart, so on colour alone the
   change would be easy to miss.

   Excludes .btn (the CTAs own their hover) and .e-svg-base (the footer logo,
   which must not gain an underline). Social icons are handled separately
   below since they have no text to underline.

   :focus-visible throughout, so keyboard users get the same affordance —
   WCAG 2.4.7. The ring is white rather than the usual blue, because
   --focus-ring #0081F3 measures 1.26:1 on this green and is invisible.
   ========================================================================= */
.elementor-location-footer a:not(.btn):not(.e-svg-base){
  transition:color var(--dur-fast) ease-out;
}
.elementor-location-footer a:not(.btn):not(.e-svg-base):hover,
.elementor-location-footer a:not(.btn):not(.e-svg-base):focus-visible{
  color:var(--pef-lime);
}

/* The rule is drawn as a pseudo-element rather than text-decoration, because
   text-decoration cannot be animated — it can only switch on. This wipes in
   from the left on the expo curve used elsewhere for reveals.

   It sits on the SPAN, not the anchor. Elementor's icon-list anchors are
   flex and stretch to the column (84px for "Impact"), while the span hugs the
   text (49px), so on the anchor the rule would overshoot past the word.

   Geometry still matches Figma TextLink: 2px thick (--rule-thick), 4px below
   the baseline box (--space-1). currentColor means it inherits the lime swap
   without restating the value. */
.elementor-location-footer a:not(.btn):not(.e-svg-base) .elementor-icon-list-text{
  position:relative;
}
.elementor-location-footer a:not(.btn):not(.e-svg-base) .elementor-icon-list-text::after{
  content:'';
  position:absolute;
  inset-inline:0;
  inset-block-end:-4px;
  height:2px;
  background-color:currentColor;
  transform:scaleX(0);
  transform-origin:left center;
  transition:transform .32s var(--ease-expo);
}
.elementor-location-footer a:not(.btn):not(.e-svg-base):hover .elementor-icon-list-text::after,
.elementor-location-footer a:not(.btn):not(.e-svg-base):focus-visible .elementor-icon-list-text::after{
  transform:scaleX(1);
}
/* Elementor wraps icon-list link text in a span, and the footer-link class
   colours it white, so the colour has to be set on the span as well as the
   anchor or only unwrapped links would change. */
.elementor-location-footer a:not(.btn):not(.e-svg-base):hover .elementor-icon-list-text,
.elementor-location-footer a:not(.btn):not(.e-svg-base):focus-visible .elementor-icon-list-text,
.elementor-location-footer a:not(.btn):not(.e-svg-base):hover .footer-link,
.elementor-location-footer a:not(.btn):not(.e-svg-base):focus-visible .footer-link{
  color:var(--pef-lime);
}
.elementor-location-footer a:not(.btn):focus-visible{
  outline:2px solid var(--pef-white);
  outline-offset:3px;
}

/* Social icons. The artwork carries fill="white" as a presentation attribute
   on its paths, which any CSS rule outranks. No text, so the colour swap is
   the whole signal. */
.elementor-location-footer a.social-icon svg,
.elementor-location-footer a.social-icon svg *{
  transition:fill var(--dur-fast) ease-out;
}
.elementor-location-footer a.social-icon:hover svg *,
.elementor-location-footer a.social-icon:focus-visible svg *{
  fill:var(--pef-lime);
}

/* ---- Footer accordion (mobile) ---- */
@media (max-width:767px){
  /* Social row sits under the brand block, per the Figma Layout=Accordion variant.
     margin-block-end 37 + the icon's own 11px margin = 48 above the accordion block,
     matching the 48 below it. */
  .footer-groups > .footer-group:last-child{order:1;margin-block-end:37px;}
  .footer-groups > .footer-group{order:2;}

  /* The accordion rows are a continuous list separated by hairlines, so the grid
     gap is removed and each row's own padding is the only spacing. */
  .elementor .footer-groups{gap:0;}
  .footer-groups > .footer-group:not(:last-child){
    border-block-end:1px solid rgba(255,255,255,.24);
    padding-block:18px;
    gap:0;
  }
  .footer-groups > .footer-group:not(:last-child) > .footer-eyebrow{
    position:relative;
    width:100%;
    cursor:pointer;
    padding-inline-end:30px;
    user-select:none;
  }
  .footer-groups > .footer-group:not(:last-child) > .footer-eyebrow::after{
    content:'';
    position:absolute;
    inset-inline-end:0;
    top:50%;
    width:14px;
    height:8px;
    margin-block-start:-4px;
    background-color:currentColor;
    transition:transform .22s var(--ease-expo);
    -webkit-mask:var(--icon-chevron) center/contain no-repeat;
    mask:var(--icon-chevron) center/contain no-repeat;
  }
  .footer-groups > .footer-group.is-open > .footer-eyebrow::after{transform:rotate(180deg);}

  /* The row collapses with the grid 0fr-to-1fr technique rather than a display
     toggle, so both directions animate. visibility is what actually keeps a
     closed row out of the tab order and the accessibility tree — a zero-height
     grid track still contains focusable links, which display:none used to
     handle for free. It is delayed on the way out so it only applies once the
     collapse has finished. */
  .footer-groups > .footer-group:not(:last-child) > .footer-links{
    display:grid !important;
    grid-template-rows:0fr;
    visibility:hidden;
    transition:grid-template-rows .28s var(--ease-expo), visibility 0s linear .28s;
  }
  .footer-groups > .footer-group.is-open > .footer-links{
    grid-template-rows:1fr;
    visibility:visible;
    transition:grid-template-rows .28s var(--ease-expo), visibility 0s;
  }
  .footer-groups > .footer-group:not(:last-child) > .footer-links > *{
    min-height:0;
    overflow:hidden;
  }
  /* The 18px breathing space goes on the list itself, INSIDE the clipped box.
     On the grid item it sat outside the clip and left every collapsed row 18px
     tall instead of closing flush. */
  .footer-groups > .footer-group:not(:last-child) > .footer-links .elementor-icon-list-items{
    padding-block-start:18px !important;
  }

  /* Links fade in one by one behind the row opening. --pef-fi is set in script.
     They fade out together rather than in reverse: a staggered exit competes
     with the collapse, which is already moving everything upward. */
  .footer-groups > .footer-group:not(:last-child) .elementor-icon-list-item{
    opacity:0;
    transition:opacity .2s ease-out;
  }
  .footer-groups > .footer-group.is-open .elementor-icon-list-item{
    opacity:1;
    transition-delay:calc(var(--pef-fi,0) * 40ms);
  }

  /* Utility block stacks and left-aligns on mobile.
     Needs .elementor to beat the global class at equal specificity. */
  .elementor .legal-stack{align-items:flex-start;}
  .elementor .legal-line{text-align:left;}
  .elementor .utility-row{gap:8px;}
}


/* ============================================================================
   8. BUTTONS
   ----------------------------------------------------------------------------
   The button system lives in Elementor, not here:

     VALUES   -> Elementor Variables  (--btn-pad-x, --btn-pad-y, --radius-pill,
                 --border-width, --text-ui-md, --font-ui, and the colours)
     RECIPES  -> Elementor Global Classes
                   `btn`            geometry + type, referencing the variables
                   `btn-primary`    colour pairing only, plus its hover state
                   `btn-outline`    "
                   `btn-secondary`  " (square, tighter side padding)
                   `btn-text`       "
                   `btn-outline-light` / `btn-accent`  on-dark pair

   Every button carries TWO classes: `btn` plus one variant. To change padding
   on all buttons, edit --btn-pad-x / --btn-pad-y in the Variables panel. To
   change one treatment's colour, edit that variant in the Class Manager.
   Nothing below restates any of that — if a value appears here as well as in
   a class, this file wins on source order and the Class Manager is lying.

   Class Manager ORDER matters: `btn` is ordered first, so the variants (which
   sit at the same (0,2,0) specificity) override it. Do not reorder it below
   the variants.

   WHAT REMAINS HERE, and why each one cannot be a class:
     1. the font fallback  — the `font-ui` variable names one family; the
                             metric-matched fallback has to follow it
     2. the CTA arrow      — a ::after pseudo-element, not a state
     3. the Ghost underline— likewise
     4. unclassed fallback — a :not() selector, not a state
     5. motion + press     — transition/transform are not style props, and
                             prefers-reduced-motion is not an Elementor breakpoint
     6. a few shorthands Elementor's schema has no prop for (white-space,
        text-decoration, cursor, box-sizing, outline)
   ========================================================================= */

/* --- 1 + 6. Font fallback, and the properties with no Elementor prop -----
   One rule covering every button, classed or not. This replaced a six-selector
   list that named each variant individually and had gone stale — `btn` and
   `btn-secondary` were both missing from it, so neither picked up the
   metric-matched fallback. */
.elementor .btn,
.elementor .e-button-base{
  font-family:"aptos-narrow","aptos-narrow-fb",sans-serif;
  box-sizing:border-box;
  text-decoration:none;
  white-space:nowrap;
  cursor:pointer;
}

/* --- 5. Motion ----------------------------------------------------------
   From the Figma component description: "Hover colour swap only. Geometry
   never moves (--hover-lift: none)." and "Active press. Same colours as Hover
   PLUS transform: scale(0.98)". Only the four animatable properties are
   listed — `all` would sweep in box-shadow and undo "no shadows". */
.elementor .btn{
  transition:background-color var(--dur-fast) ease-out,
             color var(--dur-fast) ease-out,
             border-color var(--dur-fast) ease-out,
             transform var(--dur-fast) ease-out;
}
.elementor .btn:active{transform:scale(var(--press-scale));}

/* --- 3. Ghost underline --------------------------------------------------
   Figma's TextLink (4241:185) hover is a colour swap PLUS a 2px rule offset
   4px — and Ghost is the button system's counterpart of that link, so it takes
   the same treatment. Same implementation as the footer links above: a
   pseudo-element that wipes in from the left, because text-decoration can
   only switch on, never animate.

   Ghost is the one variant where this is safe to hang off the anchor rather
   than an inner span: btn-text zeroes the padding and min-height it inherits
   from `btn`, and inline-flex hugs its content, so the box IS the text box.
   currentColor means the rule follows the swap to --text-link without
   restating it. No conflict with the arrow below — Ghost carries no arrow. */
.elementor .btn-text{
  position:relative;
}
.elementor .btn-text::after{
  content:'';
  position:absolute;
  inset-inline:0;
  inset-block-end:-4px;
  height:2px;
  background-color:currentColor;
  transform:scaleX(0);
  transform-origin:left center;
  transition:transform .32s var(--ease-expo);
}
.elementor .btn-text:hover::after,
.elementor .btn-text:focus-visible::after{
  transform:scaleX(1);
}

/* --- 2. CTA arrow ------------------------------------------------------- */
.elementor .btn-outline::after,
.elementor .btn-outline-light::after{
  content:'';display:inline-block;width:.62em;height:.62em;
  margin-inline-start:.34em;vertical-align:-.02em;
  background-color:currentColor;
  -webkit-mask:var(--icon-arrow-ne) center/contain no-repeat;
  mask:var(--icon-arrow-ne) center/contain no-repeat;
}

/* --- Disabled -----------------------------------------------------------
   Styled off aria-disabled because these are anchors, which never match
   :disabled. Elementor also offers an `e--disabled` CLASS state, which would
   move this into the Class Manager — but it requires the element to carry
   that class, which nothing does yet. The low contrast is deliberate and
   exempt under WCAG 1.4.3; the point is that a dead control must not look
   pressable. aria-disabled alone does not stop an anchor being followed —
   whoever marks one disabled must also remove href or intercept the click. */
.elementor .btn[aria-disabled="true"],
.elementor button.btn:disabled{
  background-color:var(--surface-disabled) !important;
  color:var(--text-disabled) !important;
  border-color:transparent !important;
  cursor:not-allowed;
  transform:none;
}

/* --- 4. Unclassed fallback ----------------------------------------------
   Elementor v4 atomic buttons ignore Site Settings > Buttons entirely — its
   rules compile to `.elementor-kit-7 button, .elementor-button` and an atomic
   button is an <a class="e-button-base">, so it matches none of them. Left to
   itself it takes `.elementor .e-button-base{background:#375EFB;padding:12px
   24px}` and comes out Elementor blue.

   So anything dropped on a page without the `btn` class still needs a sane
   default. It inherits the Inverted treatment. This is a safety net, not part
   of the system: the correct markup is always `btn` + a variant.

   `.card-link` is excluded because it is an atomic button element used as a
   LINK, not a button (Figma treats TextLink and Button as separate
   components). Without the exclusion it would inherit the charcoal pill.
   KEEP THIS CHAIN SHORT. An earlier version listed five variant names, went
   stale, and silently swallowed every class that was not added to it. Two
   names is the ceiling; anything more means the fallback is the wrong tool. */
.elementor .e-button-base:not(.btn):not(.card-link){
  display:inline-flex;align-items:center;justify-content:center;
  min-height:44px;
  background-color:var(--pef-charcoal);
  color:var(--pef-white);
  border:var(--border-width) solid var(--pef-charcoal);
  border-radius:var(--radius-pill);
  padding:var(--btn-pad-y) var(--btn-pad-x);
  font-weight:700;font-size:var(--text-ui-md);line-height:.9;letter-spacing:.02em;
  text-transform:uppercase;
}
.elementor .e-button-base:not(.btn):not(.card-link):hover{
  background-color:transparent;color:var(--pef-charcoal);
}


/* ============================================================================
   12. CARDS
   ----------------------------------------------------------------------------
   The card LAYOUTS live in Elementor: `card-shell`, `badge`, `card-link` and
   `card-media-crest` / `-square` / `-flat` are global classes built from the
   variables, and the five JetEngine listings assemble them from atomic
   elements bound to dynamic tags. Only what the atomic style schema cannot
   express is here.

   Figma: ScholarshipCard 4170:26, ProfileCard 4187:111/118, NewsCard 4261:191,
   ServiceCard 28:2. Every card is 392 wide, which is what CardGrid assumes.
   ========================================================================= */

/* Shape masks. border-radius with the slash syntax is a multi-part value and
   the size prop type holds one number, so the crest cannot be a class value.
   It is only correct on a square frame, which is why the flat variants are
   separate: ProfileCard Type=Organisation is 392x220 and takes no mask. */
.elementor .card-media-crest{border-radius:var(--crest);}
.elementor .card-media-square,
.elementor .card-media-flat{border-radius:var(--radius-none);}

/* Card link = `btn` + `btn-text` + this modifier.

   Figma models TextLink (4241:185) and Button (4234:171) as separate
   components, and the first pass here built a standalone class to match that.
   That was wrong in practice: the CODED Ghost variant already IS the TextLink
   treatment - same geometry reset, same 2px rule offset 4px, same wipe on the
   same curve. The standalone class restated twelve declarations that `btn`
   and `btn-text` already own, and while restating them set the type two steps
   too small (13px against a measured ~16px in the Figma card).

   As a modifier it is three declarations, and anything that changes about
   button padding or type now reaches the cards for free. The colour pair
   (green at rest, charcoal on hover) lives on the class in the Class Manager;
   only the arrow is here, because a pseudo-element is not a style prop.

   The arrow is ::before with order:1 rather than ::after. Pseudo-elements are
   flex items, so order puts it after the label - which leaves ::after free to
   go on carrying btn-text's underline instead of fighting it for the slot. */
.elementor .card-link::before{
  content:'';
  order:1;
  display:inline-block;flex:0 0 auto;
  width:.78em;height:.78em;
  margin-inline-start:.45em;
  background-color:currentColor;
  -webkit-mask:var(--icon-arrow-e) center/contain no-repeat;
  mask:var(--icon-arrow-e) center/contain no-repeat;
}

/* btn-text's rule spans the whole element. Pull its end in by the arrow's
   width so it stops at the last word, as Figma's TextLink hover does - drawn
   edge to edge it crosses the arrow and reads as a strikethrough.
   The card arrow points EAST; the CTA button's points north-east, which in
   this system means "leaves the site". They must not share a glyph. */
.elementor .card-link::after{inset-inline-end:calc(.78em + .45em);}

/* The badge is an inline pill drawn on a block paragraph, so it needs the
   width collapse that align-self alone does not give it in a grid cell. */
.elementor .badge{width:fit-content;}

/* Elementor Pro's `post-terms` tag renders each term as an <a>, and the kit
   colours every anchor green (.elementor-kit-7 a{color:#14A14D}). That beat
   the badge's own muted ink, so the pill came out green on sand and read as a
   BUTTON rather than a tag. The link is kept - it goes to the term archive,
   which is wanted once the level pages exist - it just inherits the pill. */
.elementor .badge a{color:inherit;text-decoration:none;}

/* Two properties the atomic style schema will not take, verified by reading
   the generated CSS rather than assuming the write succeeded:

   border-width on a CONTAINER is dropped. Elementor routes container borders
   through --border-*-width custom properties on .e-con, so `card-boxed` can
   state the colour and the style but not the hairline. Left unset, the border
   still paints, at the CSS initial width of `medium` - which is 3px, and looks
   like a mistake rather than a hairline.

   margin with an `auto` keyword is dropped too (the dimensions prop wants a
   size). Pushing the link to the bottom is what keeps a row of cards with
   different amounts of body copy aligned along their links. */
.elementor .card-boxed{border-width:1px;}
.elementor .card-link{margin-block-start:auto;}

/* --- Focus ---------------------------------------------------------------
   Elementor pairs its `hover` state with :focus-visible automatically, which
   covers the colour swap. The ring itself is drawn here because outline is
   not an Elementor style prop. outline rather than box-shadow: both sit
   outside the border box and neither eats the 44px hit area, but a shadow
   cannot leave a transparent gap without painting a ring colour behind it,
   and this ring must read on white, sand AND charcoal. outline-offset gives
   the gap for free on any ground, and follows border-radius.
   :focus-visible, so a mouse press leaves no ring, while every keyboard and
   assistive-tech focus still gets one — which is what WCAG 2.4.7 requires.
   outline is never set to none anywhere. */
.elementor .btn:focus-visible,
.elementor .e-button-base:not(.btn):not(.card-link):focus-visible{
  outline:2px solid var(--focus-ring);
  outline-offset:2px;
}


/* ============================================================================
   9. COLOURED SURFACES
   ----------------------------------------------------------------------------
   The kit sets an explicit `.elementor-kit-7 h1..h6 {color:#31352D}`. An
   explicit rule on the heading always beats inheriting the surface colour, so
   headings stayed dark on every coloured band — 2.58:1 on the green, a 1.4.3
   failure. The surface class owns the ink: let headings inherit it.

   The :not() matters. This selector is (0,2,1), which would also outrank a
   .elementor .color-* utility at (0,2,0). Excluding headings that carry an
   explicit colour class means the rule never matches them, so the utility
   applies instead of merely losing on specificity.
   ========================================================================= */
.elementor :is(.bg-white,.bg-shell,.bg-lime,.bg-lilac,.bg-green,.bg-blue,.bg-black)
  :is(h1,h2,h3,h4,h5,h6):not([class*="color-"]){color:inherit;}

/* btn-outline-light carries min-width:280px because it was built for the
   footer CTA stack, where buttons are full-width blocks. In the hero the
   actions sit in an inline row, so let them size to their label. */
.elementor .hero-actions .btn-outline-light{min-width:0;}


/* ============================================================================
   10. TRANSPARENT HEADER
   ----------------------------------------------------------------------------
   Transparent until scrolled. Not in Figma — both NavBar variants (Scroll=Top,
   Scroll=Scrolled) are --surface-page #ffffff and differ only by
   Elevation/Header. If this stays, it wants a NavBar Scroll=Transparent
   variant in the file.

   Driven by Elementor Page Settings -> Header -> Header Style
   (inc-header-style.php), which emits on <body>:
     .pef-header-transparent + .pef-header-ink-light   (dark hero, white nav)
     .pef-header-transparent + .pef-header-ink-dark    (pale hero, dark nav)

   TWO HALVES, ON DIFFERENT ELEMENTS, AND ONLY ONE IS AUTOMATIC.

   1. The header is pulled out of the way by its own height, so whatever
      follows runs up underneath it. Acting on the header itself needs no
      knowledge of the page structure.
   2. The first section has to give that height back as top padding, or its
      content sits under the navigation. That is the `section-under-header`
      global class, which sets padding-block-start to var(--section-pad-top-hero)
      — the section rhythm plus the header height — and the author applies it
      to the hero.

   Step 2 used to be automatic, matched with .e-con:not(.e-con .e-con). It kept
   selecting the wrong element in the Elementor editor, which wraps the
   document in extra helper elements, and produced a band of white above the
   first container. Three attempts at a smarter selector all failed the same
   way. A class needs no structural guessing and is visible in the Class
   Manager, so an author can see why the hero has the padding it has.

   TRADE-OFF: forget the class on a transparent-header page and the hero's
   content sits under the navigation. Page Settings and the class have to be
   used together.
   ========================================================================= */
body.pef-header-transparent .elementor-location-header{
  margin-block-end:calc(-1 * var(--pef-hdr-h));
}

/* --- Bar background ---------------------------------------------------
   EVERY "is the menu open" test below is :is(:has([aria-expanded="true"]),
   :has(.pef-exit)), never aria-expanded alone. Elementor flips that attribute
   to false at the START of a close, but the panel is still on screen for the
   whole 600ms exit — so keyed on the attribute the bar dropped back to
   transparent while a white panel was still retracting underneath it, leaving
   the hero showing through the bar with a white band below. The pef-exit half
   keeps the bar solid until the panel has actually gone.
   The same applies to the ink rules further down: without it the nav labels
   and logo invert back to white on a dark hero while the panel is still open.
   ---------------------------------------------------------------------- */
body.pef-header-transparent .elementor-location-header .header-bar{
  background-color:transparent !important;
  transition:background-color .25s ease, box-shadow .2s ease;
}
body.pef-header-transparent .elementor-location-header.is-scrolled .header-bar,
body.pef-header-transparent .elementor-location-header:is(:has([aria-expanded="true"]),:has(.pef-exit)) .header-bar{
  background-color:#FFFFFF !important;
}

/* --- Inverted ink, light mode only, and only while truly transparent -----
   i.e. at the top of the page AND with no menu panel open. An open panel is
   white, so the bar above it must be solid and dark-inked too.
   (ink-dark mode needs no overrides — the default header ink is already dark.) */

/* logo is two-tone (#14A14D mark + #31352D wordmark); both go white */
body.pef-header-ink-light .elementor-location-header:not(.is-scrolled):not(:is(:has([aria-expanded="true"]),:has(.pef-exit))) a.logo svg,
body.pef-header-ink-light .elementor-location-header:not(.is-scrolled):not(:is(:has([aria-expanded="true"]),:has(.pef-exit))) a.logo svg *{
  fill:#FFFFFF !important;
}

/* nav labels, chevrons, mobile MENU/CLOSE */
body.pef-header-ink-light .elementor-location-header:not(.is-scrolled):not(:is(:has([aria-expanded="true"]),:has(.pef-exit))) :is(.e-n-menu-title-container,.e-n-menu-title-text,.e-n-menu-toggle,.e-n-menu-dropdown-icon){
  color:#FFFFFF !important;
}
body.pef-header-ink-light .elementor-location-header:not(.is-scrolled):not(:is(:has([aria-expanded="true"]),:has(.pef-exit))) .e-n-menu-dropdown-icon svg{
  fill:#FFFFFF !important;
}

/* Apply: outline goes white-on-transparent. Its normal hover fills dark,
   which would sit at 2.55:1 on the green, so invert the hover too. */
body.pef-header-ink-light .elementor-location-header:not(.is-scrolled):not(:is(:has([aria-expanded="true"]),:has(.pef-exit))) .btn-outline{
  background-color:transparent !important;color:#FFFFFF !important;border-color:#FFFFFF !important;
}
body.pef-header-ink-light .elementor-location-header:not(.is-scrolled):not(:is(:has([aria-expanded="true"]),:has(.pef-exit))) .btn-outline:hover{
  background-color:#FFFFFF !important;color:#31352D !important;
}

/* Donate: a dark fill would be a 2.55:1 edge on the green, so invert to white */
body.pef-header-ink-light .elementor-location-header:not(.is-scrolled):not(:is(:has([aria-expanded="true"]),:has(.pef-exit))) .btn-primary{
  background-color:#FFFFFF !important;color:#31352D !important;border-color:#FFFFFF !important;
}
body.pef-header-ink-light .elementor-location-header:not(.is-scrolled):not(:is(:has([aria-expanded="true"]),:has(.pef-exit))) .btn-primary:hover{
  background-color:transparent !important;color:#FFFFFF !important;
}

/* focus ring: --focus-ring #0081F3 is 1.26:1 on the green, invisible */
body.pef-header-ink-light .elementor-location-header:not(.is-scrolled):not(:is(:has([aria-expanded="true"]),:has(.pef-exit))) :focus-visible{
  outline-color:#FFFFFF !important;
}

/* --- Cross-fade ------------------------------------------------------- */
body.pef-header-transparent .elementor-location-header :is(a.logo svg, a.logo svg *, .e-n-menu-title-container, .e-n-menu-dropdown-icon svg, .e-button-base){
  transition:color .25s ease, background-color .25s ease, border-color .25s ease, fill .25s ease;
}


/* ============================================================================
   11. REDUCED MOTION
   ----------------------------------------------------------------------------
   ONE block for the whole site. There were six, scattered across the seven
   files, and between them they still missed the toggle labels and the footer
   chevron.

   Motion is decoration here, so it is dropped for anyone who has asked the OS
   to reduce it. Only the transitions go — the clip-path, grid-track and
   visibility values are load-bearing, being what keeps a closed panel or row
   hidden and inert, so they are deliberately left in place to apply instantly.
   Everything that starts an animation hidden is forced back to fully visible,
   and the button press scale is dropped entirely since it is pure motion.

   The duration tokens are zeroed too, which covers every transition written
   as var(--dur-*) without naming it here.
   ========================================================================= */
@media (prefers-reduced-motion:reduce){
  :root{--dur-fast:0ms; --dur-base:0ms; --dur-slow:0ms;
        --dur-menu:0ms; --dur-menu-lag:0ms;}

  .elementor-location-header .e-n-menu .e-n-menu-title-text::after,
  .elementor-location-header .e-n-menu .e-n-menu-dropdown-icon,
  .elementor-location-header .header-bar,
  .e-n-menu-content,
  .e-n-menu-wrapper,
  .e-n-menu-item,
  .e-n-menu-toggle::before,
  .e-n-menu-toggle::after,
  .e-n-menu-dropdown-icon .pef-chev,
  .mega-panel,
  .mega-panel .elementor-icon-list-item,
  .mega-panel > .e-image-base,
  .pef-cta-in-menu,
  .footer-groups > .footer-group > .footer-links,
  .footer-groups .elementor-icon-list-item,
  .footer-groups > .footer-group > .footer-eyebrow::after,
  .elementor-location-footer a:not(.btn):not(.e-svg-base),
  .elementor-location-footer a:not(.btn):not(.e-svg-base) .elementor-icon-list-text::after,
  .elementor-location-footer a.social-icon svg,
  .elementor-location-footer a.social-icon svg *,
  .elementor .btn,
  .elementor .btn-text::after,
  .elementor .card-link,
  body.pef-header-transparent .elementor-location-header *,
  body.pef-header-transparent .elementor-location-header .header-bar{
    transition:none !important;
  }

  .e-n-menu-item,
  .pef-cta-in-menu,
  .mega-panel .elementor-icon-list-item,
  .mega-panel > .e-image-base{opacity:1 !important;transform:none !important;}
  .mega-panel{transform:none !important;}
  .footer-groups > .footer-group.is-open .elementor-icon-list-item{opacity:1 !important;}
  .elementor .btn:active{transform:none !important;}
}
