/**
 * Mechanism only – no styling of its own, no design opinions.
 *
 * Sticky, hide-on-scroll-down and show-on-scroll-up are the theme's and Ollie
 * Pro's job. This file adds what they have no concept of, plus two fixes.
 *
 * The public contract is two classes:
 *   .has-transparent-header  you add it to the header template part
 *   .is-scrolled             this plugin adds it once the page is scrolled
 *
 * The transparent state is the ABSENCE of `is-scrolled`, never a class of its
 * own. That is deliberate: a JavaScript-applied class cannot exist at first
 * paint, so making transparency the exception meant every page load rendered
 * the solid header first and then animated it away – a visible flash. Target
 * `:not(.is-scrolled)` for the top state and it is correct before any script
 * runs.
 */

/* Ollie Pro hides the header with
   translateY(calc(-100% - var(--sticky-full-offset))) but only ever sets that
   variable when a Top Offset is configured. The theme pins the header down by
   the admin bar's height regardless, so without this the group stops exactly
   that far short of the top. While the admin bar is fixed it masks the leftover
   band; at 600px and below core makes it absolute, it scrolls away, and the
   band shows as a strip of header hanging at the top of the screen. */
.wp-block-group[data-sticky-on-scroll-up="true"] {
  --sticky-full-offset: var(--wp-admin--admin-bar--height, 0px);
}

/* Sit the header flush at the top once the admin bar has scrolled away. Ollie
   pins every sticky header down by the admin bar's height
   (`top: calc(var(--wp-admin--admin-bar--height))`). At 600px and below core
   makes the admin bar `absolute`, so it scrolls off with the page, but that
   offset stays 46px – leaving the header resting below an empty band. Ollie
   ships a reset for exactly this (`@media (max-width: 600px) { … top: 0 }`) but
   it never applies: its own unscoped base rule outweighs it (0,2,2 vs 0,1,1),
   and media queries add no specificity. This restores the reset with a selector
   that outweighs the base rule (0,4,2). The header is `sticky`, so `top: 0` is
   right at both ends: in the flow at the top it still tucks under the bar, and
   it sits flush once stuck – no script needed. Transparent headers are excluded
   because they are `fixed`, not `sticky`, and set their own `top` in their own
   rule below (where being out of the flow forces a live, script-fed offset). */
@media (max-width: 600px) {
  body:not(.wp-admin) header:not(.has-transparent-header):has(> .wp-block-group[data-sticky-on-scroll-up="true"]) {
    top: 0;
  }
}

/* Fade between transparent and solid instead of snapping. Ollie Pro transitions
   only `transform`, so background-color and box-shadow would flip in one frame.
   Override ONLY transition-property, never the `transition` shorthand: the
   shorthand resets Ollie Pro's transform transition and makes the header snap
   instead of slide. Duration and timing are inherited from Ollie Pro's rule,
   so the fade and the slide stay in step by construction. */
.wp-block-group[data-sticky-on-scroll-up="true"].is-position-sticky {
  transition-property: transform, background-color, box-shadow;
}

/* Take the header out of the flow so the hero starts at the top of the
   viewport. Ollie's rule makes every sticky header `sticky`, which keeps it in
   the flow and pushes the hero down. That rule and this one have identical
   specificity (0,2,2), so this only wins because the stylesheet is enqueued
   after the theme's.

   `top` pins the header below the admin bar. Above 600px core fixes the bar to
   the viewport, so its height is a constant band, and the fallback resolves it.
   At 600px and below core makes the bar `absolute`: it scrolls away, yet
   `--wp-admin--admin-bar--height` stays 46px, so a static value would strand
   the header below an empty band once the bar has scrolled out. Unlike the
   solid sticky header, this one is `fixed` – it can't tuck under the bar in the
   flow, so a static `top: 0` would overlap the bar at the very top instead.
   js/admin-bar-offset.js (logged-in users only, below 600px only) measures the
   bar's live bottom edge into `--kntnt-admin-bar-offset`, which collapses to 0
   as the bar leaves view. The fallback keeps the static height before the
   script runs, with no JS, and for every logged-out visitor, who has no bar to
   clear. */
body:not(.wp-admin) header.has-transparent-header {
  position: fixed;
  left: 0;
  right: 0;
  top: var(--kntnt-admin-bar-offset, var(--wp-admin--admin-bar--height, 0px));
}

/* The transparent state itself: no background, no shadow, until scrolled. This
   is the default, so it is already correct in the first paint – no script
   involved. The solid state needs no rule at all: once this stops matching, the
   block's own editor-set background simply reappears. That is why this file
   ships no styling of its own. `!important` is unavoidable – core emits the
   block's preset background as:
   `.has-<slug>-background-color { background-color: … !important }`.

   An open disclosure inside the header (a mega menu, a mobile menu) drops the
   header back to solid, so the panel hanging off it has a backdrop instead of
   floating over the hero. Phrased as "nothing is open" rather than "something
   is closed": the latter needs a closed element to exist, so a header with no
   menu at all would never go transparent, and with several toggles one closed
   one would be enough to keep it transparent while another stands open. */
header.has-transparent-header > .wp-block-group:not(.is-scrolled):not(:has([aria-expanded="true"])) {
  background-color: transparent !important;
  box-shadow: none !important;
}

/* Fade the mega menu panel in on the header's timing, not its own. Ollie Menu
   Designer fades an opening panel's opacity in over ~100ms; this plugin fades
   the header's background in over 300ms (inherited from Ollie Pro's sticky
   slide – see the transition-property rule above). Over a transparent header
   the two land at visibly different moments: the panel snaps in while the
   header colour is still catching up behind it. Matching the panel's opacity
   transition to the header's makes them read as one surface arriving together.

   The 300ms and the easing are Ollie Pro's own, copied from its sticky rule
   `.wp-block-group[data-sticky-on-scroll-up="true"] { transition: transform
   0.3s cubic-bezier(0.4, 0, 0.2, 1) }`. CSS cannot read another element's
   transition timing, so the constant has to be duplicated here; if Ollie Pro
   ever retimes its slide, retime this to match. The header and the panel must
   always share the number, or the mismatch returns.

   The `visibility` step is Ollie's, kept because it carries the closed panel's
   interactivity: on the way in it flips at once (delay 0s) so the panel is
   usable immediately; on the way out it waits the whole fade (delay 0.3s) so
   the panel stays visible while it fades rather than vanishing in one frame.
   That is why the two states carry different visibility timing.

   Scoped to `:not(.is-scrolled)`: the mismatch exists only while the header is
   actually fading – transparent and turning solid. A scrolled, already-solid
   header has no fade to match, so the panel keeps Ollie's snappier default.
   Desktop only (`min-width: 600px`, Ollie's own desktop threshold): the mobile
   menu is Ollie's full-screen overlay, not a panel hanging off the header, so
   there is no header fade to sync it to. */
@media (min-width: 600px) {
  header.has-transparent-header > .wp-block-group:not(.is-scrolled) .wp-block-ollie-mega-menu__toggle ~ .wp-block-ollie-mega-menu__menu-container {
    transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), visibility 0s linear 0.3s;
  }

  header.has-transparent-header > .wp-block-group:not(.is-scrolled) .wp-block-ollie-mega-menu__toggle[aria-expanded="true"] ~ .wp-block-ollie-mega-menu__menu-container {
    transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), visibility 0s linear 0s;
  }
}

/* Hang the mega menu panel from the header's rendered bottom edge, so the two
   surfaces meet instead of overlapping. Ollie Menu Designer opens a desktop
   panel `position: absolute` with a `top` measured from the nav item it belongs
   to (the block's Top spacing setting), written as an inline style by the
   block's own script. Because that nav item sits inside the header's vertical
   padding, the panel's top lands a little above the header's bottom edge and
   the two overlap by a narrow band. Header and panel carry the same colour, so
   where they overlap two semi-transparent copies of it composite to something
   brighter than either (two layers at opacity a make 1 - (1 - a)^2, not a): a
   bright band that flashes across the header's lower edge for the length of the
   fade. Syncing the two fades (above) is what makes them semi-transparent at
   the same instant and reveals the band; removing the overlap is what removes
   it, at every point in the fade.

   The correct top is the header's bottom edge, which depends on the header's
   padding and where the nav item sits within it – both per-site, per-design and
   unknowable to CSS. So js/mega-menu-offset.js measures the header group's live
   bottom edge, relative to the panel's offset parent, into `--kntnt-mega-menu-
   top`, and this rule consumes it. `!important` is unavoidable: the block's
   script sets `top` as an inline style, which nothing weaker than `!important`
   in a stylesheet can beat. It also decouples the position from the block's
   write timing – the script rewrites its inline `top` on resize, but never
   touches this custom property, so the stylesheet keeps winning. The `100%`
   fallback hangs the panel from the nav item's own bottom before the script
   runs – near the edge, never overlapping into the band. Desktop only: the
   mobile menu is Ollie's `position: fixed` full-screen overlay with its own
   `top`, which this must not fight (the script skips it too). */
@media (min-width: 600px) {
  header.has-transparent-header .wp-block-ollie-mega-menu__menu-container {
    top: var(--kntnt-mega-menu-top, 100%) !important;
  }
}
