/* ---------------------------------------------------------------------------
   UlricCMS shared mobile navigation. Pairs with core/assets/menu.js.

   One menu, three themes. Below the fold point every design opens the same
   way: the hamburger becomes an X, a panel unrolls out from under the header,
   its links climb in on a short ladder, and the page behind it dims. Above
   the fold point each theme keeps what it always had (ulric its inline row,
   scrub and fold their full-screen wipe), because that is where the designs
   are supposed to differ.

   The markup contract, and it is the whole contract:
     [data-menu-toggle]              the button, anywhere in the header
       .mbars > b, b, b              the three rules this sheet animates
     [data-menu-panel]               the panel. Its value is "mobile" if it is
                                     only a menu below the fold point (ulric's
                                     list is the desktop navigation as well),
                                     or "always" if it is a menu at every width
     body.menu-open                  the single piece of state, set by menu.js
   The backdrop is built by menu.js, so a page without JavaScript never gets
   an inert div it cannot dismiss.

   Dressing is per theme and comes only through custom properties, which is
   why there is not a single colour literal in the panel rules:
     --menu-top    where the panel hangs from (the header's height)
     --menu-bg --menu-ink --menu-line --menu-pad --menu-z --menu-veil-z

   Browser floor: Chrome 79. No :has(), no inset shorthand, no container
   queries, dvh only ever after a vh line that already works, and the flex
   gaps that matter carry a margin fallback under html.no-flexgap (menu.js
   measures the browser rather than guessing from @supports, which lies about
   flex gap because it answers for grid).
--------------------------------------------------------------------------- */

/* ---------- the button ---------- */
[data-menu-toggle] { -webkit-tap-highlight-color: transparent; }
[data-menu-toggle] .mbars { display: block; position: relative; width: 24px; height: 16px; }
[data-menu-toggle] .mbars b { position: absolute; top: 0; left: 0; right: 0; display: block;
  height: 2px; background: currentColor; border-radius: 2px;
  transition: transform .3s cubic-bezier(.6, 0, .2, 1), opacity .18s ease, width .3s ease; }
[data-menu-toggle] .mbars b:nth-child(2) { top: 7px; width: 64%; }
[data-menu-toggle] .mbars b:nth-child(3) { top: 14px; }
[data-menu-toggle][aria-expanded="true"] .mbars b:nth-child(1) { transform: translateY(7px) rotate(45deg); }
[data-menu-toggle][aria-expanded="true"] .mbars b:nth-child(2) { opacity: 0; }
[data-menu-toggle][aria-expanded="true"] .mbars b:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
/* the button is useless without the script that answers it */
html:not(.js) [data-menu-toggle] { display: none; }

/* The panel takes focus when it opens (menu.js), which is what a screen
   reader wants; it is not itself a control, so it does not wear a ring. Its
   links still do, and that is the ring a keyboard reader is looking for. */
[data-menu-panel]:focus { outline: none; }

/* ---------- the backdrop ---------- */
.menu-veil { position: fixed; top: 0; right: 0; bottom: 0; left: 0;
  z-index: var(--menu-veil-z, 43);
  background: rgba(22, 21, 19, .46);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .32s ease, visibility 0s linear .32s; }
body.menu-open .menu-veil { opacity: 1; visibility: visible; pointer-events: auto;
  transition: opacity .32s ease, visibility 0s linear 0s; }

/* ---------- the panel, below the fold point ---------- */
@media (max-width: 920px) {
  html.js [data-menu-panel] {
    position: fixed;
    top: var(--menu-top, 72px); left: 0; right: 0; bottom: auto;
    z-index: var(--menu-z, 49);
    margin: 0;
    padding: 6px var(--menu-pad, 20px) 26px;
    background: var(--menu-bg, #faf9f5);
    color: var(--menu-ink, inherit);
    border-bottom: 1px solid var(--menu-line, rgba(25, 25, 23, .12));
    box-shadow: 0 30px 44px -32px rgba(25, 25, 23, .5);
    /* vh first so every engine has a working answer, then dvh for the ones
       that know the phone's address bar comes and goes */
    max-height: calc(100vh - var(--menu-top, 72px));
    max-height: calc(100dvh - var(--menu-top, 72px));
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-12px);
    transition: transform .42s cubic-bezier(.2, .8, .25, 1), opacity .24s ease,
                visibility 0s linear .42s;
  }
  /* the unroll, where the engine can draw it. Without clip-path the panel
     still slides and fades, it just does not peel. */
  @supports (clip-path: inset(1px)) {
    html.js [data-menu-panel] { clip-path: inset(0 0 100% 0);
      transition: transform .42s cubic-bezier(.2, .8, .25, 1), opacity .24s ease,
                  clip-path .46s cubic-bezier(.2, .8, .25, 1), visibility 0s linear .46s; }
    html.js body.menu-open [data-menu-panel] { clip-path: inset(0 0 0 0); }
  }
  html.js body.menu-open [data-menu-panel] {
    opacity: 1; visibility: visible; transform: none;
    transition: transform .5s cubic-bezier(.2, .8, .25, 1), opacity .3s ease,
                clip-path .5s cubic-bezier(.2, .8, .25, 1), visibility 0s linear 0s;
  }

  /* the ladder. --i is set by menu.js, so a panel whose links were rendered
     without one still climbs in, all together, which is the honest fallback */
  html.js [data-menu-panel] a {
    opacity: 0; transform: translateY(12px);
    transition: opacity .22s ease, transform .22s ease;
  }
  html.js body.menu-open [data-menu-panel] a {
    opacity: 1; transform: none;
    transition: opacity .42s ease, transform .5s cubic-bezier(.2, .8, .3, 1);
    transition-delay: calc(120ms + var(--i, 0) * 42ms);
  }

  /* No script, no closed state: the panel is an ordinary block of links at the
     top of the page rather than nine pages behind a button that does nothing.
     Every hiding rule above is gated on html.js for exactly this. */
  html:not(.js) [data-menu-panel] {
    position: static; max-height: none; overflow: visible;
    opacity: 1; visibility: visible; transform: none;
    box-shadow: none;
  }
}

/* ---------- what the open menu takes over ---------- */
/* The rail and the design switch both live at the top of the screen. While
   the menu owns it, they get out of the way. */
body.menu-open #rail,
body.menu-open .tsw,
body.menu-open .theme-chips { opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .2s ease, visibility 0s linear .2s; }

/* ---------- scroll lock ---------- */
/* Deliberately not the position:fixed body trick. That one collapses the
   document's height, and on the scrub theme a collapsed document is a
   ScrollTrigger refresh reading a scroll of zero, which throws the reader to
   the top of a WebGL traverse. Overflow plus the touchmove guard in menu.js
   holds iOS without moving anything. */
html.menu-locked, html.menu-locked body { overflow: hidden; }

/* ---------- flex gap fallback (Chrome < 84, Safari < 14.1) ---------- */
html.no-flexgap .shd-side > * + * { margin-left: 20px; }
html.no-flexgap .nav-links > li + li { margin-left: 26px; }
@media (max-width: 920px) {
  html.no-flexgap .nav-links > li + li { margin-left: 0; }
}

/* ---------- reduced motion ---------- */
/* The panel still opens and closes, it just arrives instead of travelling.
   Nothing here may make it unreachable. */
@media (prefers-reduced-motion: reduce) {
  [data-menu-toggle] .mbars b,
  .menu-veil,
  html.js [data-menu-panel],
  html.js [data-menu-panel] a,
  html.js body.menu-open [data-menu-panel],
  html.js body.menu-open [data-menu-panel] a { transition: none; }
  html.js body.menu-open [data-menu-panel] a { transition-delay: 0s; }
}
