/* rx-block: rx-header */
/* ==========================================================================
   Site header — Figma node 3001:122
   A floating pill, not a full-width bar.
   ========================================================================== */

.rx-header {
  position: absolute;
  inset: var(--rx-header-top) 0 auto;
  z-index: 50;
  padding-inline: var(--rx-gutter);

  /* The pill's own height, in one place: the stacked menu below 1025 has to
     clear it exactly, and it differs by breakpoint. Set here rather than read
     off the bar, so the panel and the pill cannot disagree. */
  --rx-header-pill-h: var(--rx-header-height);

  /* How far the stacked panel reaches ABOVE the header to meet the top of the
     viewport: the header's own offset, plus the lift the pill travels on
     scroll, so it still meets it once the page has moved. */
  --rx-header-panel-rise: calc(var(--rx-header-top) + var(--rx-header-lift));

  /* Aliases, never a second copy of the curves.

     BOTH DIRECTIONS DECELERATE. The first pass gave the closing sheet
     --rx-ease-standard on the reading that a menu is a state change under the
     pointer. That is the wrong half of the rule for this: the tap only STARTS
     these, and what happens next is a 395px object completing a journey on its
     own — which is the decelerating curve's case, in both directions. The
     symmetric curve is an ease-IN as well as an ease-out, so a sheet this
     large left the pill slowly, accelerated through the middle of the travel
     and had to be caught at the end. That mid-travel acceleration is what
     reads as unsmooth; it is the curve, not the frame rate.

     THE OPEN GOES FURTHER THAN THAT. --rx-ease-out is decelerating but its
     tail is short, so a 395px sheet still reads as stopping rather than
     settling; the open is on --rx-ease-out-far, which spends most of the
     distance almost at once and glides the rest in. The duration goes up with
     it — a pronounced curve needs the length or the glide has no room, and a
     strong curve at a short duration is just a snap with a hesitation on the
     end.

     Duration and curve both still differ by direction, which is what keeps the
     close from feeling like the open played backwards: a panel retreating as
     slowly as it arrived reads as a mistake being undone, the call cta-band's
     collage makes. The close keeps the plain decelerating curve — a long glide
     on the way out is the reader waiting for the page to come back. */
  --rx-header-panel-in: 620ms;
  --rx-header-panel-in-ease: var(--rx-ease-out-far);
  --rx-header-panel-out: 320ms;
  --rx-header-panel-out-ease: var(--rx-ease-out);

  /* The stacked accordion, on the same reasoning: the row is let go, not
     dragged. Shorter than the panel because the distance is a quarter of it. */
  --rx-header-accordion: 340ms;
  --rx-header-accordion-ease: var(--rx-ease-out);

  /* The toggle's two rules, stated as the drawn CENTRE-TO-CENTRE pitch, which
     is what the cross has to fold across: each bar travels half of it to land
     on the button's own centre line.

     Measured, not derived from the bars' margins: adjacent block margins
     COLLAPSE, so the 5px margin they used to carry put their centres 6.5
     apart and not 11.5. Deriving the fold from the margin therefore overshot
     by 2.25px each and drew a lopsided X. They are laid out with a flex gap
     now, which does not collapse, so the pitch below is the whole truth. */
  --rx-header-toggle-rule: 1.5px;
  --rx-header-toggle-pitch: 6.5px;
}

.rx-header--sticky {
  position: sticky;
  top: var(--rx-header-top);
}

/* Scrolled position. The pill rises toward the top edge without docking to
   it — still a floating pill, just sitting tighter once the page has moved.

   Scroll-linked, not scroll-triggered: the offset is a function of scroll
   position, so the header travels with the page and reverses as you scroll
   back, rather than firing a fixed-length animation when a threshold is
   crossed. --rx-header-lift-range is how much page scroll the travel is
   spread over.

   This translates rather than moving `top`, because `top` is the property
   sticky positioning is itself resolving each frame; changing it mid-scroll
   makes the browser re-solve the stick point and the pill stutters. A
   transform leaves sticky's own math alone.

   Two implementations of the same motion. A native scroll timeline runs off
   the main thread and is the one to have; js/main.js drives the same custom
   property by hand only where that is unsupported, and checks for the same
   @supports condition so exactly one of them is ever active. */
.rx-header--sticky {
  transform: translate3d(0, calc(var(--rx-header-lift) * var(--rx-header-progress, 0) * -1), 0);
}

@property --rx-header-progress {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}

@keyframes rx-header-lift {
  from { --rx-header-progress: 0; }
  to   { --rx-header-progress: 1; }
}

@supports (animation-timeline: scroll()) {
  .rx-header--sticky {
    animation: rx-header-lift linear both;
    animation-timeline: scroll(root block);
    animation-range: 0 var(--rx-header-lift-range);
  }
}

/* Reduced motion keeps the pill where the design puts it. The travel is
   small, but it is decorative movement tied to scrolling, which is exactly
   what this preference asks to be spared. */
@media (prefers-reduced-motion: reduce) {
  .rx-header--sticky {
    animation: none;
    transform: none;
  }
}

.rx-header__bar {
  display: flex;
  align-items: center;
  gap: var(--rx-space-6);
  /* Hugs its contents rather than filling a fixed width — see the note on
     --rx-header-max. max-width is both the cap and the property the entrance
     reveal animates, so the two must stay on the same property. */
  width: max-content;
  max-width: var(--rx-header-max);
  min-height: var(--rx-header-pill-h);
  margin-inline: auto;
  padding: var(--rx-space-3) var(--rx-space-4) var(--rx-space-3) var(--rx-space-6);
  background-color: var(--rx-surface);
  border-radius: var(--rx-radius-pill);
  box-shadow: var(--rx-shadow-header);
}

.rx-header__logo {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  text-decoration: none;
}

.rx-header__logo img {
  width: 157px;
  height: 30px;
}

/* --- Nav ------------------------------------------------------------------ */

.rx-header__nav {
  position: relative;
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  justify-content: flex-end;
  gap: var(--rx-space-6);
}

.rx-header__menu {
  display: flex;
  align-items: center;
  gap: 17px; /* measured */
  margin-inline: auto;
}

.rx-header__item {
  position: relative;
}

.rx-header__link {
  display: inline-flex;
  align-items: center;
  gap: var(--rx-space-2);
  padding: var(--rx-space-2) 0;
  background: none;
  border: 0;
  color: var(--rx-brown-base);
  font-size: var(--rx-text-sm);
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}

.rx-header__link:hover {
  color: var(--rx-accent);
}

.rx-header__caret {
  width: 0.5em;
  height: 0.5em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--rx-duration) var(--rx-ease);
}

.rx-header__item--has-children[data-open="true"] .rx-header__caret {
  transform: translateY(1px) rotate(-135deg);
}

/* --- Dropdown -------------------------------------------------------------
   One surface, many panels. The white rounded background is a single element
   that lives in the nav and morphs — x, width, height — to whatever panel is
   open, so travelling along the menu reads as one object resizing rather than
   a series of panels blinking in and out. Each panel is chrome-less and only
   cross-fades its content across that surface, sliding a few pixels in the
   direction of travel so the swap has a direction.

   Geometry comes from js/main.js, which measures the open panel and writes
   --rx-fly-* here. CSS owns every duration and easing. */

.rx-header__flyout {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.rx-header__flyout-surface {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--rx-fly-w, 200px);
  height: var(--rx-fly-h, 0);
  background-color: var(--rx-surface);
  border-radius: var(--rx-radius-md);
  box-shadow: var(--rx-shadow-md);
  opacity: 0;
  /* Sits --rx-fly-rise ABOVE its resting place while closed, so the reveal is
     a drop into position under the item rather than a fade in place. */
  transform:
    translate3d(var(--rx-fly-x, 0), calc(var(--rx-fly-y, 0) - var(--rx-fly-rise)), 0)
    scale(var(--rx-fly-from));
  transform-origin: top center;
  transition:
    opacity var(--rx-fly-reveal) var(--rx-fly-ease),
    transform var(--rx-fly-reveal) var(--rx-fly-ease),
    width var(--rx-fly-fade) var(--rx-ease),
    height var(--rx-fly-fade) var(--rx-ease);
}

/* Open, but arriving from closed: the surface drops the last --rx-fly-rise
   into place and comes up to full size as it fades. */
.rx-header__nav[data-fly="open"] .rx-header__flyout-surface {
  opacity: 1;
  transform: translate3d(var(--rx-fly-x, 0), var(--rx-fly-y, 0), 0) scale(1);
}

/* The links follow the box. Scoped to the reveal only: while MOVING, the panel
   and the surface have to travel on one clock or the content spills outside
   the box for the length of the delay. */
.rx-header__nav:not([data-fly-moving="true"])
  .rx-header__item--has-children[data-open="true"] .rx-header__submenu {
  transition-delay: var(--rx-fly-content-lag);
}

/* Open, and moving between items: the same surface travels. Longer and eased
   differently from the fade — this is the movement people read as "fluid",
   and matching it to the fade duration makes it feel abrupt. */
.rx-header__nav[data-fly-moving="true"] .rx-header__flyout-surface {
  transition:
    opacity var(--rx-fly-fade) var(--rx-ease),
    transform var(--rx-fly-move) var(--rx-fly-ease),
    width var(--rx-fly-move) var(--rx-fly-ease),
    height var(--rx-fly-move) var(--rx-fly-ease);
}

.rx-header__submenu {
  position: absolute;
  top: calc(100% + var(--rx-space-3));
  left: 50%;
  min-width: 200px;
  padding: var(--rx-space-3);
  opacity: 0;
  visibility: hidden;
  /* Clipped to its own animated height. Panels differ in height, so on a swap
     from a tall menu to a short one the outgoing content would otherwise hang
     below the shrinking surface while it fades — the script gives both panels
     the incoming height and this is what hides the overhang.

     `clip` rather than `hidden`: hidden would make the panel a scroll
     container. */
  overflow: clip;
  /* Translated by the panel's own centring plus the distance to the item it
     is travelling from, which the script animates back to zero. */
  transform: translateX(-50%) translateX(var(--rx-fly-slide, 0));
  transition:
    opacity var(--rx-fly-fade) var(--rx-ease),
    transform var(--rx-fly-fade) var(--rx-ease),
    height var(--rx-fly-fade) var(--rx-ease),
    width var(--rx-fly-fade) var(--rx-ease),
    visibility var(--rx-fly-fade) var(--rx-ease);
}

.rx-header__item--has-children[data-open="true"] .rx-header__submenu {
  opacity: 1;
  visibility: visible;
}

/* While the surface is travelling, the panel travels on the same clock. At the
   fade duration the content lands well before the box does and visibly spills
   outside it; matched to the movement, the two arrive together and the panel
   reads as the contents of the surface rather than something laid over it. */
.rx-header__nav[data-fly-moving="true"] .rx-header__submenu {
  transition:
    opacity var(--rx-fly-move) var(--rx-fly-ease),
    transform var(--rx-fly-move) var(--rx-fly-ease),
    height var(--rx-fly-move) var(--rx-fly-ease),
    width var(--rx-fly-move) var(--rx-fly-ease),
    visibility var(--rx-fly-move) var(--rx-fly-ease);
}

/* The gap between the pill and the panel is dead space a diagonal mouse
   crosses on its way down. Without this the menu closes underneath the
   pointer. Covers the gap only, and only while open. */
.rx-header__item--has-children[data-open="true"]::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: calc(var(--rx-space-3) + 2px);
}

.rx-header__sublink {
  display: block;
  padding: var(--rx-space-2) var(--rx-space-3);
  border-radius: var(--rx-radius-sm);
  font-size: var(--rx-text-sm);
  text-decoration: none;
  white-space: nowrap;
}

.rx-header__sublink:hover {
  background-color: var(--rx-gold-t5);
}

/* Group heading — the third level. Reads as a section label but is a real
   link, since each of these is also a landing page. The indent on the group
   below it is what carries the hierarchy; the heading itself is not indented
   so it aligns with the ungrouped siblings above and below it. */
.rx-header__subitem--group + .rx-header__subitem {
  margin-top: var(--rx-space-2);
}

.rx-header__group-heading {
  display: block;
  padding: var(--rx-space-2) var(--rx-space-3);
  border-radius: var(--rx-radius-sm);
  color: var(--rx-text-muted);
  font-size: var(--rx-text-xs);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.rx-header__group-heading:hover {
  color: var(--rx-accent);
}

.rx-header__group {
  margin: 0 0 var(--rx-space-2);
  padding-left: var(--rx-space-3);
  border-left: 1px solid var(--rx-rule);
  margin-left: var(--rx-space-3);
}

/* --- CTA ------------------------------------------------------------------ */

.rx-header__cta {
  flex: 0 0 auto;
  /* Inherits .rx-btn--primary deliberately — do not re-add a colour
     override. Figma's #302b20 here is an artifact, not a codified colour. */
}

/* --- Mobile toggle -------------------------------------------------------- */

.rx-header__toggle {
  display: none;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  margin-left: auto;
  padding: 0;
  background: none;
  border: 0;
}

.rx-header__toggle-bar {
  display: block;
  width: 20px;
  height: var(--rx-header-toggle-rule);
  background-color: var(--rx-brown-base);
  transition: transform var(--rx-duration) var(--rx-ease);
}

@media (max-width: 1024px) {
  .rx-header__toggle {
    /* A column with a real gap: see --rx-header-toggle-pitch on the block. */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: calc(var(--rx-header-toggle-pitch) - var(--rx-header-toggle-rule));
  }

  /* THE PANEL IS ONE SHEET REACHING THE TOP OF THE VIEWPORT, BEHIND THE PILL,
     and it slides down from there as a single object.

     Its top edge is pulled up by --rx-header-panel-rise so it meets y 0 at
     rest AND once the pill has lifted; padding-block-start puts the first link
     back where it was, below the pill. Overshooting the top costs nothing —
     the top corners are square and the shadow is off-screen.

     `z-index: -1` IS THE MECHANISM, and it is the only reason this works
     without restructuring the markup. The nav is a DESCENDANT of the pill, and
     a descendant cannot paint under its ancestor's background — except in the
     negative layer, which the painting order draws before every in-flow
     descendant background in the nearest stacking context. That context is
     .rx-header (z-index 50, and a transform besides), so the sheet and its
     links both pass behind the pill while staying above the page.
     Two consequences worth knowing before editing this:
       - .rx-header must keep its stacking context and must not gain a
         background, or the sheet lands on top of the pill / under the page.
       - Nothing needs to reveal the links separately. They ride the same
         translate, and the pill hides whatever is crossing it, so this is ONE
         gesture rather than a sheet plus a staggered content entrance.

     Closed is `translate: 0 -100%` — the sheet's own height, which puts its
     bottom edge above the top of the viewport. Held with `visibility` and not
     `display`, so the links leave the tab order rather than sitting invisible
     in it, and so there is something to transition. */
  .rx-header__nav {
    position: absolute;
    top: calc(var(--rx-header-panel-rise) * -1);
    left: 0;
    right: 0;
    z-index: -1;
    flex-direction: column;
    align-items: stretch;
    gap: var(--rx-space-4);
    padding: var(--rx-space-5);
    /* rise + pill + the gap the panel used to carry as its own top offset
       (--rx-space-3) + its own padding, so the first link does not move. */
    padding-block-start: calc(
      var(--rx-header-panel-rise) + var(--rx-header-pill-h)
      + var(--rx-space-3) + var(--rx-space-5)
    );
    background-color: var(--rx-surface);
    /* Square at the top: that edge is the top of the screen, not a corner. */
    border-radius: 0 0 var(--rx-radius-lg) var(--rx-radius-lg);
    box-shadow: var(--rx-shadow-md);
    visibility: hidden;
    translate: 0 -100%;
    transition:
      translate var(--rx-header-panel-out) var(--rx-header-panel-out-ease),
      visibility var(--rx-header-panel-out) var(--rx-header-panel-out-ease);
  }

  /* The global nav script flips data-open on the header. */
  .rx-header[data-open="true"] .rx-header__nav {
    visibility: visible;
    translate: 0 0;
    transition:
      translate var(--rx-header-panel-in) var(--rx-header-panel-in-ease),
      visibility var(--rx-header-panel-in) var(--rx-header-panel-in-ease);
  }

  /* The bars have carried a transform transition at every width since the
     toggle was built and nothing ever set a transform — declared and inert.
     Open is the cross: each bar slides to the row's centre line and turns. */
  .rx-header[data-open="true"] .rx-header__toggle-bar:first-child {
    transform: translateY(calc(var(--rx-header-toggle-pitch) / 2)) rotate(45deg);
  }

  .rx-header[data-open="true"] .rx-header__toggle-bar:last-child {
    transform: translateY(calc(var(--rx-header-toggle-pitch) / -2)) rotate(-45deg);
  }

  .rx-header__menu {
    flex-direction: column;
    align-items: stretch;
    gap: var(--rx-space-2);
    margin: 0;
  }

  /* No morphing surface below the breakpoint: the nav is a stacked list in a
     panel of its own, so there is nothing for a shared background to travel
     between. */
  .rx-header__flyout {
    display: none;
  }

  /* THE STACKED SUBMENU IS AN ACCORDION, not a block that is shown and
     hidden. `display` cannot be interpolated, so the row is a one-row grid and
     the travel is grid-template-rows 0fr -> 1fr, with the list clipping itself
     to whatever height the row currently allows.

     THE LIST IS THE ELEMENT THAT CLIPS, not the submenu: the submenu carries
     the indent, and clipping the padded box takes the indent with it.

     `min-height: 0` on the list is load-bearing. A grid item's automatic
     minimum size is its own content, which holds the row open at full height
     and makes the 0fr end of the travel a no-op — the row would simply appear.

     And `visibility`, not height alone: a link inside a zero-height clipped
     box is still focusable, so a closed row would otherwise leave its links in
     the tab order as invisible stops.

     Heights and widths are whatever the content is; js/main.js pins them only
     for the desktop panel swap and does not run below 1025. */
  .rx-header__submenu {
    position: static;
    display: grid;
    grid-template-rows: 0fr;
    transform: none;
    height: auto;
    width: auto;
    overflow: visible;
    min-width: 0;
    padding: 0 0 0 var(--rx-space-4);
    box-shadow: none;
    opacity: 1;
    visibility: visible;
    transition:
      grid-template-rows var(--rx-header-accordion) var(--rx-header-accordion-ease);
  }

  .rx-header__sublist {
    min-height: 0;
    overflow: hidden;
    visibility: hidden;
    transition:
      visibility var(--rx-header-accordion) var(--rx-header-accordion-ease);
  }

  .rx-header__item--has-children[data-open="true"] .rx-header__submenu {
    grid-template-rows: 1fr;
  }

  .rx-header__item--has-children[data-open="true"] .rx-header__sublist {
    visibility: visible;
  }

  .rx-header__cta {
    width: 100%;
  }
}


/* The header has NO entrance. The pill used to open out from a collapsed
   221px around the logo, with the nav fading in behind it; removed on
   request. It is drawn at its settled width from the first frame. */

@media (prefers-reduced-motion: reduce) {
  /* The surface still appears and disappears — it has to, it is the panel's
     background — but it does not travel or resize over time. */
  .rx-header__flyout-surface,
  .rx-header__nav[data-fly-moving="true"] .rx-header__flyout-surface {
    transition: opacity var(--rx-duration) var(--rx-ease);
    transform: translate3d(var(--rx-fly-x, 0), var(--rx-fly-y, 0), 0);
  }

  /* Deliberately does NOT restate `transform: translateX(-50%)`. That line
     lived here to drop the desktop panel's travelling slide, but this block
     sits after the max-width:1024 one, so it also landed on the stacked
     accordion — which sets `transform: none` — and shifted every open row half
     its own width to the left. The base rule's transform is already right at
     both widths, and with transform out of the transition list above the
     slide is instant, which is what reduced motion is asking for. */
  .rx-header__submenu {
    transition: opacity var(--rx-duration) var(--rx-ease);
  }

  /* The stacked panel appears and disappears — it has to, it is the menu —
     but it does not travel to get there. `visibility` alone still takes the
     links out of the tab order while closed. */
  .rx-header__nav,
  .rx-header[data-open="true"] .rx-header__nav {
    translate: none;
  }
}

/* The mark is 157px wide as drawn, which is more than half of a 281px pill on a
   phone. Scaled to the pill rather than the page. */
@media (max-width: 767px) {
  .rx-header__logo img {
    /* Full size by ~460px and only easing off below that. The first pass at
       23vw was shrinking it on screens with plenty of room — 115px at 500,
       where the pill can carry the whole 157. */
    width: clamp(126px, 34vw, 157px);
    height: auto;
  }

  /* The phone pill's own height (65.63 drawn), and the toggle's bar spacing —
     both declared as the block's variables rather than on the elements,
     because the stacked panel's top padding is derived from the first and the
     toggle's open cross from the second. The 6 is drawn (3153:8040). */
  .rx-header {
    --rx-header-pill-h: 65.63px;
    --rx-header-toggle-pitch: 6px;
  }

  /* THE PILL SPANS THE SCREEN on the phone frame (3153:8008): 357.308 wide
     inside a 402 frame, against the max-content width it carries everywhere
     else. Shrink-wrapped it reads as a floating chip with the logo and the
     toggle jammed together in the middle of an empty bar.

     Width comes from the gutter rather than from the drawn 22.35 inset, which
     puts the edge at 26 instead of 22 at the design size — 4px, and worth it
     to keep one number setting every side margin on the page.

     Insets inside the pill ARE drawn: the logo starts 28.33 from its left edge
     and the toggle ends 33 from its right. */
  .rx-header__bar {
    width: 100%;
    max-width: none;
    padding: 0 33px 0 28.33px;
  }

  /* Drawn 22 wide, the two rules 6 apart centre to centre
     (--rx-header-toggle-pitch above), 12 overall (3153:8040). The 44px hit target stays — the drawn size is the
     ink, not the button. */
  .rx-header__toggle-bar {
    width: 22px;
  }
}
