/* ==========================================================================
   DIVLAB MENU — the mobile full-screen overlay
   --------------------------------------------------------------------------
   Pairs with dvl-menu.js. Standalone: it does not import from, or depend on,
   any other dvl-* module, and removing the pair removes the feature with no
   trace left on the header.

   WHAT THE SCRIPT OWNS AND WHAT THIS FILE OWNS
   The script injects the toggle and the overlay, reads the real links out of
   the Elementor header so the hrefs can never drift, and runs the GSAP
   timeline. Everything static — colour, type, layout, stacking — is here, so
   the look can be retuned without touching the choreography.

   BREAKPOINT
   767px, matching Elementor's mobile tab and every other module in this set.
   Above it this file does nothing at all: the desktop header keeps its
   inline nav and no overlay is ever built.
   ========================================================================== */

:root {
  --dvl-menu-bg: #3a301e;
  --dvl-menu-ink: #f2f2f2;

  /* 48px / -6% / Inter Light, from the Figma inspector. Line height reads
     "Auto" there, which for Inter at 48px resolves to ~58px — set explicitly
     rather than left to the browser, because "auto" differs between engines
     and this is a four-item list where the rhythm is the design. */
  --dvl-menu-size: 48px;
  --dvl-menu-leading: 58px;
  --dvl-menu-tracking: -0.06em;

  /* Measured off the storyboard: items sit at y 320 / 397 / 475 / 553 in the
     402x874 frame, a 78px pitch. 58 of that is the line box, so 20 is the
     gap between them. */
  --dvl-menu-gap: 20px;

  /* The same 24px gutter the rest of the mobile design uses. */
  --dvl-menu-gutter: 24px;
}

/* ==========================================================================
   THE OVERLAY
   --------------------------------------------------------------------------
   clip-path is what animates, not width/height or opacity.

   The storyboard opens from a thin dark bar pinned in the dead centre of the
   viewport and pushes outward to fill it. An inset() clip does exactly that
   and costs nothing: the element is always full-size and always composited,
   so the browser animates a clip rectangle rather than relaying out a
   full-screen box every frame. Measured off menu1, the bar is roughly 15px
   wide and 105px tall in a 402x874 frame, which is the inset below.

   visibility is carried alongside, because a clipped element is still
   hittable: without it the closed overlay would swallow every tap on the
   page underneath.
   ========================================================================== */
.dvl-menu {
  position: fixed;
  inset: 0;
  z-index: 9000;

  background: var(--dvl-menu-bg);
  clip-path: inset(44% 48% 44% 48%);
  visibility: hidden;
  outline: none !important;

  display: flex;
  align-items: center;

  /* The page behind must not scroll when a drag runs off the end of the
     menu. overscroll-behavior stops the chain; touch-action stops the
     gesture being interpreted as a page pan in the first place. */
  overscroll-behavior: contain;
  touch-action: none;

  /* No CSS transition anywhere on this element. GSAP writes clip-path every
     frame during the timeline, and a transition on a scripted property does
     not smooth it — it fights it, a full transition-duration behind. The
     same rule the pinned sections needed. */
  transition: none !important;
}

.dvl-menu.is-open {
  visibility: visible;
}

.dvl-menu__nav {
  display: flex;
  flex-direction: column;
  gap: var(--dvl-menu-gap);
  padding-left: var(--dvl-menu-gutter);
  padding-right: var(--dvl-menu-gutter);
  width: 100%;
  outline: none !important;
}

.dvl-menu__link {
  /* The type, exactly as the inspector gives it. */
  font-family: 'Inter', system-ui, sans-serif;
  font-weight: 300;
  font-size: var(--dvl-menu-size);
  line-height: var(--dvl-menu-leading);
  letter-spacing: var(--dvl-menu-tracking);
  color: var(--dvl-menu-ink);

  /* The source links read "DIV", "lab", "agency", "contact"; the storyboard
     sets all four in caps. Done here rather than by rewriting the strings,
     so the markup keeps whatever the editor typed. */
  text-transform: uppercase;

  text-decoration: none;
  display: block;
  width: max-content;

  /* Each link starts displaced and invisible; the timeline brings it in.
     Declared here rather than only in script so there is no frame between
     the overlay opening and GSAP's first write where all four are visible
     in their final position. */
  opacity: 0;
  transform: translateY(20px);

  outline: none !important;
  outline-width: 0 !important;
  box-shadow: none !important;
  border: none !important;
  -webkit-tap-highlight-color: transparent !important;
  -webkit-touch-callout: none;
  user-select: none;
}

/* ---- ONE INK FOR ALL FOUR, INCLUDING THE ONE WITH NO href -------------
   The theme's reset.css carries

     a:not([href]):not([tabindex]),
     a:not([href]):not([tabindex]):focus,
     a:not([href]):not([tabindex]):hover { color: inherit }

   which is (0,2,1) and outranks `.dvl-menu__link` at (0,1,0). It matches
   exactly one element — LAB, the entry with no href — so three links took
   the design colour and the fourth inherited its way down to the theme's
   #333. Measured: rgb(242,242,242) on DIV, AGENCY and CONTACT against
   rgb(51,51,51) on LAB.

   Every state is pinned, not just the resting one: the same reset colours
   :hover and :focus, and iOS paints :active on touch. Listing them here
   means a tap cannot flash a different colour part-way through.

   -webkit-tap-highlight-color stays transparent. Setting it to transparent
   is what REMOVES the blue iOS flash — removing the declaration would bring
   the flash back, which is the opposite of what it looks like it does. */
.dvl-menu .dvl-menu__link,
.dvl-menu .dvl-menu__link:link,
.dvl-menu .dvl-menu__link:visited,
.dvl-menu .dvl-menu__link:hover,
.dvl-menu .dvl-menu__link:active,
.dvl-menu .dvl-menu__link:focus,
.dvl-menu .dvl-menu__link:focus-visible {
  color: var(--dvl-menu-ink) !important;
  -webkit-text-fill-color: var(--dvl-menu-ink);
  -webkit-tap-highlight-color: transparent !important;
  text-decoration: none;
  outline: none !important;
  outline-width: 0 !important;
  box-shadow: none !important;
  border: none !important;
  -webkit-touch-callout: none;
  user-select: none;
  /* DELIBERATELY NO opacity HERE. It is the property the reveal timeline
     animates from 0 to 1, and pinning it in a state rule would freeze every
     link visible before the sheet has opened. */
}

.dvl-menu__link:focus-visible,
.dvl-menu__link:focus {
  outline: none !important;
  outline-width: 0 !important;
  box-shadow: none !important;
}

/* ==========================================================================
   THE TOGGLE — two lines that become an X
   --------------------------------------------------------------------------
   Injected by the script because the Elementor header has no burger widget
   at all: measured on the live page, the mobile header renders the DESKTOP
   inline nav at 12px instead. That nav is hidden below.

   Drawn from two spans rather than shipped as an icon: it has to morph, and
   two elements that rotate into a cross is the whole animation with no asset
   and no request.
   ========================================================================== */
.dvl-burger {
  display: none;              /* desktop: never */
  position: relative;
  width: 40px;
  height: 40px;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer !important;
  pointer-events: auto !important;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  /* Above the overlay, so the same control closes what it opened. */
  z-index: 9500;
}

/* ---- THE THEME PAINTS A MAGENTA BOX ON EVERY BUTTON IT CAN REACH ------
   reset.css carries

     [type="button"]:focus, [type="button"]:hover,
     [type="submit"]:focus, [type="submit"]:hover,
     button:focus, button:hover { background: rgb(204, 51, 102) }

   A <button> is what this toggle is, so a tap put a solid #cc3366 square
   behind it — and because a tap leaves :focus set, it stayed there after
   the finger lifted. That is the persistent magenta box in the review
   screenshots; it was never a tap highlight, which is why turning the
   highlight off did nothing.

   Every interactive state is neutralised rather than just :focus. :hover
   is in the same reset rule and fires on touch devices too, and the theme
   also styles :focus-visible. appearance:none drops the last of the UA
   button chrome underneath all of it. */
.dvl-burger,
.dvl-burger:hover,
.dvl-burger:focus,
.dvl-burger:active,
.dvl-burger:focus-visible,
.dvl-burger:focus-within {
  -webkit-appearance: none;
  appearance: none;
  background: transparent !important;
  background-image: none !important;
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  outline: none !important;
  -webkit-tap-highlight-color: transparent !important;
}

/* Keyboard users still need to see where they are. No box shadows or borders. */
.dvl-burger:focus-visible .dvl-burger__line {
  box-shadow: none !important;
}

.dvl-burger__line {
  position: absolute;
  left: 50%;
  width: var(--dvl-burger-line, 34px);
  height: 2px;
  background: var(--divlab-font-dark, #3a301e);
  transform: translateX(-50%);
  transition: transform .34s cubic-bezier(.22, .61, .36, 1),
              background-color .34s ease,
              opacity .2s ease;
}

/* Two lines, 10px apart, centred in the 40px box.

   Sized against the logo rather than against nothing: the logo is set to
   40x40 below, so a 34px mark with a 10px gap reads as its optical equal —
   a full-width 40px rule would look heavier than the mark opposite it,
   because the logo's own glyphs do not reach its box edges. The 40px button
   stays as the tap target regardless of how wide the lines are drawn. */
.dvl-burger__line:nth-child(1) { top: calc(50% - 6px); }
.dvl-burger__line:nth-child(2) { top: calc(50% + 4px); }

/* Inverted state over dark sections (e.g. stage 5 outro on Agency page) */
body.is-dark-chrome:not(.dvl-menu-open) .dvl-burger__line,
body.dvl-agency-page.is-dark-chrome:not(.dvl-menu-open) .dvl-burger__line {
  background: var(--dvl-chrome-ink, #f7f6f2) !important;
  background-color: var(--dvl-chrome-ink, #f7f6f2) !important;
}

/* ==========================================================================
   MENU OPEN — the inverted state
   --------------------------------------------------------------------------
   body.dvl-menu-open is the single switch. It is on <body> rather than on
   the header so that the header, the toggle and the page lock can all read
   one state.
   ========================================================================== */

/* The burger becomes an X. Both lines move to the centre line and cross. */
body.dvl-menu-open .dvl-burger__line {
  background: var(--dvl-menu-ink, #f2f2f2) !important;
  background-color: var(--dvl-menu-ink, #f2f2f2) !important;
}
body.dvl-menu-open .dvl-burger__line:nth-child(1) {
  top: 50%;
  transform: translate(-50%, -50%) rotate(45deg);
}
body.dvl-menu-open .dvl-burger__line:nth-child(2) {
  top: 50%;
  transform: translate(-50%, -50%) rotate(-45deg);
}

/* THE HEADER HAS TO OUTRANK THE OVERLAY WHILE IT IS OPEN.

   The logo and the toggle sit ON the dark sheet in every storyboard frame,
   so the header is lifted above z-index 9000 for the duration.

   The three !important flags are not tidiness. dvl-stage.js owns the
   header's scroll lifecycle and writes transform, visibility and
   pointer-events as INLINE styles — and it hides the header through section
   2 and Selected Divs. Without these the menu could be opened and the header
   carrying its own close button would be invisible. !important is the only
   thing that outranks an inline style.

   Nothing here is cleared on close: the declarations simply stop applying
   with the class, and whatever the lifecycle had written inline is still
   there, so the header returns to exactly the state it was in. */
body.dvl-menu-open .dvl-header,
body.dvl-menu-open header.elementor-location-header {
  z-index: 9500 !important;
  transform: none !important;
  visibility: visible !important;
  pointer-events: auto !important;
}

/* The logo is a PNG, not an inline SVG, so `color` cannot reach it —
   measured on the live page: <img src="png-logo-scaled-1.png">. A filter is
   the only way to recolour raster artwork.

   brightness(0) crushes it to pure black whatever it started as, then
   invert() lifts it to a flat tone; 0.949 lands on #f2f2f2 rather than the
   #ffffff a plain invert(1) would give. */
body.dvl-menu-open .dvl-header img,
body.dvl-menu-open header.elementor-location-header img,
body.dvl-menu-open [data-elementor-type="header"] img,
body.dvl-menu-open #site-header img,
body.dvl-menu-open .elementor-widget-theme-site-logo img,
body.dvl-menu-open .elementor-widget-image img {
  filter: brightness(0) invert(0.949) !important;
  -webkit-filter: brightness(0) invert(0.949) !important;
  opacity: 1 !important;
  visibility: visible !important;
}

/* Page lock. overflow on the root rather than position:fixed on <body>:
   this page is driven by ScrollTrigger pins, and taking <body> out of flow
   would invalidate every pin's measurements and force a reflow of the whole
   timeline on open and again on close. */
html.dvl-menu-locked,
html.dvl-menu-locked body {
  overflow: hidden !important;
  overscroll-behavior: none;
}

/* ==========================================================================
   MOBILE ONLY
   ========================================================================== */
@media (max-width: 767px), ((max-height: 550px) and (orientation: landscape)) {
  .dvl-burger {
    display: block;
  }

  /* THE LOGO AT 40x40.

     Measured on the live page it rendered 28x24 — Elementor sizes the image
     widget, and the two header marks were visibly mismatched against a 40px
     toggle. object-fit: contain rather than a plain width/height pair so a
     logo whose own aspect is not square is letterboxed inside the 40px box
     instead of being stretched to fill it.

     Scoped to the header and flagged, because the widget's own width is
     written as a per-element Elementor rule that a plain selector loses to.
     The wrapper is released as well — sizing the <img> alone leaves it
     inside a 28px box and the extra 12px simply overflows. */
  .dvl-header img,
  header.elementor-location-header img,
  [data-elementor-type="header"] img,
  #site-header img {
    width: 40px !important;
    height: 40px !important;
    max-width: none !important;
    object-fit: contain;
  }

  .dvl-header *:has(> img),
  header.elementor-location-header *:has(> img),
  [data-elementor-type="header"] *:has(> img),
  #site-header *:has(> img) {
    width: auto !important;
    max-width: none !important;
  }

  /* The desktop inline nav and the Contact button are replaced by the
     overlay at this width. They are still in the DOM — the script reads the
     links out of them — but they must not paint.

     Scoped to the header so an icon list anywhere else on the page is
     untouched. */
  .dvl-header .elementor-icon-list--layout-inline,
  .dvl-header .elementor-widget-button {
    display: none !important;
  }
}

/* ==========================================================================
   LANDSCAPE MOBILE (2x2 Grid Layout & Safe Insets)
   --------------------------------------------------------------------------
   In landscape orientation on mobile phones, viewport height is very limited
   (~320px - 420px), while horizontal width is generous.
   Instead of a tall 1-column list that overflows and collides with the top-left
   header logo, we arrange the 4 menu links into a balanced 2x2 grid:
     Row 1: DIV        LAB
     Row 2: AGENCY     CONTACT
   with ample breathing room, proportionate font size, and safe-area padding.
   ========================================================================== */
@media (orientation: landscape) and (max-height: 550px),
       (orientation: landscape) and (max-width: 1024px) and (max-height: 600px) {
  .dvl-menu {
    align-items: center;
    justify-content: flex-start;
    padding-top: max(60px, calc(env(safe-area-inset-top) + 48px));
    padding-bottom: max(20px, env(safe-area-inset-bottom));
    padding-left: max(40px, calc(env(safe-area-inset-left) + 24px));
    padding-right: max(40px, calc(env(safe-area-inset-right) + 24px));
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }

  .dvl-menu__nav {
    display: grid;
    grid-template-columns: repeat(2, minmax(max-content, auto));
    column-gap: clamp(48px, 12vw, 110px);
    row-gap: clamp(12px, 3vh, 22px);
    width: auto;
    max-width: min(820px, 92vw);
    padding-left: 0;
    padding-right: 0;
  }

  .dvl-menu__link {
    font-size: clamp(34px, 7.5vh, 42px);
    line-height: 1.15;
    margin: 0;
  }
}

/* Above the breakpoint the overlay is disabled for regular desktop, but permitted on landscape mobile */
@media (min-width: 768px) and (min-height: 551px) {
  .dvl-menu {
    display: none !important;
  }
}

/* Someone who asked for less motion gets the same menu without the sweep:
   it appears and disappears, fully formed. */
@media (prefers-reduced-motion: reduce) {
  .dvl-menu__link {
    transform: none;
  }
  .dvl-burger__line {
    transition: none;
  }
}
