/* SchoolCMS – Menu (template-parts/menu/)
   Burlington House School full-screen menu, from `menus/desktop`
   13024:443 (tier-1 10001:593, tier-2 10001:745, tier-3 10001:803) and
   `menus/mobile` 13024:444 (10001:645 / 10001:681 / 10001:715). A PLUM
   overlay (rectangle-28 in tier-1 10001:593 binds brand/plum; the mobile
   set binds no purple at all – corrected from purple 2026-09-14) under
   the fixed header bar, the logo-mark outline ghosted across it. ONE wp_nav_menu tree (menu.php) is both appearances:
   mobile-first it is a drill-down – an opened parent's list replaces
   its own (`.drilled` on the list, `.open` on the parent, menu.js) with
   Back above and the quick links at the foot; from 992px the tiers are
   columns – serif tier-1 left, tier-2 and tier-3 in hairline-bordered
   columns to its right, revealed as a parent opens. Item states come
   from `components/about-us` 10001:864 and `components/our-team`
   10001:869: Default white, Hover grey-600b (also the open parent). */

/* Locking the scroll removes the scrollbar, which widens the viewport by
   its width and shifts everything centred or right-aligned – the fixed
   bar's logo and utilities most visibly – on open, and back on close.
   Reserving a gutter instead would leave an empty strip only the root
   background could colour, so let the scrollbar go and give its width
   back – as a BORDER in the menu's plum, not padding. A padding strip
   is painted by the body's white and showed as a white bar against the
   banner until the panel had covered it; the border is the panel's own
   colour from the first frame, so the strip reads as the panel's edge
   arriving with it. The fixed .site-header (nav.css) and the panel
   below take the width as padding – nothing paints there. --sbw is
   measured in menu.js – Cathedral's fix. */
body.menu-open {
    overflow:     hidden;
    border-right: var(--sbw, 0px) solid var(--color-plum);

    /* The Innermedia Dev Tools badge and its grid overlay are fixed to
       the viewport and know nothing about the scroll lock, so both slid
       across by the scrollbar's width every time the menu opened – on
       desktop as well as mobile (reported 2026-09-15). They are a
       plugin's elements and not the theme's to restyle, but it is the
       theme's scroll lock that moves them, so the compensation belongs
       here with the rest of --sbw. The badge's placement is the
       developer's choice: the three right-hand anchors take the whole
       gutter, the two centred ones half of it (a centre on `left: 50%`
       travels half of what the viewport gains), and the left-hand
       anchors do not move at all.
       BASE: every schoolcms site runs this plugin. */
    .im-devtools--corner-top-right,
    .im-devtools--corner-bottom-right,
    .im-devtools--middle-right {
        margin-right: var(--sbw, 0px);
    }

    .im-devtools--middle-top,
    .im-devtools--middle-bottom {
        margin-left: calc(var(--sbw, 0px) / -2);
    }

    #grid-overlay {
        padding-right: var(--sbw, 0px);
    }
}

.siteMenu {
    position:   fixed;
    inset:      0;
    z-index:    90;
    background: var(--color-plum);
    color:      var(--color-white);
    overflow:   hidden;
    isolation:  isolate;
    /* "slides in from the right" – the annotation on the tier-1 frame
       10001:593 (missed by the 2026-09-08 build, which read the frame's
       leaves only and faded the panel in; corrected 2026-09-14). The
       mechanism is Cathedral's #navbar: the panel rests one width off
       the right edge and translates in over --transition-slow; on close
       it slides back out and only THEN goes visibility: hidden (the 0s
       transition delayed by the slide), so it is never hidden mid-flight
       and never focusable while off screen. */
    translate:  100% 0;
    visibility: hidden;
    transition: translate var(--transition-slow), visibility 0s var(--transition-slow);

    .menu-open & {
        translate:  0 0;
        visibility: visible;
        transition: translate var(--transition-slow), visibility 0s;
        /* the panel spans the strip the hidden scrollbar frees; padding
           it back keeps the columns' percentages on the width the closed
           state had, so nothing inside reflows during the slide – the
           plum still fills inset: 0 (--sbw, menu.js) */
        padding-right: var(--sbw, 0px);
    }

    /* The logo-mark outline – one huge rotated copy (mask-group
       10001:647 mobile / 10001:595 desktop), its lower-left sweep
       crossing the panel.

       The mark is ROTATED, so get_metadata's numbers are not the shape:
       its width/height are the rotated node's BOUNDING BOX (1.2645× the
       square at 18.38deg) and its x is the rotated top-left CORNER, not
       the box's left edge. The 2026-09-08 build took both at face value
       and drew the mark 26% oversized and ~795px too far right (the
       corner offset, height × sin 18.38°); corrected 2026-09-14 from the
       design context's own layout, which gives the shape before the
       rotation and the box it is centred in:

         mobile   panel 360×640    – 2522×2521, centre (1024, 380)
         desktop  panel 1560×904   – 3564×3575, centre (1447, 539)

       The centre is held against the viewport's middle, as the build
       had it, so a wider window keeps the mark's left arcs over the
       menu rather than pulling its outer edge into view.

       It arrives last: absent while the panel slides, then fading up to
       its drawn 5% and settling out of a 1.05 zoom – starting 100ms into
       the open, over 1.2s (developer's call, 2026-09-14; the file draws
       the pattern only in its settled state). Closing takes it back out
       with the slide, no delay. */
    &::before {
        content:        '';
        position:       absolute;
        z-index:        -1;
        top:            380px;
        left:           calc(50% + 844px);
        width:          2522px;
        height:         2521px;
        translate:      -50% -50%;
        rotate:         18.38deg;
        scale:          1.05;
        background:     var(--color-white);
        opacity:        0;
        mask:           url(../../images/icons/logo-mark-outline.svg) center / contain no-repeat;
        -webkit-mask:   url(../../images/icons/logo-mark-outline.svg) center / contain no-repeat;
        pointer-events: none;
        transition:     opacity var(--transition-slow), scale var(--transition-slow);

        @media (min-width: 992px) {
            top:    539px;
            left:   calc(50% + 667px);
            width:  3564px;
            height: 3575px;
        }
    }

    .menu-open &::before {
        opacity:    0.05;
        scale:      1;
        transition: opacity 1.2s ease 0.1s, scale 1.2s ease 0.1s;
    }

    /* the scrolling layer – a column on mobile so the quick links sit
       at the foot; on desktop the tier columns are positioned inside it */
    .siteMenuInner {
        position:       relative;
        display:        flex;
        flex-direction: column;
        height:         100%;
        /* THE 75px FOOT IS ROOM FOR THE PAGE'S OWN FURNITURE, not padding.
           The cookie and accessibility buttons float over the panel's
           bottom-left corner, and the file draws the quick links clear above
           them: `accessibility-icons-1` 10001:674 is 81 × 43 sitting 15px
           off the bottom of the 640 panel, with the last link ending 17px
           above it. The links sat where those buttons land – invisible while
           the plugins are off, and under them the moment they are on
           (2026-09-15). It is the SCROLLER's padding rather than the foot's,
           so a list long enough to scroll also ends clear of them.

           THE TOP IS 81, NOT THE DRAWN 89. The file puts Back at 89 on its
           640px canvas (10001:681 `back` y 89), 8px under the disc's bottom
           edge (group-126, 15 + 66). On a shorter phone the tree ran out of
           room at the OTHER end: at 614px tall the scroller's content came
           to 653, so the foot could not float up to this 75px pad and the
           last quick link ended 20px INTO the CookieYes revisit disc (45px,
           15 from the bottom and left – the plugin's, not the theme's; the
           file draws the accessibility widget there instead). Charlie's
           call, 2026-09-30: take the room from the top, not the foot. 8px
           here and 30px off .menuTiers below move the tree up 38px, which
           lands the foot on the drawn 565 at 640 and 18px clear of the disc
           at 614. Back sits on the disc's bottom edge, on the far side of
           the panel from it, 25px under the switcher (40..56). */
        padding:        81px 15px 75px;
        overflow-y:     auto;
        /* the contents settle in behind the panel rather than arriving
           with it (Cathedral's .navbarInner): a short hold, then the fade;
           on close they fade for the length of the slide-out */
        opacity:        0;
        transition:     opacity var(--transition-slow);

        @media (min-width: 992px) {
            display: block;
            padding: 177px 32px 60px 9.36%;
        }

        .menu-open & {
            opacity:    1;
            transition: opacity var(--transition-slow) 0.15s;
        }
    }

    ul {
        margin:     0;
        padding:    0;
        list-style: none;
    }

    a {
        display:         block;
        color:           var(--color-white);
        text-decoration: none;
        transition:      color var(--transition-base);

        &:hover,
        &:focus-visible {
            color: var(--color-grey-600b);
        }
    }

    /* ── Parent rows – a chevron saying the words open a tier ──
       The file draws none: `components/about-us` 10001:864 (tier-1) and
       `components/our-team` 10001:869 (tier-2) are the bare word, white
       by default and grey-600b on hover, in both states. But a parent's
       words are the TOGGLE here at every width rather than a link to its
       page (menu.js; the page itself is the alias row the walker injects
       below), and nothing said so except the cursor. Added 2026-09-14 at
       the developer's request: the theme's own chevron – the one the
       location switch uses – turned a quarter to point the way the tier
       opens, right on the drill-down and the desktop columns alike. It
       paints in `currentColor`, so it greys with its row on hover and
       while the tier is open, and no state is invented for it. The gaps
       are 3px short of the drawn ones because the turned glyph sits in
       the middle of its own box (14 wide, 8 of ink). */
    a.toggleItem {
        display:     flex;
        align-items: center;
        gap:         13px;

        &::after {
            content:          '';
            flex-shrink:      0;
            width:            14px;
            height:           8px;
            rotate:           -90deg;
            background-color: currentColor;
            mask:             url(../../images/icons/chevron-down.svg) center / contain no-repeat;
            -webkit-mask:     url(../../images/icons/chevron-down.svg) center / contain no-repeat;
        }

        /* ON THE CAP BAND, not the line box. `align-items: center` centres on
           the LINE box, and that only coincides with the cap band's centre
           where a face's ascent and descent happen to sit symmetrically
           around it. Kievit's very nearly do – tier-2's chevron lands within
           0.2px of its cap centre, which is why that tier reads right – but
           Cultura's do not, and tier-1's sat 2.6px high. Measured at 40px:
           ascent 39, descent 9, cap height 24.8, so the baseline is 40 from
           the line-box top, the cap band is 15.2..40 centred on 27.6, and the
           line box centres on 25. The 2.6px difference is 0.065em, which
           holds at 24px too – the metrics scale with the type. */
        &::after {
            translate: 0 0.065em;
        }

        /* The glyph is sized against its ROW's type, not shared across the
           tiers: tier-1 is 40px serif from 992px while tier-2 is 20px sans,
           so one figure cannot serve both. The turned chevron reads at half
           the type's size – 10px of visual height on tier-2's 20px, which is
           the one the developer confirmed looks right – so tier-1 takes 20px
           on its 40px. At 14px it was a third of its row and read as an
           afterthought beside the display type (2026-09-14). Below 992px
           tier-1 is 24px and 14px is already that half, so it stays. */
        @media (min-width: 992px) {

            &::after {
                /* the BOLD cut of the same chevron. A mask scales its stroke
                   with the mark, so sizing the hairline up to this row left it
                   at 1.17px against Cultura's 4px stems – a third of the
                   weight tier-2's 0.63px carries against Kievit's 1px. The two
                   files share a centreline and a viewBox, so only the stroke
                   differs: 2.5px here, which is tier-2's stroke-to-stem ratio
                   on this row's type. Shipped as a second file rather than an
                   edit to the shared one, per CLAUDE.md § Reading the design –
                   the hairline is still the right mark everywhere else,
                   including this same row below 992px where the type is 24px. */
                width:        20px;
                height:       11px;
                mask:         url(../../images/icons/chevron-down-bold.svg) center / contain no-repeat;
                -webkit-mask: url(../../images/icons/chevron-down-bold.svg) center / contain no-repeat;
            }
        }
    }

    .sub-menu a.toggleItem {
        gap: 9px;

        &::after {
            /* Back to the HAIRLINE. The bold cut is set on a.toggleItem inside
               the 992px query, and this rule outspecifies it only for what it
               declares – so the mask has to be restated here or tier-2 inherits
               the bold one, which it did until this line. Kievit at 20px wants
               the hairline: it is the weight the design's own rows carry.
               No nudge either – the cap-band correction above is Cultura's, and
               Kievit already lands on its own cap centre (within 0.2px). */
            translate:    0;
            width:        10px;
            height:       6px;
            mask:         url(../../images/icons/chevron-down.svg) center / contain no-repeat;
            -webkit-mask: url(../../images/icons/chevron-down.svg) center / contain no-repeat;
        }
    }

    /* ── Back – "‹ BACK", mobile drill-down only; keeps its line at
       tier-1 so the list never jumps ── */
    .menuBack {
        display:        flex;
        align-items:    center;
        /* the drawn gap is a typed space, and the angle already carries
           the row's 2.2px tracking after it – 3px lands the pair on the
           file's 46px */
        gap:            3px;
        width:          fit-content;
        padding:        0;
        border:         0;
        background:     none;
        font:           var(--text-12kx);
        text-transform: uppercase;
        letter-spacing: 2.2px;
        color:          var(--color-white);
        cursor:         pointer;
        visibility:     hidden;

        /* The mark is TYPE, not an icon: `back` 10001:675 is one text
           node reading "< BACK" in the same Kievit Extrabold as the
           word, so the angle carries the caps' own weight, size and
           baseline. Masking a chevron into it never matched – the
           rotated mark came out thinner and shorter than the letters
           beside it, whichever cut was used (2026-09-15). The pair after
           the slash is the alt text: empty, so a screen reader announces
           the button's label alone. */
        &::before {
            content: '<' / '';
        }

        @media (min-width: 992px) {
            display: none;
        }
    }

    &:not([data-depth="0"]) .menuBack {
        visibility: visible;
    }

    /* ── The tree ──
       12px under the Back line, not the drawn 42 (Back ends 105, the
       drilled list starts 147 – 10001:681): the second half of the 38px
       the tree moved up on 2026-09-30, see .siteMenuInner above. The
       Back line keeps its height at tier-1 (visibility, .menuBack), so
       the list sits at the same height whichever tier is showing – the
       7px tier-1 nudge below is the drawn 154/147 and is not a jump. */
    .menuTiers {
        margin-top: 12px;

        @media (min-width: 992px) {
            margin-top: 0;
        }
    }

    /* tier-1 – serif h3, 36px rows on mobile, 72px on desktop; the
       mobile list sits 7px lower than a drilled tier (154 vs 147) */
    .menu:not(.drilled) {
        padding-top: 7px;

        @media (min-width: 992px) {
            padding-top: 0;
        }
    }

    .menu > li {
        font: var(--text-40cl);

        & + li {
            margin-top: 6px;

            @media (min-width: 992px) {
                margin-top: 22px;
            }
        }
    }

    /* tier-2 and tier-3 – the design's 20px sans on both devices (the
       h4 token's mobile value, the h5 token's desktop value) */
    .sub-menu li {
        font: var(--text-30kl);

        @media (min-width: 992px) {
            font: var(--text-20kl);
        }

        & + li {
            margin-top: 17px;

            @media (min-width: 992px) {
                margin-top: 12px;
            }
        }
    }

    /* the parent whose tier is showing takes the hover colour */
    li.open > a {
        color: var(--color-grey-600b);
    }

    /* Tiers start hidden; menu.js opens a parent (`.open`) and, on
       mobile, marks its list `.drilled` so the siblings and the parent's
       own row give way to the children (10001:681). The parent's page
       stays reachable through the alias row the walker injects
       (`.submenu_parent`) – needed only here, where the parent's words
       are the toggle. */
    .sub-menu {
        display: none;
    }

    li.open > .sub-menu {
        display: block;
        /* "fade in from the…" – the annotation on the mobile tier-3 frame
           10001:715, truncated in the file itself; the direction is taken
           as the right, the way the drill travels and the panel arrives.
           display: none → block cannot transition, so arrival is a
           keyframe run (Cathedral's tiers do the same). Mobile only – the
           desktop columns carry no annotation. Missed by the 2026-09-08
           build (leaf-only design-context reads); added 2026-09-14. */
        animation: menuTierIn var(--transition-slow) both;

        @media (min-width: 992px) {
            animation: none;
        }
    }

    ul.drilled > li:not(.open),
    li.open > a.toggleItem {
        display: none;
    }

    @media (min-width: 992px) {
        ul.drilled > li:not(.open) {
            display: block;
        }

        li.open > a.toggleItem {
            display: flex;
        }

        /* The alias row shows on desktop too, because the parent's words
           are a toggle at every width (menu.js – Rikkyo's behaviour) and
           this is the only way to its own page. The design's tier-2
           column (10001:745) draws the children alone, so this is one
           row more than the mockup: the alternative is a page with no
           route to it, which no mockup intends. */

        /* the columns: tier-1 holds 38% (146→740 of 1560); tier-2 opens
           at the hairline, 24px below the tier-1 top, 40px in from its
           rule, 20% wide; tier-3 the same column again, to its right */
        .menu {
            width: 38%;
        }

        .menu > li > .sub-menu {
            position:     absolute;
            top:          201px;
            left:         47.4%;
            width:        20%;
            min-height:   276px;
            padding-left: 40px;
            border-left:  1px solid var(--color-white-60);
        }

        .menu > li > .sub-menu > li > .sub-menu {
            position:     absolute;
            top:          0;
            left:         100%;
            width:        100%;
            min-height:   276px;
            padding-left: 40px;
            border-left:  1px solid var(--color-white-60);
        }
    }

    /* ── Foot – the quick links, mobile only (the bar carries them
       from 992px) ── */
    .menuFoot {
        margin-top:  auto;
        padding-top: 48px;

        @media (min-width: 992px) {
            display: none;
        }

        li + li {
            margin-top: 18px;
        }

        a {
            font:           var(--text-12kx);
            text-transform: uppercase;
            letter-spacing: 2.2px;
        }
    }
}

@keyframes menuTierIn {
    from {
        opacity:   0;
        translate: 24px 0;
    }

    to {
        opacity:   1;
        translate: 0 0;
    }
}

/* Every open-state selector is repeated here: each carries one class
   more than its resting rule, so listing only the short form leaves the
   transition running for the state that actually moves. */
@media (prefers-reduced-motion: reduce) {
    .siteMenu,
    .menu-open .siteMenu,
    .siteMenu::before,
    .menu-open .siteMenu::before,
    .siteMenu .siteMenuInner,
    .menu-open .siteMenu .siteMenuInner,
    .siteMenu a {
        transition: none;
    }

    .siteMenu li.open > .sub-menu {
        animation: none;
    }
}
