/* Mega-menu: full-bleed dropdown panel on desktop, drill-down on small screens.

   Everything themeable is a custom property on .mm, and every default resolves to a site-theme.css
   token, so rebranding that one file rebrands the menu.

   Variants live at the bottom of this file as .mm--{name} token overrides - the markup, role
   filtering and drill-down are shared, so a new skin cannot fork the behaviour.

   Breakpoint is 768px. One tree, two layouts: nothing here hides content on small screens except
   the promo image and a promo explicitly marked desktop-only.
*/

.mm {
    --mm-bar-gap: 1.5rem;
    --mm-panel-top: 4rem;

    /* Ceiling on a promo sharing a row with link columns. The track is an equal share like any
       other, so this only bites on the wide tracks a low-column panel produces. */
    --mm-promo-width: 20rem;

    /* Every colour resolves to a --site-header-* shell token, so rebranding site-theme.css rebrands
       the menu. The fallbacks are the values site-theme.css ships, so the menu still renders if
       loaded without a theme.

       These read SHELL tokens, never brand roles. A theme may point --site-header-background at
       any colour, so the panel cannot infer its relationship to the bar - it is told. */
    --mm-fg: var(--site-header-text, #ffffff);
    --mm-fg-muted: rgba(255, 255, 255, .66);

    /* The panel's emphasis colour, which is not the brand accent. --site-color-accent is a brand
       role and is allowed to be a neutral - BioHorizons' is #adafb2 - and a neutral cannot pick
       anything out. Reading it here turned every column heading, Back and "All ..." the same flat
       grey. The shell token lets a theme nominate a colour that does the job. */
    --mm-accent: var(--site-header-panel-accent, #a8c95f);

    /* Text placed ON the accent where the accent is used as a fill. The default accent is a light
       green, so white here would be unreadable - the bug a hard-coded #ffffff was hiding. */
    --mm-accent-contrast: var(--site-header-panel-accent-contrast, #19324d);

    --mm-panel-bg: var(--site-header-panel-background, #10263b);
    --mm-panel-fg: var(--site-header-panel-text, #ffffff);
    --mm-panel-muted: var(--site-header-panel-muted, rgba(255, 255, 255, .66));
    --mm-panel-border: var(--site-header-panel-border, rgba(255, 255, 255, .12));
    /* Column headings have their own token rather than borrowing --site-header-panel-muted.
       Sharing it made the heading the same tone as the link descriptions under it, so the label
       for a group read as quieter than the group - hierarchy upside down. A theme that nominates
       nothing still gets the old muted value, so this changes nothing until a theme opts in. */
    --mm-panel-heading: var(--site-header-panel-heading, var(--site-header-panel-muted, rgba(255, 255, 255, .66)));

    --mm-promo-bg: rgba(255, 255, 255, .06);

    /* Transparent by default: the scrim is opt-in, and only the glass variant turns it on. */
    --mm-scrim: transparent;

    --mm-radius: .5rem;

    /* The corner on a staff-preview state box. Its own value rather than --mm-radius: the boxes
       are drawn round single words as often as round a whole link, and .5rem on a box the height
       of one line reads as a pill rather than as a marker. */
    --mm-state-radius: .1875rem;

    --mm-transition: 180ms cubic-bezier(.25, .46, .45, .94);

    position: relative;
    display: flex;
    align-items: center;
    flex: 1 1 auto;
}

.mm *,
.mm *::before,
.mm *::after {
    box-sizing: border-box;
}

/* ---------------------------------------------------------------------------
   Bar
   --------------------------------------------------------------------------- */

.mm__bar {
    display: flex;
    align-items: center;
    gap: var(--mm-bar-gap);
    list-style: none;
    margin: 0;
    padding: 0;
}

.mm-item {
    position: relative;
    display: flex;
    align-items: center;
}

.mm-item__link,
.mm-item__toggle {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .5rem 0;
    border: 0;
    background: none;
    color: var(--mm-fg);
    font: inherit;
    text-decoration: none;
    cursor: pointer;
}

.mm-item__link:hover,
.mm-item__link:focus-visible,
.mm-item__toggle:hover,
.mm-item__toggle:focus-visible {
    color: var(--mm-accent);
    text-decoration: none;
}

/* The chevron is a drill-down affordance, so it exists only in the small-screen menu. On desktop
   it is hidden - see the desktop block - and there is no open/closed rotation to animate. */
.mm-item__chevron {
    font-size: .625em;
}

/* ---------------------------------------------------------------------------
   Panel - desktop
   --------------------------------------------------------------------------- */

.mm-panel {
    background: var(--mm-panel-bg);
    color: var(--mm-panel-fg);
}

.mm-panel[hidden] {
    display: none;
}

/* Used on desktop only. A panel appearing against the bare page is worth a short fade; see the
   desktop block for why a panel replacing another one is not. */
@keyframes mm-panel-in {
    from {
        opacity: 0;
        transform: translateY(-.375rem);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

.mm-panel__inner {
    display: grid;
    /* Column count is derived from the child count and written onto the element by Razor, so the
       grid can never disagree with the tree. */
    grid-template-columns: repeat(var(--mm-columns, 4), minmax(0, 1fr));
    gap: 2rem;
    /* The PADDED cap, the same shape bootstrap-theme.css gives .container, so the first column
       starts on the logo's left edge at every width.

       max-width: var(--site-content-width) with 1.5rem of padding was out on both sides and in
       opposite directions. Above 1464px the box landed on the measure but its own padding pushed
       the columns 24px inside it, so they sat in from the logo; below 1464px nothing subtracted
       the page gutter, so the box ran to the window and the columns sat 24px from the edge while
       the logo was at 32px. Right for no one.

       Cap and padding have to move together: the cap carries the gutter (T + 2g) and the padding
       IS the gutter, which is the only combination where a centred padded box puts its content on
       the same measure as .site-container's border edge. Same arithmetic as the note in
       bootstrap-theme.css.

       Still max-width rather than width, deliberately - the dropdown variant and the small-screen
       block below both release this box with max-width: none / their own padding, and a width
       would not answer to that. */
    max-width: calc(var(--site-content-width) + var(--site-page-gutter) * 2);
    margin: 0 auto;
    padding: 2rem var(--site-page-gutter) 2.5rem;
}

/* Sentence case at the same size as the links beneath it, not small uppercase.

   This was .8125rem uppercase with letter-spacing, against 1rem links - a label set smaller than
   the things it labels, and capitals make a size look smaller still because there are no
   ascenders or descenders to read a word's shape from. The group label read as quieter than the
   group, which is the hierarchy upside down.

   Hierarchy now comes from weight and colour rather than size and case: the heading keeps 600 and
   --mm-panel-heading, the links drop to 400 and sit in --mm-panel-fg. letter-spacing goes with
   the capitals - it exists to open up uppercase and only loosens lowercase text.

   .mm-drop__group, the equivalent label in the simple dropdown, is deliberately NOT changed here:
   it is a different surface and was not part of the review. The two are worth reconciling at some
   point. */
.mm-col__heading {
    display: block;
    margin: 0 0 .75rem;
    font-size: 1rem;
    font-weight: var(--site-font-weight-semibold, 600);
    letter-spacing: normal;
    text-transform: none;
    color: var(--mm-panel-heading);
}

/* A heading is a heading whether or not it has a URL. Taking --mm-panel-fg would style a heading
   with a destination identically to its own children, so whether a group label looked like a label
   would depend on whether an author typed a URL into it. */
a.mm-col__heading--link {
    color: var(--mm-panel-heading);
    text-decoration: none;
}

/* Underline only. The resting colour is already the emphasis colour, so re-colouring on hover has
   nothing left to say - and pointing it at --mm-accent would have moved it between two oranges
   almost nobody can tell apart. */
a.mm-col__heading--link:hover,
a.mm-col__heading--link:focus-visible {
    text-decoration: underline;
}

.mm-col__links {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: .75rem;
}

.mm-link {
    display: block;
    color: var(--mm-panel-fg);
    text-decoration: none;
    border-radius: var(--mm-radius);
}

/* The anchor's own colour and decoration have to be stated, not just the title's. Site.css
   underlines a:hover and bootstrap-theme.css recolours it to --site-color-link-hover, both at
   (0,1,1), which outranks .mm-link's (0,1,0) text-decoration: none. So an underline appeared on
   the panel anyway, painted in currentColor - the body link palette - while the title inside
   moved to --mm-accent.

   That is where the menu's "two different oranges" came from: on BioHorizons, #eb8535 title text
   over a #b3560d underline, the second of which is a colour for links in prose and has no
   business on the header panel (it measures 2.73:1 there). These selectors are (0,2,0) and win.

   The description is why the underline sits on the title rather than the anchor: .mm-link is
   display: block, so underlining it would strike through both lines of a link that has one. */
.mm-link:hover,
.mm-link:focus-visible {
    color: var(--mm-accent);
    text-decoration: none;
}

.mm-link:hover .mm-link__title,
.mm-link:focus-visible .mm-link__title {
    color: var(--mm-accent);
    text-decoration: underline;
    text-underline-offset: .2em;
}

/* 400, not 600. The links and their column heading were both semibold, so the only thing setting
   them apart was colour - and at the same weight a column of links reads as a block of emphasis
   rather than a list. Regular weight here gives the heading above something to be heavier than.
   The hover state is unaffected: it changes colour and adds an underline, not weight, so nothing
   reflows when the pointer crosses an item. */
.mm-link__title {
    display: block;
    font-weight: 400;
    line-height: 1.3;
}

.mm-link__description {
    display: block;
    margin-top: .125rem;
    font-size: .8125rem;
    line-height: 1.4;
    color: var(--mm-panel-muted);
}

/* ---------------------------------------------------------------------------
   Promo
   --------------------------------------------------------------------------- */

.mm-promo {
    display: flex;
    flex-direction: column;
    gap: .625rem;
    padding: 1rem;
    border-radius: var(--mm-radius);
    background: var(--mm-promo-bg);
}

.mm-promo__media {
    margin: -.25rem 0 .25rem;
}

.mm-promo__image {
    display: block;
    width: 100%;
    height: auto;
    border-radius: calc(var(--mm-radius) - .125rem);
}

.mm-promo__headline {
    margin: 0;
    font-weight: 700;
    color: var(--mm-accent);
}

.mm-promo__body {
    margin: 0;
    font-size: .8125rem;
    line-height: 1.45;
    color: var(--mm-panel-muted);
}

.mm-promo__button {
    display: block;
    margin-top: auto;
    padding: .5rem .75rem;
    border-radius: calc(var(--mm-radius) - .125rem);
    background: var(--mm-accent);
    color: var(--mm-accent-contrast);
    font-size: .875rem;
    font-weight: 600;
    text-align: center;
    text-decoration: none;
}

.mm-promo__button:hover,
.mm-promo__button:focus-visible {
    filter: brightness(1.08);
    color: var(--mm-accent-contrast);
    text-decoration: none;
}

/* Drawer chrome, the panel's Back / "All ..." bar, and the scrim exist only at one breakpoint
   each - the first three in the drill-down, the scrim on desktop. */
.mm__drawer-toggle,
.mm__drawer-header,
.mm-panel__bar,
.mm-panel__close,
.mm-item__toggle-label,
.mm__scrim {
    display: none;
}

/* ---------------------------------------------------------------------------
   Desktop
   --------------------------------------------------------------------------- */

@media (min-width: 768px) {
    .mm__drawer {
        display: flex;
        flex: 1 1 auto;
        align-items: center;
    }

    /* The hover target has to touch the panel, or there is nowhere safe to put the pointer on
       the way down. The panel is position: fixed at the header's bottom edge; an item shorter than
       the header row leaves a gap that belongs to neither, and crossing it fires mouseleave and
       starts CLOSE_DELAY. Stretching the chain to fill the row puts the item's bottom edge exactly
       on the panel's top edge, with no measurement written down - so a theme that changes the
       header height cannot reopen the gap.

       align-self rather than flipping each parent's align-items: it moves only these four elements
       and leaves every sibling centred.

       Invisible by construction: hover is signalled by colour on .mm-item__link, never by a
       background on .mm-item, and .mm-item keeps align-items: center. Desktop only. */
    .mm,
    .mm__drawer,
    .mm__bar,
    .mm-item {
        align-self: stretch;
    }

    /* Nav links, not prose. Inheriting the body font outright makes the top-level links
       typographically identical to a paragraph. Weight does more of that work than size, so this
       drops one notch to 15px and raises the weight.

       The spacing moves INSIDE the link: .mm__bar's gap goes to 0 below and equal padding on each
       side reproduces the same visual separation while making the target cover it. */
    .mm-item__link,
    .mm-item__toggle {
        padding-inline: var(--mm-link-gap, .75rem);
        font-size: .9375rem;
        font-weight: var(--site-font-weight-medium, 500);
    }

    /* gap: 0 because the separation now lives inside the links as padding, above.

       flex and justify-content are the alignment axis: the bar fills the drawer, and where the
       links land inside it is whatever --site-nav-alignment says. The fallback is the arrangement
       this bar has always had, so a theme that never mentions it is unchanged. */
    .mm__bar {
        flex: 1 1 auto;
        gap: 0;
        justify-content: var(--site-nav-alignment, flex-start);
    }

    /* Separation from the brand. Bootstrap's own .navbar-brand { margin-right: 1rem } puts the logo
       closer to the first link than the links are to each other, so the brand reads as the first
       item in the list. Zeroed and replaced with a gap the menu owns.

       Desktop only - below 768px the brand sits beside the drawer toggle. */
    .navbar-brand {
        margin-right: 0;
    }

    .mm {
        margin-inline-start: var(--mm-brand-gap, 2rem);
    }

    /* Hover and focus on the bar read the HEADER accent, not the panel's. The base rule uses
       --mm-accent, correct inside the drawer where these toggles sit on the panel; on desktop the
       same elements sit on --site-header-background. Surface decides the token.

       Colour is NOT the only hover signal: the underline is. This used to be text-decoration:
       none, with a note saying colour alone carried the state and that --site-header-accent
       therefore had to sit far enough from --site-header-text to register as a change - something
       a contrast checker cannot measure, because it compares text to background and never text to
       the text it replaced.

       That requirement turned out to be one a theme cannot always meet. A brand may rule out a
       whole direction on the bar - BioHorizons rules out anything dark on orange - which leaves
       only values close to the resting text, and a hover a third of a shade away from white is
       not a hover. Carrying the state in the underline costs the theme nothing and lets the
       accent be chosen for the brand instead of against this constraint.

       A theme whose accent IS strongly separated from its header text loses nothing by this: it
       keeps the colour change and gains an underline. */
    .mm-item__link:hover,
    .mm-item__link:focus-visible,
    .mm-item__toggle:hover,
    .mm-item__toggle:focus-visible {
        color: var(--site-header-accent, var(--site-color-accent, #a8c95f));
        text-decoration: underline;
        text-underline-offset: .35em;
        text-decoration-thickness: 2px;
    }

    /* No chevron on the bar. Hovering or clicking a label already opens its panel, so the chevron
       was a second control beside every header item and it is what made the bar look busy. */
    .mm-item__chevron {
        display: none;
    }

    /* The toggle is still the disclosure control for anyone not using a pointer, so it cannot just
       be dropped. It sits out of the layout until it takes focus and then appears under its own
       label - positioned rather than reflowed, so focusing it never shifts the bar. */
    .mm-item__toggle {
        position: absolute;
        top: 100%;
        left: 0;
        width: 1px;
        height: 1px;
        padding: 0;
        overflow: hidden;
        clip-path: inset(50%);
    }

    .mm-item__toggle:focus {
        width: auto;
        height: auto;
        padding: .35rem .6rem;
        overflow: visible;
        clip-path: none;
        z-index: 1031;
        border-radius: var(--mm-radius);
        background: var(--mm-panel-bg);
        /* --mm-panel-fg, not --mm-fg. The pill is painted in the PANEL colour, so its text is
           panel text - the bar's text colour belongs to the bar. Reading --mm-fg here put the
           BioHorizons header colour (#212529) on the panel background (#292f37) at 1.14:1: the
           one control a keyboard user needs, and only they would ever have seen it. Same mistake
           as the hover accent and the panel background before it - surface decides the token. */
        color: var(--mm-panel-fg);
        white-space: nowrap;
    }

    .mm-item__toggle:focus .mm-item__toggle-label,
    .mm-item__toggle:focus .mm-item__chevron {
        display: inline-block;
    }

    /* Touch devices are also "desktop" at this width, and the rules above leave them no way in: the
       chevron is hidden, the toggle is clipped to 1px until focused, and the only other opener is
       mouseenter, which the JS gates on (hover: hover) and (pointer: fine). An iPad in landscape or
       a touch laptop matches this breakpoint and reports hover: none, so tapping a header item just
       followed its link.

       So where hovering is not available the toggle stops hiding and becomes the visible control in
       place of the link - same text, same position, same styling. The click handler was always
       bound; the target was not reachable. A plain item keeps its link, having no panel to open. */
    @media (hover: none), (pointer: coarse) {
        .mm-item:not(.mm-item--plain) > .mm-item__link {
            display: none;
        }

        .mm-item__toggle {
            position: static;
            width: auto;
            height: auto;
            padding: .5rem 0;
            overflow: visible;
            clip-path: none;
        }

        .mm-item__toggle .mm-item__toggle-label {
            display: inline;
        }

        /* Hiding the link takes away the header item's own destination, and on desktop the panel's
           "All ..." bar is hidden too - so without this a touch user could open Products but never
           reach the Products page. The drill-down solves this at small widths by moving the link
           into the panel; this does the same here. Back and the close button stay hidden: there is
           no drill-down to come back from at this width. */
        /* The focus pill belongs to the keyboard reveal, not to a tap. Above the breakpoint the toggle
       is clipped until focused and :focus paints it as a panel-coloured pill. In this block the
       toggle is already the visible bar control, so that styling would turn an ordinary tap into a
       dark box inside the coloured header. */
    .mm-item__toggle:focus {
        padding: .5rem 0;
        border-radius: 0;
        background: none;
        color: var(--mm-fg);
    }

    .mm-item__toggle:focus .mm-item__chevron {
        display: none;
    }

    /* Touch-at-desktop-width only - note the enclosing (hover: none), (pointer: coarse) query.
       A mouse closes the panel by leaving it, so this bar and its Close button exist on tablets
       and nowhere else. It is NOT on the desktop screenshots in the review.

       It still needs the measure, because it is a SIBLING of .mm-panel__inner rather than a child
       and so inherits nothing from it. Left at 1.5rem it would have become the odd one out the
       moment the columns moved: on a landscape tablet the Close button would sit 24px from the
       screen edge while the content it belongs to starts at the logo. The two agreed before only
       because both were wrong by the same amount. */
    .mm-item:not(.mm-item--plain) .mm-panel__bar {
            display: flex;
            justify-content: flex-end;
            max-width: calc(var(--site-content-width) + var(--site-page-gutter) * 2);
            margin-inline: auto;
            padding: 1rem var(--site-page-gutter) 0;
        }

        .mm-panel__back,
        .mm-panel__close {
            display: none;
        }
    }

    /* Full-bleed regardless of the header's container width. --mm-panel-top is written by
       navigation-megamenu.js from the header's own height, so the panel meets the bar exactly
       whatever a site's header measures. */
    .mm-panel {
        position: fixed;
        top: var(--mm-panel-top);
        left: 0;
        right: 0;
        z-index: 1030;
        border-top: 1px solid var(--mm-panel-border);
        box-shadow: 0 18px 40px rgba(0, 0, 0, .28);

        /* Visibility follows .is-open here, not the [hidden] attribute. The script clears [hidden]
           only after the drill-down's slide-out has had time to run, which on desktop left the
           outgoing panel painted over the incoming one for the length of that timer - two stacked
           panels of different heights, then a snap. That was the bad swap. */
        display: none;
    }

    .mm-item.is-open > .mm-panel {
        display: block;
        animation: mm-panel-in 140ms ease-out;
    }

    /* Replacing one open panel with another is instant. The box is already on screen at the same
       position, so fading the new one in reads as a flicker rather than a transition - the fade
       earns its place only when a panel appears against the page. */
    .mm-panel--instant {
        animation: none;
    }

    /* Inert as written, and kept deliberately. The base tracks are minmax(0, 1fr), so they already
       fill the container and there is no free space to distribute. It only starts doing anything
       if those tracks are given a fixed measure.

       Capping tracks at 18rem was tried and reverted: it fixes a two-column panel with no promo,
       but every low-column panel in the template reset also carries a promo, which takes a track -
       meanwhile the cap shrank the panels that do exist and left dead space. Measure before
       capping. */
    .mm-panel__inner {
        justify-content: start;
    }

    .mm-panel[data-mm-panel] .mm-col,
    .mm-panel[data-mm-panel] .mm-promo {
        min-width: 0;
    }

    /* A panel with a promo and few tracks sizes its columns to their content instead of splitting
       the row equally, so the promo lands beside the last column rather than across the panel
       from it.

       Equal 1fr tracks are right for a full panel and wrong for a sparse one. Services is one
       column of links plus a promo: two tracks, 684px each, links that need about 180px of it.
       Measured, that left a 640px hole in the middle of the panel - the thing the review calls
       "the gulf". Content-sized tracks close it to 32px, the same gutter every other panel has,
       at every width from 768px up.

       Scoped to --narrow, NOT applied to every panel, and that scoping is the whole point. The
       note further up this file records that capping tracks was tried once and reverted because
       it "shrank the panels that do exist and left dead space" - which is exactly right and still
       true: measured across the real menus, content-sizing everything costs Products 781px of
       trailing space and Company 889px, for no benefit, because their links already fill their
       tracks. The earlier attempt was not wrong about the mechanism, only about the scope.

       The trade on the panels this DOES touch: their slack moves from the middle of the panel to
       the end of it. Services ends up with around 1000px of trailing space. That is the review's
       stated preference - a gap between two pieces of content reads as a break in the content,
       trailing space reads as margin - but it is a real change in how a sparse panel looks, and
       it is the reason this is a deliberate opt-in class rather than a blanket rule. */
    .mm-panel--narrow .mm-panel__inner {
        grid-template-columns: repeat(var(--mm-columns, 2), minmax(0, max-content));
        justify-content: start;
    }

    /* The image is the only part of a promo whose height is not set by its own content, so a wide
       track turns straight into height: a two-track panel gives a 620px cell, and a 16:9 upload
       comes out 349px tall, which makes the promo set the row height and stretches the links
       beside it. The cap only bites there - a four-track panel's image is already under it.

       contain rather than cover, so a portrait cover or a tall product shot is shown whole inside
       that height instead of losing its top and bottom. The small-screen rule below still crops to
       16:9, where a full-width image has the room for it. */
    .mm-promo__image {
        max-height: 15rem;
        object-fit: contain;
    }

    /* Capped, and sat at the START of its track so it lands beside the links rather than across
       the panel from them.

       The cap is what stops a low-column panel handing the promo half the menu; justify-self only
       ever decided which edge of the track it sits on, and end put the whole of the track's spare
       width between the last link and the promo. Measured on the Company panel - one column of
       links plus a promo, so two 684px tracks - that was a 396px hole in the middle of the panel.
       With start it is 32px, the same gap as every other panel's inter-column gutter.

       It only moves anything when the promo's track is wider than --mm-promo-width, which is to
       say only on the panels where the hole was. A four-column panel's track is 254px, narrower
       than the cap, so the promo fills it and this declaration is inert.

       The trade, stated plainly: a low-column panel now ends with its spare width as trailing
       space on the right instead of as a gap in the middle. That is the point - a gap between two
       pieces of content reads as a break in the content, trailing space reads as margin. */
    .mm-panel--has-promo .mm-promo {
        max-width: var(--mm-promo-width);
        justify-self: start;
    }

    /* A header item carrying a promo and no columns leaves the panel with one cell, and that cell
       is the full width of the menu. Left alone the promo spans it: a 1300px image over one line
       of copy, which reads as a mistake rather than a feature panel. Holding it to a measure keeps
       the panel full-bleed while the promo stays the size a promo is everywhere else. */
    .mm-panel--single .mm-promo {
        max-width: 34rem;
        margin-inline: auto;
    }

    /* Nothing pushes the button down when the promo is not sharing a row with taller columns, so
       the auto top margin that aligns buttons across a panel has nothing to do here. */
    .mm-panel--single .mm-promo__button {
        margin-top: .25rem;
        align-self: flex-start;
        padding-inline: 1.25rem;
    }

    /* The scrim covers the page from the bottom of the header down. One z-index below the panel, and
       it never takes pointer events - closing on an outside click is the document handler's job.

       --mm-scrim is transparent unless a variant sets it, so this costs the other skins nothing.
       The visibility delay is what lets it fade out rather than vanish. */
    .mm__scrim {
        position: fixed;
        top: var(--mm-panel-top);
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 1029;
        display: block;
        background: var(--mm-scrim);
        opacity: 0;
        visibility: hidden;
        pointer-events: none;
        transition: opacity var(--mm-transition), visibility 0s linear 180ms;
    }

    .mm.mm-has-panel .mm__scrim {
        opacity: 1;
        visibility: visible;
        transition-delay: 0s;
    }
}

/* ---------------------------------------------------------------------------
   Variants
   Each is a token override and nothing more. Adding one here plus a wrapper partial in
   Views/Shared/Navigation is the whole job of shipping a new look.
   --------------------------------------------------------------------------- */

/* Glass: the panel is translucent over a blurred page, with a scrim behind it. The blur is the
   whole trick - without it, translucency just puts the page's own text and images directly behind
   the menu's. So the translucent background and the blur ship together, and anywhere the blur is
   not in effect the panel is opaque. There are two such places, below and in the @supports block. */
.mm--glass {
    --mm-panel-border: rgba(255, 255, 255, .18);
    --mm-promo-bg: rgba(255, 255, 255, .10);
    --mm-scrim: rgba(8, 13, 21, .42);
}

@media (min-width: 768px) {
    /* Translucency and blur are desktop-only. Below this width the variant keeps the opaque
       --mm-panel-bg: the drawer and the open panel both paint it and the panel covers the drawer,
       so a translucent fill would stack on a translucent fill. There is also no page around a
       full-screen drawer for the glass to sit over. */
    .mm--glass {
        --mm-panel-bg: color-mix(in srgb, var(--site-header-panel-background, #10263b) 74%, transparent);
    }

    .mm--glass .mm-panel {
        -webkit-backdrop-filter: blur(16px) saturate(140%);
        backdrop-filter: blur(16px) saturate(140%);
    }
}

/* No blur available, so the panel goes solid. Must stay after the block above to win the cascade -
   neither @media nor @supports adds specificity, so this is decided by source order alone. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .mm--glass {
        --mm-panel-bg: var(--site-header-panel-background, #10263b);
    }
}

/* Light: a pale sheet under the coloured bar instead of a darker box continuing it.

   Every value is derived, so this cannot drift toward black and cannot ignore a rebrand. It
   measures 12.8:1 from the seamless panel - a third option should be a different menu, not a
   slightly different shade of the first.

   Two values need explaining. The muted tone is mixed rather than taken from
   --site-color-text-muted, which is tuned for body copy on the page background and lands just
   under the line here. And the promo background is flipped to a dark wash: the shared default is
   a white film, which is invisible on a pale panel. */
.mm--light {
    --mm-panel-bg: var(--site-color-surface, #f8fafc);
    --mm-panel-fg: var(--site-color-text, #344054);
    --mm-panel-muted: color-mix(in srgb, var(--site-color-text, #344054) 80%, var(--site-color-surface, #f8fafc));
    /* No --mm-panel-heading here. Headings follow --site-header-panel-heading on every variant, so
       the theme makes that choice once instead of each skin making it again. */
    --mm-panel-border: var(--site-color-border, #d8dee7);

    /* The page's own link colour, which a theme is already required to keep legible on a light
       background - so Back and "All ..." inherit that guarantee instead of needing their own.
       The panel accent is not used here: it is chosen for a dark panel, and the BioHorizons one
       (#eb8535) measures 2.4:1 on this surface. */
    --mm-accent: var(--site-color-link, #087f8c);

    /* Text on the accent where the accent is a fill, e.g. the promo button. White clears 4.5:1 on
       both shipped link colours (4.94 on #b3560d, 4.75 on #087f8c). A theme choosing a paler link
       colour must check this pairing. */
    --mm-accent-contrast: #ffffff;

    --mm-promo-bg: rgba(0, 0, 0, .045);
}

/* ---------------------------------------------------------------------------
   Dropdown structure
   Not a skin. _DropdownMenu renders its own markup - a single list per item instead of a column
   grid - but keeps the .mm-* skeleton and data attributes, so navigation-megamenu.js drives it
   unchanged. These rules only reshape the panel.
   --------------------------------------------------------------------------- */

.mm-drop__list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.mm-drop__link {
    display: block;
    padding: .5rem 1.25rem;
    color: var(--mm-panel-fg);
    text-decoration: none;
    line-height: 1.35;
}

.mm-drop__link:hover,
.mm-drop__link:focus-visible {
    color: var(--mm-accent);
    text-decoration: none;
}

/* A level-2 item with no destination of its own, introducing the links beneath it. */
.mm-drop__group {
    display: block;
    padding: .75rem 1.25rem .25rem;
    color: var(--mm-panel-muted);
    font-size: .75rem;
    font-weight: var(--site-font-weight-semibold, 600);
    letter-spacing: .04em;
    text-transform: uppercase;
}

.mm-drop__item--nested .mm-drop__link {
    padding-left: 2rem;
}

@media (min-width: 768px) {
    /* Anchored to its own item rather than full-bleed. .mm-item is position: relative in the base
       rules, so this needs no extra positioning context - and it is why the desktop panel rule
       below has to be overridden rather than extended: that one is fixed and spans the viewport. */
    .mm--dropdown .mm-panel {
        position: absolute;
        top: 100%;
        left: 0;
        right: auto;
        width: max-content;
        min-width: 13rem;
        max-width: 22rem;
        border-top: 0;
        border-radius: 0 0 var(--mm-radius) var(--mm-radius);
        box-shadow: var(--site-shadow-medium, 0 8px 24px rgba(15, 23, 42, .18));
    }

    .mm--dropdown .mm-panel__inner {
        grid-template-columns: minmax(0, 1fr);
        gap: 0;
        max-width: none;
        margin: 0;
        padding: .5rem 0;
    }

    /* The scrim dims the page for a full-bleed panel. A dropdown is a small box over one corner of
       the header, so dimming the whole page for it reads as a modal that is not one. */
    .mm--dropdown .mm__scrim {
        display: none;
    }
}

/* ---------------------------------------------------------------------------
   Small screens - drill-down
   --------------------------------------------------------------------------- */

@media (max-width: 767.98px) {
    .mm__drawer-toggle {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        margin-left: auto;
        padding: .5rem;
        border: 0;
        background: none;
        color: var(--mm-fg);
        font-size: 1.25rem;
        cursor: pointer;
    }

    .mm__drawer {
        position: fixed;
        inset: 0;
        z-index: 1040;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        background: var(--mm-panel-bg);
        color: var(--mm-panel-fg);
        transform: translateX(100%);
        transition: transform var(--mm-transition);
        visibility: hidden;
    }

    .mm.is-drawer-open .mm__drawer {
        transform: translateX(0);
        visibility: visible;
    }

    .mm__drawer-header {
        display: flex;
        justify-content: flex-end;
        flex: 0 0 auto;
        padding: .75rem 1rem;
        border-bottom: 1px solid var(--mm-panel-border);
    }

    .mm__drawer-close {
        border: 0;
        background: none;
        color: var(--mm-panel-fg);
        font-size: 1.25rem;
        padding: .25rem .5rem;
        cursor: pointer;
    }

    .mm__bar {
        flex: 1 1 auto;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        overflow-y: auto;
    }

    /* position: static undoes the base rule, and it is load-bearing. The base .mm-item is
       position: relative so the desktop panel anchors to the row; left relative here it also
       becomes the containing block for the drill-down panel, which is inset: 0 - so the panel was
       sized to one row and everything below the Back bar was clipped. Static hands the job to
       .mm__drawer, which is fixed and is the layer the panel belongs to. */
    .mm-item {
        position: static;
        display: block;
        border-bottom: 1px solid var(--mm-panel-border);
    }

    /* The row is the drill-down control; the item's own destination moves into the panel as
       "All {title}". A plain item has no panel, so its link stays the row. */
    .mm-item__link {
        display: none;
    }

    .mm-item--plain .mm-item__link {
        display: block;
        padding: 1rem;
        color: var(--mm-panel-fg);
    }

    .mm-item__toggle {
        display: flex;
        width: 100%;
        justify-content: space-between;
        align-items: center;
        padding: 1rem;
        color: var(--mm-panel-fg);
        text-align: left;
    }

    .mm-item__toggle-label {
        display: inline;
        font-size: 1.0625rem;
    }

    /* Chevron points into the panel rather than down - this drills sideways, not expands. It does
       not change with open state, so there is nothing here for the open case to override. */
    .mm-item__chevron {
        font-size: .75em;
        transform: rotate(-90deg);
    }

    /* Each panel is a layer over the drawer. Sliding it in rather than expanding in place is what
       lets all three levels stay reachable: a nested accordion at this width is unusable, which is
       why the reference mockups dropped the third level entirely. */
    .mm-panel {
        position: absolute;
        inset: 0;
        z-index: 1;
        display: flex;
        flex-direction: column;
        overflow-y: auto;
        transform: translateX(100%);
        transition: transform var(--mm-transition);
    }

    .mm-panel[hidden] {
        /* Kept in the layout so the slide-in can animate; the script manages [hidden] for
           assistive technology and inert-ness. */
        display: flex;
        visibility: hidden;
    }

    .mm-item.is-open > .mm-panel {
        transform: translateX(0);
        visibility: visible;
    }

    .mm-panel__bar {
        display: flex;
        align-items: center;
        gap: 1rem;
        flex: 0 0 auto;
        padding: .75rem 1rem;
        border-bottom: 1px solid var(--mm-panel-border);
    }

    .mm-panel__close {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        flex: 0 0 auto;
        border: 0;
        background: none;
        padding: .25rem .5rem;
        color: var(--mm-panel-fg);
        font-size: 1.25rem;
        line-height: 1;
        cursor: pointer;
    }

    /* Back holds the left and everything else collects on the right. An auto margin rather than
       space-between on the bar, because "All ..." is conditional - with it absent, space-between
       would strand the close button and leave a hole in the middle. */
    .mm-panel__back {
        display: inline-flex;
        align-items: center;
        gap: .4rem;
        margin-right: auto;
        border: 0;
        background: none;
        padding: .25rem 0;
        color: var(--mm-accent);
        font: inherit;
        cursor: pointer;
    }

    .mm-panel__all {
        color: var(--mm-accent);
        font-weight: 600;
        text-decoration: none;
    }

    /* margin: 0 undoes the base rule's "margin: 0 auto". On desktop .mm-panel is a block, so those
       auto margins are ordinary block centring against max-width: 1320px. Here .mm-panel is a
       column flex container, and auto margins on the cross axis beat align-items: stretch - the
       grid stops filling the line, shrinks to its widest link and centres there.

       A promo hid this: its headline and body push the grid to nearly full width, so the leftover
       margin read as padding. */
    .mm-panel__inner {
        grid-template-columns: minmax(0, 1fr);
        gap: 1.75rem;
        margin: 0;
        padding: 1.25rem 1rem 2rem;
    }

    .mm-col__links {
        gap: 1rem;
    }

    /* Promos go full width at the end of their panel, and they keep their image. Hiding it ignored
       the promo's own "Show on small screens" switch, with nothing in the UI to explain why.

       The ratio is the part that made hiding it tempting: a tall image on a phone pushes the
       headline and button off the screen, so the box is pinned to 16:9 and the picture cropped to
       fill it rather than setting its own height. */
    .mm-promo__media {
        display: block;
    }

    .mm-promo__image {
        aspect-ratio: 16 / 9;
        height: auto;
        object-fit: cover;
    }

    .mm-promo--desktop-only {
        display: none;
    }
}

/* The drawer is full-screen, so the page behind it must not scroll underneath. Set by
   navigation-megamenu.js on <body> rather than on .mm, because that is the scrolling element. */
body.mm-drawer-open {
    overflow: hidden;
}

@media (min-width: 768px) {
    /* The drawer never opens above the breakpoint, but a resize mid-interaction could otherwise
       leave the page locked. */
    body.mm-drawer-open {
        overflow: visible;
    }
}

/* ---------------------------------------------------------------------------
   Reduced motion
   --------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    .mm__drawer,
    .mm-panel,
    .mm-item__chevron {
        transition: none;
    }

    .mm-item.is-open > .mm-panel {
        animation: none;
    }
}

/* ---------------------------------------------------------------------------
   Staff preview state markers
   ---------------------------------------------------------------------------
   Rendered only when SiteNavigationViewModel.IsPreview is true. The gate is in that view model,
   not here and not in the partials, so no partial can leak a marking to a visitor.

   SHAPE, NOT COLOUR. A line through a pending removal, a dashed box around an item in review, and
   nothing else. These classes land on the header bar and inside the panel, and the panel changes
   colour with the skin, so any fixed colour would have to be legible against all of them at once.
   A shape drawn in currentColor has no such question to answer. The two shapes are also
   unambiguous - a strike is something being taken away, a box something held pending a decision -
   so this needs no non-colour fallback; it IS the non-colour version.

   OUTLINE, NOT BORDER. outline is drawn outside the border box and takes no space, so a marked
   item occupies the same room as an unmarked one; a border would push its neighbours along.
   outline-offset lifts the box off the glyphs so it reads as an annotation.

   The strike goes on the text, because it is the text that is going away. The box goes round the
   whole unit - so on a level-3 link the box encloses the title and description together, while
   the strike crosses only the title. */

.mm-pending-removal .mm-label,
.mm-pending-removal.mm-item__toggle-label,
.mm-link.mm-pending-removal .mm-link__title {
    text-decoration: line-through;
    text-decoration-thickness: 1px;
}

/* An outline takes its corners from the border-radius of whatever it is drawn on, and the
   elements these boxes land on disagree: .mm-link carries --mm-radius while the label spans carry
   none, so the same marker came out rounded in the panel and square on the bar. So every state box
   states its own radius. Setting it on the labels is free, and on .mm-link it overrides a value
   that was inert - that element paints no background, border or shadow. */
.mm-in-review .mm-label,
.mm-in-review.mm-item__toggle-label {
    outline: 1px dashed currentColor;
    outline-offset: 2px;
    border-radius: var(--mm-state-radius);
}

/* A level-3 link is a block carrying a title and a description, so its box goes round the link
   itself rather than round the title alone - a box round the title with the description hanging
   outside it reads as marking the wrong thing. */
.mm-link.mm-in-review {
    outline: 1px dashed currentColor;
    outline-offset: 3px;
    border-radius: var(--mm-state-radius);
}

/* The description under a level-3 link is not the thing being removed - the link is - so it keeps
   its ordinary colour and carries no decoration. */
.mm-link.mm-pending-removal .mm-link__description,
.mm-link.mm-in-review .mm-link__description {
    text-decoration: none;
}

/* ---------------------------------------------------------------------------
   Where the visitor is
   ---------------------------------------------------------------------------
   NO VISIBLE MARKER, deliberately - the menu does not report where the visitor is.

   aria-current="page" is still set by the partials on the one link matching the request. It costs
   nothing visually and is what assistive technology announces. Anything styling [aria-current]
   here would put the marker back, so there is nothing to style. */
