/**
 * Chrome offset — the strip the theme does not own.
 *
 * ALWAYS ENQUEUED, and that is the point. This started life in hero.css, which
 * fixed the nine header test pages and nothing else: hero.css is loaded per
 * page by the effect loader, so on an ordinary page neither the token nor the
 * rules below existed at all. The site header went on sitting under the admin
 * bar and the token that was supposed to stop it was not on the page.
 *
 * A value every page depends on cannot live in a stylesheet only some pages
 * get. Enqueued in functions.php beside surfaces.css and spacing.css.
 */

/* ==========================================================================
   The admin bar

   WordPress pins #wpadminbar at the top of the viewport for a logged-in
   visitor: 32px at >=783px, 46px below that, and NOT fixed at all at <=600px,
   where it scrolls away with the page. Anything the theme fixes to top: 0, or
   sizes against 100vh, is therefore wrong by that strip for every editor
   looking at their own site.

   It cost us a pinned header clipped to a sliver at tablet width. Desktop
   masked it: WordPress also sets html { margin-top: 32px }, which happened to
   line up with the 32px bar, so the defect only appeared once the bar grew to
   46px and the margin did not.

   One token, resolved once here, consumed everywhere below. The <=600px rule
   returns it to 0 because the bar stops being fixed there — subtracting a
   strip that scrolls away would leave a permanent gap.
   ========================================================================== */

:root {
  --plexa-chrome-top: 0px;
}

body.admin-bar {
  --plexa-chrome-top: 32px;
}

@media screen and (max-width: 782px) {
  body.admin-bar {
    --plexa-chrome-top: 46px;
  }
}

@media screen and (max-width: 600px) {
  body.admin-bar {
    --plexa-chrome-top: 0px;
  }
}

/* EVERY top-pinned chrome element, not just this theme's own header-bars.
   The site chrome is stored HTML and pins itself with Tailwind utilities —
   `class="sticky top-0"` on #site-header — so tokenising .header-bars--sticky
   fixed the nine header test pages and left every ordinary page of the site
   exactly as broken as before. The header there sits under the admin bar and
   the utility is the thing doing it, which no amount of care in the theme's own
   stylesheet can reach.

   Keyed on the data-sticky ATTRIBUTE because that is the theme's contract for
   "this pins" — it is what sticky-header.js queries and what the renderers
   emit — rather than on a class an author may or may not have typed. `body`
   prefix takes it to (0,1,1), which beats Tailwind's .top-0 at (0,1,0) in the
   same cascade layer regardless of source order. */
body.admin-bar [data-sticky="true"],
body.admin-bar .header-bars--overlay,
body.admin-bar #site-header.sticky,
body.admin-bar #site-header.fixed {
  top: var(--plexa-chrome-top, 0px);
}

/* Header review round 1, #5b. An overlay header's bars at rest are absolute
   inside <header>, which is already in flow BELOW the admin bar (WordPress's
   html margin): the strip above was applied twice and a band of the photo
   showed between the admin bar and the header. At rest they sit at the top
   of <header>; pinned (.header-bars--sticky, fixed to the viewport) they
   take the strip as every pinned bar does. */
body.admin-bar .site-header--overlay .header-bars--overlay:not(.header-bars--sticky) {
  top: 0;
}


/* ==========================================================================
   Sticky header — moved out of hero.css on 2026-09-14

   These rules ARE the sticky behaviour: sticky-header.js only adds classes, and
   without `.header-bars--sticky { position: fixed }` the class lands on an
   element that does not move. hero.css is enqueued per page by the effect
   loader, so on any page without a hero the JS ran, the class was added, and
   nothing happened.

   That is the second time the same trap: the admin-bar token was declared here
   too, and worked only on the pages that happened to load this stylesheet. A
   value every page depends on cannot live in a stylesheet only some pages get.
   ========================================================================== */

/* THE HEADER HAS TO OUTRANK THE PAGE, OR ITS MENUS OPEN UNDERNEATH IT.

   `.site-header` carries a glass preset, and `backdrop-filter` establishes a
   stacking context whether anyone wanted one or not. Its own z-index was
   `auto`, so that context sat at level 0 inside `.bg-layers__content` — and
   every dropdown within it was trapped there, however high its own z-index.
   The mega panel asks for z-index: 100 and still lost to
   `.plexa-page-header__inner`, a sibling context at level 3.

   Measured on an interior page 2026-09-16: the panel was the right size, in
   the right place, with a white background, and
   document.elementFromPoint() in the middle of it returned
   `H1.plexa-page-header__title`. It was painting behind the page header, which
   reads as a transparent menu with only its top row showing.

   The home page hid this: nothing there is positioned above level 0, so the
   header won by document order and the menu looked fine.

   40 sits above the content and below `.header-bars--sticky`'s 100, so a
   pinned header still wins against a header at rest. `.header-bars`' own
   z-index below is inert until that sticky class makes it `fixed` — a static
   element's z-index does nothing — and is left alone because it is the sticky
   state's business, not this one's. */
.site-header {
  position: relative;
  z-index: 40;
}

.header-bars {
  /* position controlled by .sticky class when needed */
  z-index: 3;
  width: 100%;
}

.header-bars--overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
}


/* Base sticky state - applied via JavaScript when scrolled past threshold */
.header-bars--sticky {
  position: fixed;
  top: var(--plexa-chrome-top, 0px);
  left: 0;
  right: 0;
  z-index: 100;
  transition: transform 0.3s ease, background-color 0.2s ease, box-shadow 0.2s ease;
}


/* Scrolled state - when past threshold */
.header-bars--sticky.is-scrolled {
  background-color: var(--color-base-100);
  /* Tokenised 2026-09-14 (step 7). The only convertible literal in this file:
     this shadow falls on the PAGE, whose ground is --color-base-100 right
     above, so it should travel with the family like every other drop shadow
     (shapes.css, image-effects.css). The other fourteen literals here are
     scrim-class and stay literal — see the register in
     tests/integrity/expected-inert.json. */
  box-shadow:
    0 1px 3px 0 color-mix(in oklch, var(--color-neutral) 10%, transparent),
    0 1px 2px -1px color-mix(in oklch, var(--color-neutral) 10%, transparent);
}


/* Transparent bars get solid background when scrolled */
.header-bars--sticky.header-bars--transparent.is-scrolled {
  background-color: var(--color-base-100);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}


/* Override individual bar transparency when scrolled */
.header-bars--sticky.header-bars--transparent.is-scrolled .bar {
  background-color: var(--color-base-100);
  border-bottom: 1px solid var(--color-base-200);
}


/* Hide non-sticky bars when header is scrolled */
.header-bars.is-scrolled .bar[data-sticky="false"] {
  display: none;
}


/* Hidden sticky clone - for split layout (slide down + fade) */
.header-bars .bar.header-bars__sticky-clone {
  height: 0;
  min-height: 0 !important;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  transition: none;
}

.header-bars.is-scrolled .bar.header-bars__sticky-clone {
  height: var(--bar-height-md, 80px);
  opacity: 1;
  pointer-events: auto;
  overflow: visible;
  transition: height 0.6s ease-out, opacity 0.5s ease-out;
}



/* Sticky clone nav - ensure flex display (CSS is ID-scoped, clone may not get it) */
.header-bars__sticky-clone .nav-menu-nav {
  display: flex;
  flex-direction: row;
  align-items: center;
  height: 100%;
  width: 100%;
}

.header-bars__sticky-clone .nav-menu-list {
  display: flex;
  flex-direction: row;
  list-style: none;
  margin: 0;
  padding: 0;
  gap: 1.5rem;
}

.header-bars__sticky-clone .nav-menu-list > li {
  display: inline-flex;
  align-items: center;
}




/* Sticky clone logo - ensure flex display (CSS is ID-scoped, clone may not get it) */
.header-bars__sticky-clone .logo-link {
  display: flex;
  align-items: center;
  height: 100%;
  gap: 0.5rem;
  color: var(--color-base-content);
  text-decoration: none;
}

.header-bars__sticky-clone .logo-link img {
  max-height: 50px;
  width: auto;
}

.header-bars__sticky-clone .logo-link svg {
  max-height: 50px;
  width: auto;
}

.header-bars__sticky-clone .logo-link i {
  font-size: 1.75rem;
  line-height: 1;
  color: var(--color-primary);
}

.header-bars__sticky-clone .logo-text {
  font-weight: 900;
  font-size: 1.5rem;
  white-space: nowrap;
  color: var(--color-base-content);
}






/* Auto-hide: hide on scroll down, show on scroll up */
.header-bars--sticky.header-bars--auto-hide.is-scrolling-down {
  transform: translateY(-100%);
}

.header-bars--sticky.header-bars--auto-hide.is-scrolling-up {
  transform: translateY(0);
}



/* Body compensation when header is fixed (no hero case) */
body.has-sticky-header {
  padding-top: calc(var(--sticky-header-height, 80px) + var(--plexa-chrome-top, 0px));
}


/* ==========================================================================
   HEADER SYSTEM (header research §1.4-1.5, HG5-HG7, 2026-09-28)
   ========================================================================== */

/* HG5 / HB-S4 — anchors and Tab focus land below the pinned header, never
   under it (WCAG 2.4.11). sticky-header.js writes --plexa-scroll-offset on
   <html>: the height of the bars that stay when pinned plus the admin-bar
   strip, recomputed on resize because both change with width. */
html {
  scroll-padding-top: var(--plexa-scroll-offset, 0px);
}

/* HG5 / HB-S3 — sticky.condense: pinned, a stacked header is ONE row. Its
   brand row is a retracting bar (data-sticky="false", display:none once
   scrolled, above); the row that stays carries the mark, the nav and the
   actions in its own container, so the pinned row keeps the container's
   edges. What each row shows at rest is bars.css (header review round 2,
   #1). Declared on the header, drawn here — never per-entry css, which a
   layout cannot carry. */
.header-bars--condense.is-scrolled > .bar[data-sticky="true"] {
  height: 64px;
}

/* HG6 — overlay without a hero. The bars are absolute over <main>'s first
   section (.header-bars--overlay, above); at rest a scrim keeps their light
   text readable over an unknown photograph, and once pinned the transparent
   rules above make them solid base-100 with a shadow. sticky-header.js
   measures the bars into --plexa-overlay-height, and the first section's
   content moves down by it so nothing starts under the bar — its ground
   still runs to the top edge, under the bar. */
/* Header review round 1, #5a. At rest the bars are TRANSPARENT: the rest
   theme's data-theme on .header-bars also painted its base-100, an opaque
   dark band (and the bars' own light data-theme put dark text on it — fixed
   in Default_Header::create_children()). The scrim is what gives the light
   text its contrast: the neutral at 80% at the top and 72% through the
   middle of the bar, where the nav's text line sits, so light text holds
   4.5:1 even over a white photograph (the rest theme's neutral is about
   oklch(22%); 72% of it over white is about 0.13 relative luminance against
   ~0.75 for the text); it fades out by the bar's bottom edge. */
.header-bars--overlay:not(.is-scrolled) {
  background-color: transparent;
}

.header-bars--scrim:not(.is-scrolled) {
  background-image: linear-gradient(
    to bottom,
    color-mix(in oklch, var(--color-neutral) 80%, transparent),
    color-mix(in oklch, var(--color-neutral) 72%, transparent) 60%,
    transparent
  );
}

body:has(.site-header--overlay) main > :first-child > .section-content {
  margin-top: var(--plexa-overlay-height, 0px);
}

/* HG7 / HB-A1 — skip link: the first focusable element on every page, out of
   sight until it has focus (WCAG 2.4.1). */
.skip-link {
  position: absolute;
  left: 1rem;
  top: -10rem;
  z-index: 1000;
  padding: 0.75rem 1rem;
  background-color: var(--color-base-100);
  color: var(--color-base-content);
  border-radius: var(--radius-field, 0.25rem);
  box-shadow: 0 1px 3px 0 color-mix(in oklch, var(--color-neutral) 20%, transparent);
}

.skip-link:focus {
  top: calc(var(--plexa-chrome-top, 0px) + 0.5rem);
}

/*
 * The drawer's overlay is the drawer's previous SIBLING, so a part-scoped rule
 * (`#mobile-menu .mobile-menu-overlay`) never matched it: the overlay never
 * showed, and with `#mobile-menu .is-open` the drawer itself never opened.
 * The drawer's own states are `self.*` in Slide_Mobile_Menu; the overlay lives here.
 */
.mobile-menu-overlay {
  position: fixed;
  inset: 0;
  background-color: color-mix(in oklch, var(--color-neutral) 50%, transparent);
  z-index: 99;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0.3s ease;
}

.mobile-menu-overlay.is-open {
  opacity: 1;
  visibility: visible;
}

/* The page behind an open drawer does not scroll (header research A4). */
body.mobile-menu-open {
  overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .mobile-menu-overlay,
  .plexa-slide-mobile-menu {
    transition: none !important;
  }
}
