/* Header — adapted from the design: logo + section
   title grouped on the left so nothing shifts when a title appears or
   disappears. Padding = the global 5% gutter; every action control has a
   36px tap target whose padding extends into the margin (the last
   control gets a negative margin so its ICON aligns with the gutter). */

.site-header {
  position: sticky;
  top: 0;
  z-index: 10; /* below the menu overlay (20) */
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  height: 3.625rem; /* 58px */
  padding-inline: var(--gutter);
  background: var(--header-tint, var(--color-paper));
  /* iOS Safari's elastic bounce briefly reveals whatever's above the
     page when you overscroll past the top — overscroll-behavior (the
     usual fix) isn't honored there for this. A shadow with a huge
     negative offset extends the header's own background far enough
     upward to cover that gap outright, rather than relying on the
     scroll container to never overscroll. */
  box-shadow: 0 -100vh 0 var(--header-tint, var(--color-paper));
  /* A sticky element can lag the viewport by a frame mid-scroll (Mozilla
     bug 1585378), flashing a gap above it. will-change promotes the
     header to its own GPU-composited layer so the compositor moves it
     directly. Safe since .menu__nav is a sibling, not a descendant
     (site/snippets/header.php) — a transformed/will-change ancestor
     becomes the containing block for fixed-position descendants. */
  will-change: transform;
}

/* iOS Safari fights position:sticky against the visual viewport while
   the on-screen keyboard is open, causing lag/flicker (confirmed WebKit
   bug, same family as the newsletter dialog's keyboard issue).
   js/keyboard-sticky-fix.js toggles this class while any text input has
   focus, dropping sticky back to static instead of fighting it. */
html.has-focused-input .site-header {
  position: static;
  box-shadow: none; /* the -100vh overscroll cover only makes sense pinned to the viewport */
}

.site-header--home {
  --header-tint: #eff8f3; /* one-off pale mint */
}

.site-header--shop {
  --header-tint: #fcf3fa; /* one-off pale pink */
}

.site-header--journal {
  --header-tint: #fffada; /* one-off pale yellow */
}

.site-header--gatherings {
  --header-tint: #50bb9f; /* teal */
}

.site-header--about {
  --header-tint: #ff0000; /* full red, unlike the other pale tints */
}

.site-header--contact {
  --header-tint: #a6d7ff; /* pale blue */
}

.site-header--cart {
  --header-tint: #13ff79; /* green */
}

/* shared across login/account/orders — one account area, one tint */
.site-header--account {
  --header-tint: #ff9ced; /* pink */
}

/* count sits inside the basket body of cart.svg — the basket is NOT
   centered on the icon's own bounding box (the handle stub skews it),
   so center is computed from the path data itself (45.83% / 60.5%). */
.site-header__cart {
  position: relative;
}

.site-header__cart-count {
  /* 12px on screen: SVG text, and the basket's 31-unit viewBox spans 34px.
     Deliberate px text exception — it must stay inside the px-fixed drawing */
  font-size: 10.94px;
  font-weight: var(--weight-semibold);
  fill: currentColor;
}

.site-header__cart-count:empty {
  display: none;
}

.site-header__brand {
  grid-column: 1;
  justify-self: start;
  display: flex;
  align-items: center;
  /* explicit gap — logo/title don't have their own tap-target boxes to
     produce a matching gap for free the way .site-header__actions'
     icons do. */
  gap: var(--space-1); /* 8px */
}

.site-header__logo {
  display: block;
}

.site-header__logo img {
  display: block;
  width: 3.0625rem; /* 49px */
  height: auto;
}

/* a link since the section-title-navigates change — dressed as the plain
   text it was, the wordmark-style slot is its own affordance */
.site-header__title {
  font-size: var(--text-title);
  font-weight: var(--weight-semibold);
  white-space: nowrap;
  color: inherit;
  text-decoration: none;
}

.site-header__title:focus-visible {
  text-decoration: underline;
}

@media (hover: hover) {
  .site-header__title:hover {
    text-decoration: underline;
  }
}

.site-header__actions {
  grid-column: 2;
  justify-self: end;
  display: flex;
  align-items: center;
  /* icons sit in their own 36px tap-target box, flush against the next
     one — most of the visual space between icons comes from that box;
     this gap adds a bit more on top, off the --space token scale */
  gap: 0.25rem; /* 4px */
  /* pulls the last icon's own glyph (not its box) flush with the gutter —
     extrapolated for the 36px box from the measured 40px->44px relation
     (box shrinks by X, margin becomes less negative by X/2) */
  margin-right: -0.40625rem;
}

.site-header__lang,
.site-header__account,
.site-header__cart,
.menu summary {
  display: grid;
  place-items: center;
  min-width: 36px;  /* tap target — deliberately under the usual 44px; still clears WCAG 2.5.8's 24px AA minimum */
  min-height: 36px;
  line-height: 1;
}

.site-header__lang {
  font-size: var(--text-title);
  font-weight: var(--weight-medium);
  text-decoration: none;
}

/* Hover picks up the same tints the open-popover state uses below — cart
   via currentColor on the inline SVG; the account icon is a PNG, so on
   hover-capable devices it's rendered as an anchor-painted mask at ALL
   times and hover only swaps the paint color. Toggling between the <img>
   and the mask on hover instead produced a one-frame dark flash on the
   way out. The blink follows via .is-blinking (eye-blink.js) since the
   hidden <img>'s src swap can't show through. */
@media (hover: hover) {
  .site-header__cart:hover {
    color: #13ff79;
  }

  .site-header__account {
    background: var(--color-ink);
    /* px, not rem: must stay in step with the <img>'s 34×32 attributes
       and the px-sized cart SVG beside it under the fluid root */
    mask: url('../img/account-eyes-open.png') center / 34px 32px no-repeat;
  }

  .site-header__account .site-header__account-icon {
    visibility: hidden; /* its box still holds the tap target open */
  }

  .site-header__account:has(.is-blinking) {
    mask-image: url('../img/account-eyes-closed.png');
  }

  .site-header__account:hover {
    background: #ff9ced;
  }
}

/* burger — CSS-only via <details>; panel styled in menu.css */
.menu summary {
  list-style: none;
  cursor: pointer;
}

.menu summary::-webkit-details-marker {
  display: none;
}

/* language dropdown — same CSS-only <details> pattern as the burger */
.lang {
  position: relative;
}

.lang summary {
  list-style: none;
  cursor: pointer;
}

.lang summary::-webkit-details-marker {
  display: none;
}

.lang__list {
  position: absolute;
  /* first item (44px) centers on the 36px summary box, +1px list border */
  top: calc((36px - 44px) / 2 - 1px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 11; /* above the sticky header's own plane, below the menu overlay (20) */
  margin: 0;
  padding: 0;
  list-style: none;
  border: var(--border-thin);
  border-radius: var(--radius-m);
  background: var(--color-paper);
  white-space: nowrap;
}

.lang__list a {
  display: grid;
  place-items: center;
  min-height: 44px; /* tap-target minimum */
  padding: 0 0.75em;
  font-size: var(--text-title); /* matches the header marker */
  font-weight: var(--weight-medium);
  text-decoration: none;
}

/* nav row (menu.css) is a fixed sibling layered over the header, not a grid child */
@media (min-width: 72rem) {
  .site-header {
    height: 2.78125rem;
    /* 44.5px is a half-pixel height: iPad Safari rounds the sticky layer
       down and a dark seam of the content behind shows underneath —
       overdraw 1px of tint below, joining the -100vh overscroll cover */
    box-shadow:
      0 -100vh 0 var(--header-tint, var(--color-paper)),
      0 1px 0 var(--header-tint, var(--color-paper));
  }

  .site-header__logo img {
    width: 3.03125rem;
  }

  .site-header__brand {
    gap: 1rem; /* more air between logo and the current-page title than mobile's 8px */
  }

  .lang__list {
    top: calc((36px - 44px) / 2 - 1px + 0.625rem); /* 10px lower, halfway between the original and the +20px pass */
  }

  /* open trigger takes the tint its own section's header uses
     (.site-header--cart / --account above), so it reads as the active one.
     Driven off :popover-open via :has() rather than a JS-toggled class —
     the popover already holds that state. */
  .site-header__actions:has(#cart-popover:popover-open) .site-header__cart {
    color: #13ff79;
  }

  /* the account icon is a PNG, so it can't take currentColor: the anchor
     paints the tint and the drawing masks it (alpha line art on
     transparent), with the <img> hidden by visibility so its box still
     holds the 36px target open. */
  .site-header__actions:has(#account-popover:popover-open) .site-header__account {
    background: #ff9ced;
    /* px, not rem: must stay in step with the <img>'s 34×32 attributes
       and the px-sized cart SVG beside it under the fluid root */
    mask: url('../img/account-eyes-open.png') center / 34px 32px no-repeat;
  }

  .site-header__actions:has(#account-popover:popover-open) .site-header__account-icon {
    visibility: hidden;
  }

  /* keeps the mascot blinking while the popup is open — eye-blink.js marks
     the closed frame and the mask follows it, since swapping the hidden
     <img>'s src alone can no longer show through */
  .site-header__actions:has(#account-popover:popover-open) .site-header__account:has(.is-blinking) {
    mask-image: url('../img/account-eyes-closed.png');
  }

  /* account/cart popovers (header-popovers.js): same drawn speech-bubble
     dialog (assets/img/popup-frame.png),
     same one size for both — a mobile-viewport-like card, not an
     arbitrary compact dropdown. height shrinks with the viewport (capped
     at 90dvh) so the whole dialog always fits without page scroll; width
     follows via aspect-ratio so the frame art never distorts. Browser's
     default popover centering is overridden below. Content inside is the
     same account/cart page classes/markup, just in this frame instead of
     a full page. */
  .header-popover {
    --popover-height: min(48.25rem, 90dvh); /* 772px */
    /* the drawn frame's own top line, y=38 of popup-frame.png's 516 —
       it stands in for mobile's fixed header inside this card */
    --popover-frame-top: calc(var(--popover-height) * 0.074);
    /* clipped a further 1% inside the drawn lines, top and bottom, so
       scrolling text cuts off short of them instead of flush against.
       Every anchor below subtracts it, so nothing actually moves. */
    --popover-crop: calc(var(--popover-height) * 0.01);
    --popover-inset-top: calc(var(--popover-frame-top) + var(--popover-crop));
    /* head anchor: the login page's 23.1vh face position re-anchored to the card.
       Shared so the account face and the empty-cart head land identically
       — measured from the popover's own top edge, before any padding. */
    --popover-head-top: calc(var(--popover-height) * 0.231);
    /* content renders 10% smaller than mobile inside the same frame.
       Applied to the children, not here — zooming the popover itself
       would drag its own size and fixed offsets down with it. Every
       anchor below is divided by it so positions survive unchanged. */
    --popover-scale: 0.9;
    /* back arrow's resting AND sticky offset — one value so the two can't
       drift. Both are measured from the padding box, which is the frame's
       interior, so this is a plain gap below the drawn line. Used only
       inside the zoomed children, hence the scale division. */
    --popover-back-top: calc((var(--space-2) - var(--popover-crop)) / var(--popover-scale));
    position: fixed;
    /* right edge lines up with the CART icon's left edge (36px icon box),
       not the gutter itself — see .account-popover below for its own icon */
    inset: auto calc(var(--gutter) + 36px) auto auto;
    top: calc(2.78125rem + 0.5rem);
    margin: 0;
    /* 395×772 — mobile's design width, so mobile's own CSS wraps
       identically inside the frame. */
    aspect-ratio: 395 / 772;
    width: auto;
    height: var(--popover-height);
    /* The drawn box's own four insets, as transparent borders, so the
       PADDING BOX is the frame's interior: scrolled content then clips at
       the drawn lines instead of painting on into the speech-bubble tail
       above them, and the scrollbar spans just that interior rather than
       the whole card. Measured off popup-frame.png (264x516): box runs
       x=1..255, y=38..514, as fractions of the card height. The right one
       carries an extra --space-1 to pull the bar in off the line.
       background-origin has to follow: the shorthand below resets it to
       padding-box, which would shrink the art away from these borders. */
    border: solid transparent;
    border-width: var(--popover-inset-top)
                  calc(var(--popover-height) * 0.0174 + var(--space-1))
                  calc(var(--popover-height) * 0.004 + var(--popover-crop))
                  calc(var(--popover-height) * 0.0019);
    /* pure breathing room now the insets are borders. Asymmetric because
       the drawn box's middle is 4px LEFT of the art's own middle, so equal
       padding would leave content sitting right of the frame's centre. */
    /* right clears the scrollbar sitting in it; left gets the same bump so
       the centring above (right inset - left inset) stays constant */
    padding: 0 var(--space-2) var(--space-1) var(--space-3);
    background: transparent url('../img/popup-frame.png') center / 100% 100% no-repeat;
    background-origin: border-box;
    overflow-y: auto;
    overscroll-behavior: contain; /* reaching its ends must not chain to the page */
    /* no-op where scrollbars overlay (macOS); where they take real space
       it reserves both gutters so a scrolling popover stays centred */
    scrollbar-gutter: stable both-edges;
  }

  /* account sits one more 36px icon box + the row's 2px gap to the left
     of cart in .site-header__actions — its left edge is one full icon
     further out than cart's */
  .account-popover {
    right: calc(var(--gutter) + 72px + 0.125rem);
  }

  /* zoom, not transform: scale() — it scales layout, so the popover's
     own scrollHeight stays honest and no containing block is created for
     positioned descendants. Every vertical anchor on these children is
     therefore written in zoomed space (divided by the scale) so the
     rendered positions come out identical to the unscaled ones. */
  .header-popover > * {
    zoom: var(--popover-scale);
  }

  /* auth.css anchors the face at 23.1svh/25svh of the full viewport and
     forces min-height 100svh — that's the window, not this card, so it
     scrolled. Re-anchored to the card instead; the popover's own padding
     is subtracted so the face lands exactly on --popover-head-top.
     Scoped under .header-popover for a 3rd class: auth.css loads AFTER
     header.css, so a two-class selector here ties on specificity and
     silently loses. */
  .header-popover .popover-page.auth--full {
    padding-block: calc((var(--popover-head-top) - var(--popover-inset-top)) / var(--popover-scale)) 0;
    min-height: auto;
  }

  /* orders/addresses/address-form (auth--sub) zero .page's top padding on
     mobile so the sticky back arrow sits flush under the fixed header.
     The frame's drawn line is that header here, so the arrow starts on
     it — without this it sat above the line, outside the frame. */
  .header-popover .popover-page.auth--sub {
    padding-top: var(--popover-back-top);
  }

  /* same viewport-height trap as .cart__empty below — inside the popup
     100svh is still the whole window, forcing a scroll */
  .header-popover .orders__empty {
    min-height: auto;
  }

  /* cart-content.php sits directly in the popover (no .popover-page
     wrapper), so .header-popover's own padding replaces the .page
     padding it would have had. Restored per child rather than on the
     popover, so both popovers share one container padding and the zoom
     compensation above stays the same on either side. */
  .cart-popover > * {
    padding-top: calc((var(--space-3) - var(--popover-crop)) / var(--popover-scale));
  }

  /* .cart__loading/.cart__empty (cart.css) size themselves against the
     full viewport (100vh) for the standalone page — inside the popup
     that's still the whole browser window, not this card, forcing it
     taller than itself and scrolling. */
  .cart-popover .cart__loading,
  .cart-popover .cart__empty {
    min-height: auto;
  }

  /* the -20% optically centres the gif inside .cart__loading's tall
     viewport box; with that box collapsed to the gif itself it just
     drags it back out through the frame's top line */
  .cart-popover .cart__loading-gif {
    transform: none;
  }

  /* the head sits on the shared anchor, level with the account popover's
     face — same expression as .popover-page.auth--full above, which is
     what keeps the two aligned */
  .cart-popover .cart__empty {
    padding-top: calc((var(--popover-head-top) - var(--popover-inset-top)) / var(--popover-scale));
  }

  /* post-checkout: the thank-you panel replaces the cart rather than
     stacking on top of it. Shopify empties the cart at checkout, so
     without this the empty state renders under the message. */
  .cart-popover.is-thankyou .cart__loading,
  .cart-popover.is-thankyou .cart__empty,
  .cart-popover.is-thankyou .cart__content {
    display: none;
  }

  .cart-popover .cart__empty-icon {
    width: 7rem; /* matches .auth__face (auth.css) in the account popover */
    height: auto;
  }

  .menu {
    display: none;
  }

  /* .product__back (product.css) is a bare arrow, reused as-is for
     orders/addresses/address-form's own popover back link. Its sticky
     offset clears mobile's fixed header; here it pins to the frame's
     drawn line instead, so the arrow stays inside the frame while the
     list scrolls under it rather than riding up to the scrollport edge.
     a.popover-back (element+class), not .popover-back alone: product.css
     loads AFTER header.css, so a same-specificity class-only override
     here loses to .product__back's own rule — the selector needs the
     element boost or the arrow's top stays at the page value and drops
     into the first card. */
  a.popover-back {
    top: var(--popover-back-top);
    margin-bottom: var(--space-1);
    /* the page version's white+difference can't work here: a [popover]
       is an isolated top-layer blend group, so over the frame PNG's
       transparent parts there's no backdrop to blend with and the arrow
       stays raw white — the card is plain paper, plain ink is right */
    color: var(--color-ink);
    mix-blend-mode: normal;
    /* .product__back carries its own gutter because on the full page it
       sits OUTSIDE <main class="page">; here it's inside .popover-page,
       which already applies one, so it was indented twice. 1% of that
       content box is the nudge past the content's own left edge. */
    padding-left: 1%;
  }
}


/* big desktops: the language list rides 1% of the viewport higher */
@media (min-width: 100rem) {
  .lang__list {
    top: calc((36px - 44px) / 2 - 1px + 0.625rem - 1svh);
  }
}
