/*
Theme Name: Evolution
Theme URI: https://evolution.edu.au/
Author: FlexiMail IT Solutions
Description: Custom block theme for Evolution Hospitality Institute.
Version: 0.1.0
Text Domain: evolution
*/

html {
    scroll-behavior: smooth;
    /* Defense-in-depth against the homepage phantom horizontal scrollbar
       (previously fixed at the carousel level in home-blocks.css via
       touch-action:pan-y, which only covers touch/pen input, not mouse
       wheel/tilt-scroll input reaching a nested overflow:hidden carousel
       track). overscroll-behavior-x:contain stops that scroll attempt from
       chaining up to the document without altering layout or creating a new
       overflow/scroll box (unlike overflow-x:hidden, this can't affect the
       sticky header's positioning context - see test-sticky-header-parity.ps1). */
    overscroll-behavior-x: contain;
}

body {
    -moz-osx-font-smoothing: grayscale;
    -webkit-font-smoothing: antialiased;
    overscroll-behavior-x: contain;
}

img {
    max-width: 100%;
    height: auto;
}

a {
    text-underline-offset: 0.18em;
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
.wp-element-button:focus-visible {
    outline: 2px solid var(--wp--preset--color--accent);
    outline-offset: 3px;
}

.wp-site-blocks {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

/* Confirmed live: the standard "sticky footer" pattern needs main to grow
   (flex:1) so it fills any leftover vertical space in .wp-site-blocks's
   min-height:100vh column, pushing the footer down to the viewport's
   bottom edge on short pages. .evolution-front-page never had a
   contradicting override and its footer already sticks correctly; the
   legacy-page template's own main previously had flex:0 0 auto here
   instead (main refusing to grow), which is why every legacy-page-template
   page had a gap between its footer and the bottom of the viewport - this
   was backwards from the standard pattern, not a legacy-fidelity
   requirement (sticky-footer-on-short-pages is baseline layout behaviour,
   not something migration parity should override). Removed so
   .evolution-legacy-page falls back to this same shared flex:1 rule. */
.wp-site-blocks > main {
    flex: 1;
}

/* Confirmed live (not guessed): the homepage's own content wrapper
   (.wp-block-post-content, inside <main class="evolution-front-page">) is
   is-layout-flow, and WordPress's own generated CSS gives every non-first
   child of a flow-layout group `margin-block-start: 1.5rem` (24px) - the
   same mechanism already found and fixed for the navigation white-strip
   regression, here affecting the homepage's OWN top-level sections instead.
   Every homepage section after the hero (Courses, Why Study With Us, Video,
   Social, Testimonials, Blog/News, Partners) is not :first-child, so each
   one silently gained an extra 24px on top of its own explicit pt---NN
   padding class - legacy's flat HTML has no such margin concept at all
   (each section's spacing is entirely its own padding-top, e.g.
   .react_popular_topics.pt---60 = 60px, full stop). Neutralized here,
   scoped to the homepage's own content wrapper specifically - not a global
   override of is-layout-flow spacing, which other pages' normal paragraph/
   block content still needs. */
.evolution-front-page .wp-block-post-content > * {
    margin-block-start: 0;
}

/* Deliberate, larger gap specifically before the video section, by explicit
   user request - three classes (0,3,0) so it reliably wins over the
   zeroing rule above (0,2,0) regardless of source order or which
   stylesheet loads later (.evolution-home-video's own styling lives in a
   separate plugin stylesheet, legacy-page-blocks.css). */
.evolution-front-page .wp-block-post-content > .evolution-home-video {
    margin-block-start: 80px;
}

/* Confirmed live via DevTools (computed margin-block-start:24 on <main
   class="evolution-front-page">) - a SEPARATE generic WordPress mechanism
   from the is-layout-flow one above: `:where(.wp-site-blocks) > * {
   margin-block-start: var(--wp--preset--spacing--50) }` with only
   `:where(.wp-site-blocks) > :first-child` exempted. .wp-site-blocks does
   not carry is-layout-flow itself, so this rule is independent of it - it
   is WordPress's own site-template-region spacing, applied directly to
   .wp-site-blocks's own children (<header>, <main>, <footer>). <header> is
   :first-child (correctly exempted, 0). <main class="evolution-front-page">
   is the second child, so it silently received the 24px gap between the
   header/nav block and the hero - this is the actual white-strip cause,
   unconditional (present whether the desktop menu is open or collapsed),
   just far more visually obvious once the taller open-state dark bar makes
   the header-to-hero boundary prominent. Neutralized here, scoped to this
   specific page template's main element - not a global override of
   .wp-site-blocks/.is-layout-flow/main, which the task explicitly
   prohibits touching. */
.evolution-front-page {
    margin-block-start: 0;
}

/* Confirmed live via Kudu-fetched HTML: wp:template-part with
   tagName:"footer" renders an outer wrapper `<footer
   class="wp-block-template-part">`, with the footer part's own
   `evolution-footer` class one level further in on a nested inner
   <footer>. The selector this replaced (`main... + footer.evolution-footer`)
   never matched any element - the actual next sibling after <main> is
   always footer.wp-block-template-part, on every template (all of them
   declare the footer part with tagName:"footer"), so this had been dead
   CSS site-wide, not merely unscoped to the homepage. */
.wp-site-blocks > main + footer.wp-block-template-part {
    margin-block-start: 0;
    margin-top: 0;
    /* flex:0 0 auto (natural height, not growing) - now that main correctly
       grows again (see the shared main rule above), the footer shouldn't
       also try to grow: a flex-grow footer stretches its own box while its
       content stays top-aligned inside it, which is not what a "stick to
       the bottom" footer should do - main growing to push the footer down
       is the actual mechanism; the footer itself should stay sized to its
       own content. */
    flex: 0 0 auto;
}

.wp-block-navigation__responsive-container.is-menu-open {
    padding: var(--wp--preset--spacing--50);
}

.screen-reader-text {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.evolution-header-area {
    --evolution-header-accent: #D62B7B;
    --evolution-header-dark: #0F1216;
    --evolution-header-purple: #6B5CF6;
    --evolution-header-brand-dark: #2D2D73;
    position: relative;
}

/* Confirmed live (not guessed): this element carries WordPress core's own
   default block styling, `:where(.wp-block-group.has-background) { padding:
   1.25em 2.375em; }` (its class list includes has-background - set because
   this group has a background colour assigned in the editor). That's ~20px
   top+bottom with no legacy equivalent at all (legacy's header sizing is
   entirely `.menu-part { min-height: 91px; }`, menus.css - no padding layer
   exists), and nothing here previously overrode it - the primary source of
   the header rendering visibly taller than legacy production. `:where()` has
   zero specificity, so a single plain class selector is enough to override it. */
.evolution-header {
    position: relative;
    z-index: 20;
    min-height: 91px;
    padding: 0;
    font-family: Montserrat, var(--wp--preset--font-family--system-sans);
    border-bottom: 0;
}

.evolution-header__inner {
    min-height: 91px;
    max-width: 1340px;
    margin-right: auto;
    margin-left: auto;
    gap: 24px;
}

/* Confirmed via legacy source (assets/js/main.js: a plain window scroll
   listener adds/removes .react-sticky on the header once scrollTop crosses
   100px, no breakpoint gate; style.css:973-988: .react-sticky sets
   position:fixed/top:0/left:0/right:0/width:100%/z-index:999 plus a
   translateY(-100px)->translateY(0) "drop in" entrance animation). Applied
   here to .evolution-header-area (the shared containing block for both the
   header row and the desktop overlay nav below it, not just .evolution-
   header alone) so the overlay's own top:100% anchor point moves together
   with the header rather than staying pinned to the header's original
   in-flow position once it goes fixed. header.js toggles is-header-sticky
   using the same 100px threshold, unconditionally at every viewport width,
   matching legacy exactly - legacy does not gate this by breakpoint either.
   No content-shift compensation is added, matching legacy's own real
   behaviour (legacy has none either - the page content shifts up by the
   header's height at the moment it goes fixed, the same trade-off legacy
   itself makes, masked partly by the drop-in animation). */
.is-header-sticky.evolution-header-area {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    width: 100%;
    z-index: 999;
    animation: evolution-header-sticky-in 800ms cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
}

/* Confirmed live: with animation-fill-mode "both" above, the sticky-in
   keyframe's final transform:translateY(0) stays permanently applied to
   .evolution-header-area once scrolled past the sticky threshold - and per
   spec, ANY non-none transform on an ancestor (even an identity transform
   like translateY(0)) establishes a new containing block for position:fixed
   descendants. .evolution-header-search (the full-screen search overlay)
   lives inside this same element, so once scrolled while search is open,
   its inset:0 started sizing against .evolution-header-area's own small
   ~91px box instead of the true viewport - the reported "shrinks on scroll"
   bug. Three classes (0,3,0) deliberately outweighs the rule above's two
   (0,2,0), so this wins regardless of source order. */
.is-header-sticky.evolution-header-area.is-search-open {
    animation: none;
    transform: none;
}

@keyframes evolution-header-sticky-in {
    0% {
        transform: translateY(-100px);
    }
    100% {
        transform: translateY(0);
    }
}

.evolution-site-logo,
.evolution-site-logo .custom-logo-link {
    display: flex;
    align-items: center;
}

.evolution-site-logo {
    flex: 0 0 auto;
    margin-top: 14px;
    margin-bottom: 14px;
}

.evolution-site-logo img {
    width: 161px;
    max-width: 161px;
    height: auto;
}

.evolution-header__actions {
    gap: 23px;
    padding-right: 21px;
    padding-left: 21px;
    margin-left: auto;
}

.evolution-utility-nav {
    font-family: Montserrat, var(--wp--preset--font-family--system-sans);
    font-size: 13px;
    font-weight: 700;
    line-height: 1;
    text-transform: uppercase;
}

.evolution-utility-nav .wp-block-navigation-item__content {
    padding-top: 6px;
    padding-bottom: 6px;
    color: #000000;
    text-decoration: none;
}

.evolution-utility-nav .wp-block-navigation-item__content:hover,
.evolution-utility-nav .wp-block-navigation-item__content:focus,
.evolution-utility-nav .current-menu-item > .wp-block-navigation-item__content,
.evolution-utility-nav .current-menu-ancestor > .wp-block-navigation-item__content {
    color: var(--evolution-header-accent);
}

.evolution-search-toggle,
.evolution-menu-toggle {
    appearance: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: 0;
    cursor: pointer;
}

.evolution-search-toggle {
    width: 24px;
    height: 24px;
}

.evolution-menu-toggle {
    width: 32px;
    height: 32px;
}

/* Confirmed live via legacy source trace (header.php's search button svg
   uses stroke="currentColor" with no explicit color rule anywhere in the
   base react-header variant actually used on evolution.edu.au - it simply
   inherits the surrounding black nav text colour). Only the hamburger
   (.icon-bar, confirmed background-color:#d62b7b !important in legacy
   menus.css) is the brand-pink accent; the search icon was never pink on
   legacy, so the two can no longer share one colour rule. */
.evolution-search-toggle {
    color: #000000;
}

.evolution-menu-toggle {
    color: var(--evolution-header-accent);
}

.evolution-search-toggle:hover,
.evolution-search-toggle:focus-visible {
    color: #000000;
    background: transparent;
}

.evolution-menu-toggle:hover,
.evolution-menu-toggle:focus-visible {
    color: var(--evolution-header-accent);
    background: transparent;
}

.evolution-search-toggle__icon {
    position: relative;
    display: block;
    width: 14px;
    height: 14px;
    border: 2px solid currentColor;
    border-radius: 50%;
}

.evolution-search-toggle__icon::after {
    position: absolute;
    right: -4.5px;
    bottom: -3px;
    width: 7px;
    height: 1.5px;
    content: "";
    background: currentColor;
    border-radius: 999px;
    transform: rotate(45deg);
    transform-origin: center;
}

.evolution-menu-toggle__bars {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    justify-content: center;
    width: 25px;
    gap: 6px;
}

.evolution-menu-toggle__bars span {
    display: block;
    height: 2.5px;
    background: currentColor;
    border-radius: 999px;
    transition: width 500ms ease, transform 500ms ease, opacity 300ms ease;
}

.evolution-menu-toggle__bars span:nth-child(1) {
    width: 16px;
}

.evolution-menu-toggle__bars span:nth-child(2) {
    width: 20px;
}

.evolution-menu-toggle__bars span:nth-child(3) {
    width: 25px;
}

.evolution-menu-toggle:hover .evolution-menu-toggle__bars span,
.evolution-menu-toggle:focus-visible .evolution-menu-toggle__bars span {
    width: 25px;
}

.is-navigation-open .evolution-menu-toggle__bars span:nth-child(1) {
    width: 25px;
    transform: translateY(8.5px) rotate(45deg);
}

.is-navigation-open .evolution-menu-toggle__bars span:nth-child(2) {
    width: 25px;
    opacity: 0;
}

.is-navigation-open .evolution-menu-toggle__bars span:nth-child(3) {
    width: 25px;
    transform: translateY(-8.5px) rotate(-45deg);
}

/* Desktop's secondary nav bar (.evolution-menu-panel) now defaults to
   CLOSED on both breakpoints, by explicit user request overriding the
   earlier "always visible on desktop" decision recorded below at
   .evolution-menu-panel - the panel should only ever show once the user
   actually clicks the toggle, matching mobile's own default-closed
   behaviour. The icon now needs no unqualified/default override at this
   breakpoint at all: the base (non-media-query) .evolution-menu-toggle__bars
   span rules above already render the correct plain-bars "closed" shape,
   identical to mobile's own default. Only .is-desktop-menu-open - added by
   header.js exactly when the panel is actually open - needs to morph the
   bars into an X, mirroring the .is-navigation-open rules above for mobile. */
@media (min-width: 992px) {
    .is-desktop-menu-open .evolution-menu-toggle__bars span:nth-child(1) {
        width: 25px;
        transform: translateY(8.5px) rotate(45deg);
    }

    .is-desktop-menu-open .evolution-menu-toggle__bars span:nth-child(2) {
        width: 25px;
        opacity: 0;
    }

    .is-desktop-menu-open .evolution-menu-toggle__bars span:nth-child(3) {
        width: 25px;
        transform: translateY(-8.5px) rotate(-45deg);
    }
}

/* Redesigned to match legacy's actual full-screen dark search modal
   (Bootstrap #searchModal, style.css: .modal-backdrop.show{opacity:.88},
   h3.text-white.text-center heading, joined rounded input+button pair) -
   the previous inline light dropdown was a deviation from legacy's real,
   still-live behaviour. */
.evolution-header-search {
    display: none;
}

/* .evolution-header-search is is-layout-flow (see header.html), so WordPress's
   generated CSS gives every non-first child margin-block-start:1.5rem (24px)
   - .evolution-search-close is position:absolute and occupies no visual
   space, but it still counts as the (structural) first child, so the form
   right after it was still treated as non-first and picked up the phantom
   24px gap, visually separating the close button/heading/input-row into
   disconnected pieces instead of one cohesive block. Neutralized here, the
   same fix already applied several times elsewhere in this file for the
   identical mechanism. */
.evolution-header-search > * {
    margin-block-start: 0;
}

.is-search-open .evolution-header-search {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    flex-direction: column;
    /* align-items intentionally NOT centered - a column flex container's
       default cross-axis behaviour (stretch) is what lets the search form
       below fill this container's full width; align-items:center would
       shrink it to its own content width instead (confirmed live: the form
       rendered at 409px, its natural content-fit width, until this was
       removed). */
    justify-content: center;
    max-width: none;
    margin: 0;
    padding: 60px;
    background: rgba(0, 0, 0, 0.9);
}

/* In-flow (not position:absolute) and centered via align-self, so it always
   sits directly above the "Search entire site" heading with a small fixed
   gap - a fixed top:180px offset only looked right at one particular
   viewport height, drifting away from the heading at any other. */
.evolution-search-close {
    align-self: center;
    display: block;
    width: 32px;
    height: 32px;
    margin-bottom: 12px;
    color: #ffffff;
    background: transparent;
    border: 0;
    font-size: 32px;
    line-height: 1;
    cursor: pointer;
}

.evolution-header-search .wp-block-search__label {
    display: block;
    margin-bottom: 20px;
    color: #ffffff;
    font-size: 28px;
    font-weight: 500;
    text-align: center;
    text-transform: none;
}

/* No max-width cap - confirmed live via legacy's own #searchModal .modal-
   dialog{max-width:100%;padding:60px} (desktop): the input/button bar spans
   the full available width (viewport minus the overlay's own 60px padding),
   not a small centered box. */
/* padding:0 is required, not just border:none - WP core's own
   .wp-block-search__button-inside .wp-block-search__inside-wrapper rule
   sets padding:4px, which insets the input/button rectangle inside this
   wrapper's rounded+clipped edge. That 4px inset was the actual cause of
   BOTH the visible seam between input and button (the wrapper's own
   background showing through the gap) and the input's square-looking left
   corners (the input's own straight edges sitting visibly inside the
   rounded outer clip, instead of flush against it). */
.evolution-header-search .wp-block-search__inside-wrapper {
    display: flex;
    width: 100%;
    margin: 0 auto;
    padding: 0;
    border: none;
    border-radius: 8px;
    overflow: hidden;
}

.evolution-header-search .wp-block-search__input {
    flex: 1;
    height: 62px;
    padding: 12px 20px;
    border: none;
    background: #f4f5f5;
}

.evolution-header-search .wp-block-search__button {
    min-width: 150px;
    margin-left: 0;
    padding: 15px 20px;
    color: #ffffff;
    background: var(--evolution-header-purple);
    border: none;
    border-radius: 0;
}

/* Confirmed live via direct legacy source trace (assets/js/menus.js +
   menus.css), not guessed - and corrected after an earlier, wrong reading
   of this same evidence: legacy's main desktop nav is VISIBLE BY DEFAULT
   on page load. `.middle-menu .react-menus { display: block; }` is
   unconditional CSS at desktop widths (menus.css, @media min-width:992px),
   and the responsive-menu plugin's own init logic
   (`if ($(window).innerWidth() <= resizeWidth) { menuCollapse(); }`) only
   auto-collapses the menu when the page ALREADY loads below the 991px
   breakpoint - on a normal desktop load nothing hides it. This element was
   previously `display:none` UNCONDITIONALLY (every viewport), gated behind
   the hamburger even on desktop - a real bug, not an intentional overlay
   design; that is what the "closed = no dark bar" report was actually
   describing. Desktop default is now simply "in normal flow, visible" - no
   class needed. The genuine legacy behaviour that DOES exist - clicking the
   hamburger (`#menu-btn`) runs `$backmenu.slideToggle()`, a real ANIMATED
   collapse, even at desktop widths, independent of the mobile breakpoint's
   own hide/show - is reproduced in the desktop-only block below via a
   max-height transition (CSS cannot animate to height:auto directly; a
   generously-oversized max-height is the standard technique for the same
   visual effect without requiring JS-measured heights, matching jQuery's
   own default slideToggle duration of 400ms - confirmed live: the
   `animationSpeed` plugin option is defined but never actually passed to
   any .slideToggle()/.fadeIn()/.fadeOut() call in menus.js, so every one of
   them silently uses jQuery's hardcoded default). Mobile's existing
   default-hidden/is-navigation-open-shows behaviour (its own, separate,
   already-correct, already-approved accordion) is unchanged, just properly
   scoped to its own media query below instead of leaking into desktop. */
/* margin-block-start:0 here is the proven, minimal fix for the reported
   white-strip regression, found via source-level tracing, not guessed:
   .evolution-header-area (this element's own parent) carries
   `is-layout-flow`, and WordPress's generated global CSS
   (:where(.is-layout-flow) > * { margin-block-start: var(--wp--preset--
   spacing--50); margin-block-end: 0; }, confirmed live in the page's own
   generated CSS) gives every NON-first child of a flow-layout group a 24px
   top margin - the :first-child exemption rule only protects
   .evolution-header (the actual first child); .evolution-menu-panel is the
   second child, so it received this 24px margin unaccounted-for, with no
   override anywhere in this stylesheet before this line (confirmed by
   grepping the entire file for any existing margin/margin-block-start rule
   targeting this selector - none existed). This is the same generic
   is-layout-flow mechanism already found and fixed twice before in this
   project (.evolution-menu-panel__inner below, and the homepage's own
   inter-section spacing) - a fourth instance of the identical root cause,
   in the one remaining un-audited spot: the header/nav-panel's own shared
   parent. Margin sits OUTSIDE this element's max-height/overflow-clipped
   border-box, so it persisted even while the desktop collapse animation
   (added in the previous round) was otherwise working correctly - proven by
   the fact that no rule anywhere counteracted it prior to this change. */
.evolution-menu-panel {
    position: relative;
    z-index: 15;
    margin-block-start: 0;
    font-family: Montserrat, var(--wp--preset--font-family--system-sans);
    background: #0F1216;
}

@media (min-width: 992px) {
    /* Overlay by explicit user decision (not a legacy-fidelity claim - the
       user directly compared before/after screenshots of the live site and
       asked for this, overriding legacy's own push-the-page-down flow
       behaviour documented above in Part 21). Taking the panel out of
       normal flow via position:absolute, anchored to .evolution-header-area
       (given position:relative above) at top:100%, means it no longer
       contributes to .evolution-header-area's own height in either state -
       the header area's box stays exactly .evolution-header's height
       (~91px) whether the panel is open or collapsed, so opening it can no
       longer push hero/page content down; it renders on top of it instead.
       This overlay mechanism is unchanged; only the DEFAULT state below it
       has since been flipped - see the .is-desktop-menu-open comment. */
    /* Switched from the max-height:2000px collapse trick to the CSS Grid
       0fr/1fr technique, by explicit user request after live testing: with
       a fixed max-height target (2000px) far larger than the panel's real
       content height (~90px, a single nav row), OPENING reached its full
       visible height almost immediately (as soon as the interpolated
       max-height value crossed ~90px, roughly the first 5% of the
       transition's total duration), then spent the remaining ~95% of the
       transition invisibly still counting up toward 2000px - while CLOSING
       stayed visibly full-height until the interpolated value dropped back
       below ~90px, near the END of the transition. Same transition
       duration, wildly different PERCEIVED duration per direction - opening
       looked much faster than closing even though both used an identical
       650ms rule. grid-template-rows: Nfr genuinely interpolates against
       the row's own real content size (not an arbitrary oversized ceiling),
       so both directions now visibly animate across the FULL transition
       duration symmetrically, with no dependency on knowing/guessing the
       content's real pixel height. */
    /* Default flipped to CLOSED (grid-template-rows: 0fr) by explicit user
       request, superseding the earlier "default visible on desktop" decision
       documented elsewhere in this project's history - the panel should only
       ever appear once the toggle is actually clicked, on every breakpoint,
       matching mobile's own default-closed behaviour below. */
    .evolution-menu-panel {
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        display: grid;
        grid-template-rows: 0fr;
        box-shadow: 0 16px 32px rgba(15, 18, 22, 0.25);
        transition: grid-template-rows 650ms ease;
    }

    /* Deliberately a SEPARATE class from mobile's `is-navigation-open`, not
       that same class reused - keeping the two independent (rather than
       sharing one class across breakpoints) avoids ambiguity in header.js's
       ARIA/label bookkeeping (aria-expanded, aria-hidden, the screen-reader
       label) at the exact moment the viewport crosses the breakpoint. Both
       now mean the same thing - "the panel is open" - just gated by their
       own breakpoint's class for that reason. */
    .is-desktop-menu-open .evolution-menu-panel {
        grid-template-rows: 1fr;
    }

    /* The grid ITEM (not the grid container) needs overflow:hidden and
       min-height:0 for the 0fr/1fr trick to actually clip during the
       transition - grid items default to min-height:auto (their content's
       own intrinsic minimum), which would otherwise prevent the row from
       ever fully collapsing to 0. .evolution-menu-panel__inner is
       display:none on desktop (see below), so .evolution-desktop-nav is the
       only element actually occupying this single-row grid. Same submenu-
       clipping concern as before (the dropdown overlay is a DOM descendant
       that extends well below this element's own small natural height once
       opened) - the overflow:visible exemption on hover/focus-within moves
       here with it, unchanged in spirit, just retargeted to the element
       that now actually owns overflow:hidden. */
    .evolution-desktop-nav {
        overflow: hidden;
        min-height: 0;
    }

    .evolution-desktop-nav:has(.evolution-desktop-nav__list > li:hover),
    .evolution-desktop-nav:has(.evolution-desktop-nav__list > li:focus-within) {
        overflow: visible;
    }
}

/* display:none here on desktop (root cause of the white-strip regression,
   confirmed live via the page's own global-styles-inline-css, not guessed):
   .evolution-menu-panel is `is-layout-flow`, and WordPress's own generated
   CSS gives every child of a flow-layout group `margin-block-start: 1.5rem`
   (the "50" spacing preset) EXCEPT :first-child, which gets 0. Before the
   desktop-nav rebuild, .evolution-menu-panel__inner was .evolution-menu-
   panel's ONLY/first child (both navs lived inside it), so it always
   qualified for the zero-margin exemption. The rebuild inserted
   .evolution-desktop-nav BEFORE it as the new first child, so
   .evolution-menu-panel__inner became the SECOND child and picked up the
   24px margin-block-start it had never carried before - even though its
   only content (.evolution-primary-nav) is already display:none on desktop,
   the WRAPPER itself was still present, still claiming its own min-height
   plus this new margin, extending .evolution-menu-panel's box past the
   nav's own visible content. Since this wrapper has zero desktop purpose
   now (the mobile-only accordion nav is its sole content), giving the
   wrapper itself display:none removes it from flow-layout margin/gap
   calculations entirely, not just hiding its content - eliminating the
   extra space at its source rather than compensating for it with a
   negative margin or fixed offset. */
.evolution-menu-panel__inner {
    display: none;
    min-height: 58px;
    max-width: 1340px;
    margin-right: auto;
    margin-left: auto;
}

.evolution-primary-nav {
    min-height: 58px;
    font-family: Montserrat, var(--wp--preset--font-family--system-sans);
    font-size: 14px;
    font-weight: 700;
    line-height: 1.2;
}

.evolution-primary-nav .wp-block-navigation-item {
    position: static;
}

.evolution-primary-nav > .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-item__content,
.evolution-primary-nav > .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-submenu__toggle {
    /* !important matches the legacy stylesheet's own approach for this
       exact selector (menus.css: ".main-navbar.react-main-menu .react-menus
       > li > a { color: #ffffff !important; }") - core's navigation block
       CSS ships a same-specificity ".wp-block-navigation-item__content
       .wp-block-navigation-item__content { color: inherit }" rule that
       otherwise ties with this one and can win depending on enqueue order,
       leaving top-level labels inheriting the page's default (dark) text
       color against this dark menu strip.

       Scoped with `>` combinators to ONLY the top-level items (direct
       children of the nav's own <ul>), not `.evolution-primary-nav
       .wp-block-navigation-item__content` (a plain descendant selector) -
       that broader form also matched every item *inside* a submenu panel,
       and because !important always wins regardless of specificity, it was
       forcing white-on-white text there too (invisible until :hover
       triggered the equally-!important accent-colour rule below) even
       though a separate, correctly-dark submenu-item rule already existed
       further down. Scoping structurally by rendering family - top-level
       vs. submenu-nested - removes the conflict entirely rather than
       stacking more !important rules to fight it. */
    color: #ffffff !important;
    text-decoration: none;
}

.evolution-primary-nav > .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-item__content:hover,
.evolution-primary-nav > .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-item__content:focus,
.evolution-primary-nav > .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-submenu__toggle:hover,
.evolution-primary-nav > .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-submenu__toggle:focus,
.evolution-primary-nav > .wp-block-navigation__container > .current-menu-item > .wp-block-navigation-item__content,
.evolution-primary-nav > .wp-block-navigation__container > .current-menu-ancestor > .wp-block-navigation-item__content,
.evolution-primary-nav > .wp-block-navigation__container > .current-menu-ancestor > .wp-block-navigation-submenu__toggle {
    color: var(--evolution-header-accent) !important;
}

/* Desktop submenu geometry for .evolution-primary-nav (core/navigation's own
   markup) was removed here - not patched further. Root cause (confirmed live
   via wp-includes/blocks/navigation/style.min.css, not guessed): that
   stylesheet ships several rules that only activate in the OPEN state and
   carry deliberately escalating specificity - the SAME class repeated four
   times (0,4,0) setting left/right, and a state-attribute rule
   (".has-child .wp-block-navigation-submenu__toggle[aria-expanded=true] ~
   .wp-block-navigation__submenu-container", 0,5,0) setting width/height/
   overflow. This theme's own box rule (0,3,0, a plain descendant chain) lost
   those fights specifically once a submenu opened - exactly when it visually
   mattered - so width/right silently fell back to core's `auto`, producing a
   box that floated independently of its own full-width, white-background
   shell (the "full-width strip separate from a floating submenu" defect).
   No further override could fix this without `!important` (fighting core
   rule-for-rule) or replicating core's own specificity-boosting tricks
   (fragile against future core updates) - both are the "CSS patches" this
   rollback deliberately stops adding.
   Desktop navigation is now rendered by a dedicated `evolution/desktop-nav`
   block (plugins/evolution-core/includes/class-navigation-render.php),
   using plain <ul>/<li>/<a> markup core's stylesheet has no rules for at
   all - see `.evolution-desktop-nav` below - so no specificity conflict is
   even possible. `.evolution-primary-nav` (core/navigation's own markup) is
   retained AS-IS, unmodified, for MOBILE only (see the existing
   `@media (max-width: 991px)` block further down, and the display toggle
   below) - its already-working accordion behaviour was never the bug and is
   not touched by this change. */

/* .evolution-desktop-nav is mounted in header.html as a DIRECT child of
   .evolution-menu-panel, NOT nested inside .evolution-menu-panel__inner -
   confirmed live (not guessed) that WordPress's own auto-generated global
   styles apply `max-width:1340px; margin-left:auto !important; margin-right:
   auto !important;` to every DIRECT CHILD of a "constrained"-layout group
   (.wp-container-core-group-is-layout-5 > :where(...), which is exactly
   what .evolution-menu-panel__inner is) - so being nested inside it was
   constraining the nav itself (and, with it, everything positioned relative
   to it, including the submenu) to a centered 1340px box instead of the
   required full-width panel, with the hero visible on both sides. Being a
   sibling of that wrapper instead removes ANY dependency on its rules.
   `position: relative` makes .evolution-desktop-nav itself the submenu's
   containing block directly and unambiguously (not "whichever ancestor
   happens to still be position:relative"), so `top: 100%` on the submenu
   resolves against exactly this element's own height - the trigger row's
   own bottom edge, nothing taller/shorter - eliminating any hover dead-zone
   from an ambiguous or mismeasured containing block. */
.evolution-desktop-nav {
    display: block;
    position: relative;
}

.evolution-primary-nav {
    display: none;
}

/* max-width/margin/padding here (not on .evolution-desktop-nav itself)
   replicates exactly what .evolution-menu-panel__inner previously provided
   for free (its own max-width:1340px;margin:auto, plus its
   has-global-padding class's 24px inset - theme.json's
   styles.spacing.padding, spacing preset "50" = 1.5rem) - so the trigger
   row's own visual position/centering is unchanged; only the submenu's
   positioning context (the now-full-width, self-contained
   .evolution-desktop-nav) has changed. */
.evolution-desktop-nav__list {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 44px;
    list-style: none;
    max-width: 1340px;
    margin: 0 auto;
    padding: 0 24px;
    box-sizing: border-box;
}

.evolution-desktop-nav__list > li {
    position: static;
}

.evolution-desktop-nav__list > li > a {
    display: block;
    padding: 18px 0;
    color: #ffffff;
    text-decoration: none;
    font-weight: 700;
}

.evolution-desktop-nav__list > li > a:hover,
.evolution-desktop-nav__list > li > a:focus,
.evolution-desktop-nav__list > li.current-menu-item > a,
.evolution-desktop-nav__list > li.current-menu-ancestor > a,
.evolution-desktop-nav__list > li.current_page_item > a,
.evolution-desktop-nav__list > li.current_page_ancestor > a {
    color: var(--evolution-header-accent);
}

/* Submenu box: legacy's own values, read directly from menus.css and
   confirmed against production screenshots (see the git history of this
   file for the full trace) - an edge-to-edge panel sharing the dark bar's
   own left/right edges. Containing block is .evolution-desktop-nav itself
   (position:relative, set above) - NOT .evolution-menu-panel and NOT
   .evolution-menu-panel__inner - so this is unambiguous and self-contained:
   `left/right:0; width:100%` always resolve against exactly the full-width
   nav wrapper's own box, regardless of what either of those other ancestors
   do. `top: 100%` for the same reason resolves against
   .evolution-desktop-nav's own height (= the trigger row's height, its only
   content), so the panel's top edge sits exactly at the trigger row's own
   bottom edge with zero gap - the hover path from a top-level link straight
   down into the submenu never leaves the hovered <li>'s own rendered box.
   Content flush against the box's own left edge, min-height matching
   legacy's own explicit 270px. Hidden/shown by plain `display`, driven
   solely by :hover/:focus-within - a real boolean with no persisted state
   to fall out of sync, so a stale/leftover open panel (the earlier
   white-strip defect class) is not structurally possible here regardless of
   how fast the pointer moves between items. */
.evolution-desktop-nav__list > li > ul.sub-menu {
    display: none;
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    width: 100%;
    min-height: 270px;
    padding: 28px 34px 34px;
    background: #ffffff;
    box-shadow: 0 18px 36px rgba(15, 18, 22, 0.14);
    list-style: none;
    margin: 0;
    z-index: 2;
}

.evolution-desktop-nav__list > li:hover > ul.sub-menu,
.evolution-desktop-nav__list > li:focus-within > ul.sub-menu {
    display: block;
}

.evolution-desktop-nav__list > li > ul.sub-menu > li > a {
    display: block;
    padding: 9px 0;
    color: #151515;
    text-decoration: none;
    font-size: 14px;
    font-weight: 500;
}

.evolution-desktop-nav__list > li > ul.sub-menu > li > a:hover,
.evolution-desktop-nav__list > li > ul.sub-menu > li > a:focus,
.evolution-desktop-nav__list > li > ul.sub-menu > li.current-menu-item > a,
.evolution-desktop-nav__list > li > ul.sub-menu > li.current_page_item > a {
    color: var(--evolution-header-accent);
}

.evolution-primary-nav .wp-block-navigation__submenu-container .wp-block-navigation-item {
    width: 100%;
}

.evolution-primary-nav .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
    width: 100%;
    padding: 9px 0;
    color: #151515;
    font-size: 14px;
    font-weight: 500;
}

.evolution-primary-nav .wp-block-navigation__submenu-container .wp-block-navigation-item__content:hover,
.evolution-primary-nav .wp-block-navigation__submenu-container .wp-block-navigation-item__content:focus,
.evolution-primary-nav .wp-block-navigation__submenu-container .current-menu-item > .wp-block-navigation-item__content {
    color: var(--evolution-header-accent);
}

@font-face {
    font-family: "ElegantIcons";
    src: url("assets/fonts/ElegantIcons.woff") format("woff");
    font-weight: normal;
    font-style: normal;
    font-display: block;
}

.social_facebook,
.social_instagram,
.social_youtube {
    font-family: "ElegantIcons";
    font-style: normal;
    font-weight: normal;
    font-variant: normal;
    line-height: 1;
    text-transform: none;
    speak: none;
}

.social_facebook::before {
    content: "\e093";
}

.social_instagram::before {
    content: "\e09a";
}

.social_youtube::before {
    content: "\e0a3";
}

.react-footer.evolution-footer {
    position: relative;
    color: #ffffff;
    background-color: #1e1e1e;
    border-top: 0;
    font-family: Montserrat, var(--wp--preset--font-family--system-sans);
}

.react-footer .container {
    box-sizing: border-box;
    width: 100%;
    max-width: 1140px;
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
}

.react-footer .row {
    display: flex;
    flex-wrap: wrap;
    margin-right: -15px;
    margin-left: -15px;
}

.react-footer .col-lg-3 {
    box-sizing: border-box;
    position: relative;
    width: 100%;
    padding-right: 15px;
    padding-left: 15px;
}

.react-footer .footer-top {
    padding: 70px 0 43px;
}

.react-footer .footer-widget .footer-title {
    position: relative;
    margin: 0 0 20px;
    color: #ffffff;
    font-size: 18px;
    font-weight: 700;
    line-height: 24px;
}

.react-footer .footer-top .footer-menu ul,
.react-footer .footer-top .footer-menu .wp-block-navigation__container,
.react-footer .footer-top .footer-menu .wp-block-page-list,
.react-footer .footer-top .footer-menu .wp-block-navigation {
    display: block;
    gap: 0;
    margin: 0;
    padding: 0;
    list-style: none;
}

.react-footer .footer-top .footer-menu li,
.react-footer .footer-top .footer-menu .wp-block-navigation-item {
    display: block;
    margin: 0 0 6px;
    padding: 0;
    list-style: none;
}

.react-footer .footer-top .footer-menu li:last-child,
.react-footer .footer-top .footer-menu .wp-block-navigation-item:last-child {
    margin-bottom: 0;
}

.react-footer .footer-top .footer-menu li a,
.react-footer .footer-top .footer-menu .wp-block-navigation-item__content {
    position: relative;
    display: inline-block;
    padding: 0;
    color: #b7b7b9;
    font-size: 16px;
    font-weight: 400;
    line-height: 24px;
    text-decoration: none;
    transition: all 0.5s ease 0s;
}

.react-footer .footer-top .footer-menu li a::after,
.react-footer .footer-top .footer-menu .wp-block-navigation-item__content::after {
    position: relative;
    bottom: 0;
    left: 0;
    z-index: 1;
    display: block;
    width: 0;
    height: 1px;
    content: "";
    background-color: #d62b7b;
    transition: all 0.3s ease;
}

.react-footer.home-main .footer-top .footer-menu li a:hover,
.react-footer.home-main .footer-top .footer-menu li a:focus,
.react-footer.home-main .footer-top .footer-menu .wp-block-navigation-item__content:hover,
.react-footer.home-main .footer-top .footer-menu .wp-block-navigation-item__content:focus {
    color: #d62b7b;
    margin-left: 5px;
}

.react-footer .footer-top .footer-menu li a:hover::after,
.react-footer .footer-top .footer-menu li a:focus::after,
.react-footer .footer-top .footer-menu .wp-block-navigation-item__content:hover::after,
.react-footer .footer-top .footer-menu .wp-block-navigation-item__content:focus::after {
    width: 100%;
}

.react-footer .social-links {
    display: block;
    margin: 0 0 32px;
    padding: 0;
    list-style: none;
}

.react-footer .social-links li {
    display: inline-block;
    margin-right: 6px;
}

.react-footer .social-links li:last-child {
    margin-right: 0;
}

.react-footer .social-links li a {
    display: block;
    width: 44px;
    height: 44px;
    color: #ffffff;
    font-size: 13px;
    line-height: 43px;
    text-align: center;
    text-decoration: none;
    background: transparent;
    border: 2px solid rgba(255, 255, 255, 0.1);
    border-radius: 50%;
    transition: all 0.7s ease 0s;
}

.react-footer.home-main .social-links li a:hover,
.react-footer.home-main .social-links li a:focus {
    color: #ffffff;
    background: #d62b7b;
    border-color: #d62b7b;
}

.react-footer .footer-location {
    color: #b7b7b9;
}

.react-footer .footer-location p {
    margin: 0 0 6px;
}

.react-footer .footer-lheader {
    color: #ffffff;
}

.react-footer .footer-or {
    padding-bottom: 3px;
    margin: 0;
    color: #b7b7b9;
    font-size: 14px;
    font-weight: 400;
    line-height: 22px;
}

.react-footer .footer-representatives {
    margin: 0;
    padding: 0;
    list-style: none;
}

.react-footer .footer-representatives li::before {
    content: "\2022";
    margin-right: 5px;
}

.react-footer .copyright {
    text-align: center;
}

.react-footer .copyright .container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
    padding-top: 20px;
    padding-bottom: 20px;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.react-footer .copyright .react-copy-left {
    margin-bottom: 0;
    color: #a6a6a8;
    font-size: 14px;
    font-weight: 400;
    line-height: 22px;
}

.evolution-card {
    border: 1px solid var(--wp--preset--color--border);
    border-radius: var(--wp--custom--border-radius--medium);
}

.evolution-media-placeholder {
    display: grid;
    place-items: center;
    border-radius: var(--wp--custom--border-radius--medium);
}

.wp-block-pullquote {
    border-left-width: 4px;
}

@media (max-width: 700px) {
    body {
        --wp--style--root--padding-left: var(--wp--preset--spacing--40);
        --wp--style--root--padding-right: var(--wp--preset--spacing--40);
    }
}

@media (min-width: 992px) {
    .react-footer .col-lg-3 {
        flex: 0 0 25%;
        max-width: 25%;
    }
}

@media (max-width: 991px) {
    .evolution-header__inner {
        min-height: 91px;
    }

    .evolution-header__actions {
        gap: 18px;
    }

    .evolution-search-toggle {
        display: none;
    }

    .evolution-header-search {
        display: none !important;
    }

    .evolution-menu-panel {
        display: none;
        background: #ffffff;
        border-top: 1px solid #ececf2;
        border-bottom: 1px solid #ececf2;
    }

    .is-navigation-open .evolution-menu-panel {
        display: block;
    }

    .evolution-menu-panel__inner {
        display: block;
        min-height: 0;
        padding-top: 8px;
        padding-bottom: 8px;
    }

    .evolution-desktop-nav {
        display: none;
    }

    .evolution-primary-nav {
        display: block;
        min-height: 0;
        width: 100%;
        font-size: 15px;
    }

    .evolution-primary-nav .wp-block-navigation__container,
    .evolution-primary-nav .wp-block-page-list,
    .evolution-primary-nav .wp-block-navigation-item {
        width: 100%;
        align-items: stretch;
        gap: 0;
    }

    .evolution-primary-nav .wp-block-navigation__container {
        flex-direction: column;
    }

    .evolution-primary-nav .wp-block-navigation-item__content,
    .evolution-primary-nav .wp-block-navigation-submenu__toggle {
        justify-content: space-between;
        width: 100%;
        padding: 14px 14px 14px 24px;
        color: #151515;
        font-size: 15px;
        font-weight: 600;
        line-height: 1.25;
    }

    .evolution-primary-nav .wp-block-navigation-submenu {
        display: block;
    }

    .evolution-primary-nav .has-child .wp-block-navigation__submenu-container {
        position: static;
        display: none;
        width: 100%;
        padding: 0 0 8px;
        background: #ffffff;
        box-shadow: none;
        transform: none;
        opacity: 1;
        visibility: visible;
    }

    .evolution-primary-nav .has-child.is-submenu-open > .wp-block-navigation__submenu-container {
        display: block;
    }

    .evolution-primary-nav .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
        padding: 10px 14px 10px 42px;
        font-size: 14px;
    }

    .react-footer .footer-top {
        padding: 60px 0 33px;
    }

    .react-footer .md-mb-30 {
        margin-bottom: 30px;
    }

    .react-footer .footer-widget .footer-title {
        margin-bottom: 10px;
        font-size: 18px;
        line-height: 24px;
    }

    .react-footer .footer-top .footer-menu li a,
    .react-footer .footer-top .footer-menu .wp-block-navigation-item__content {
        font-size: 14px;
        line-height: 22px;
    }

    .react-footer .copyright .container {
        flex-wrap: wrap;
        justify-content: center;
    }

    .react-footer .copyright .react-copy-left {
        margin-top: 12px;
    }
}

@media (max-width: 575px) {
    .evolution-header__inner {
        gap: 16px;
    }

    .evolution-site-logo img {
        width: 150px;
        max-width: 150px;
    }

    .evolution-utility-nav {
        display: none;
    }
}

/* Scroll-to-top button - ported from legacy style.css:13770-13809
   (#backscrollUp, .home variant: pink #D62B7B background, 3px corners,
   40x40px, confirmed live) with one deliberate behaviour change the user
   asked for beyond legacy's plain "past a scroll threshold" trigger:
   visible only while actively scrolling UP, not just past the threshold
   (assets/js/scroll-top.js tracks scroll direction each frame). bottom:100px
   is a reasoned estimate to clear the Tawk.to chat bubble
   (evolution_print_tawk_widget() in functions.php) sitting at the same
   corner, not a pixel-measured value - Tawk's own widget renders in a
   cross-origin iframe this stylesheet cannot inspect, so this may need a
   visual nudge once seen live. */
.evolution-scroll-top {
    position: fixed;
    right: 27px;
    bottom: 100px;
    z-index: 99999;
    width: 40px;
    height: 40px;
    padding: 0;
    border: none;
    border-radius: 3px;
    background: #D62B7B;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    opacity: 0;
    visibility: hidden;
    transform: translateY(10px);
    transition: opacity 0.3s ease 0s, transform 0.3s ease 0s, visibility 0.3s ease 0s, background 0.3s ease 0s;
}

.evolution-scroll-top:hover {
    background: #2D2D73;
}

.evolution-scroll-top.is-visible {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

/* Prevent the homepage Testimonials Bootstrap row from extending past the viewport. */
.student_satisfaction-section.evolution-home-testimonials > .container-fluid > .row.align-items-center {
    margin-left: 0;
    margin-right: 0;
}
