/* 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;
}

/* A flex row so a parent item that is a LINK PLUS A CARET keeps the same gap
   between label and caret the single-button form got from `.rx-header__link`'s
   own gap. Items with one child render one flex item and are unaffected. */
.rx-header__item {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--rx-space-2);
}

.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);
}

/* The caret's own button. It carries no text, so it needs a tap target of its
   own rather than the label's — the padding is what supplies it, and the
   negative margin keeps the drawn gap between label and caret unchanged. */
.rx-header__link--caret {
  padding-inline: var(--rx-space-2);
  margin-inline: calc(var(--rx-space-2) * -1);
  cursor: pointer;
}

.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);
}

/* --- Submenu panel and its optional card ----------------------------------
   Figma 3375:18. The panel's children are wrapped so the stacked accordion
   below 1025 still has exactly one row to animate.

   Every number here is a drawn measure off that node, in design pixels, with
   the cap-trim arithmetic left in place: Figma trims text nodes to cap-top and
   baseline, so a drawn gap excludes the leading a CSS line box carries on both
   sides. Inter, per em: cap .727, and for size S at line-height L the box
   overshoots the cap by (L - 1.21) / 2 + .242 em above and the baseline by
   (L - 1.21) / 2 + .241 em below. */

.rx-header__panel {
  /* ONE WIDTH for the card and for a column of links. The drawn card is 204
     and a link list left to its own content is as narrow as its longest
     label, which next to a 204 card reads as a stray list rather than as the
     other half of the panel. Both take this. */
  --rx-header-col-w: 204px;
  /* Drawn 29 between the card's right edge (712) and the link list's text
     (741), less the sublink's own inline padding, which the drawing has no
     equivalent of. Also the gutter between columns. */
  --rx-header-col-gap: calc(29px - var(--rx-space-3));
  display: flex;
  flex-direction: column;
}

.rx-header__panel--carded {
  flex-direction: row;
  gap: var(--rx-header-col-gap);
  /* Card 119.195-279.61, list 144-256: the two centres land within .6 of each
     other, so the list rides the card's height. */
  align-items: center;
}

.rx-header__card {
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
  /* Drawn 204 x 160.419. The height is NOT set: the padding and the gaps below
     reproduce it exactly at the drawn copy length, and a longer string should
     grow the card rather than spill out of it. */
  inline-size: var(--rx-header-col-w);
  /* 27.53 to the heading's cap, less its 15 x .187em = 2.8 of leading.
     Right: 204 - 22.93 - the drawn 143.57 text width. Bottom: 10.2 to the
     arrow's own box. */
  padding: 24.73px 37.5px 10.2px 22.93px;
  border-radius: var(--rx-radius-panel);
  background-color: var(--rx-header-card-fill);
  color: var(--rx-text);
  text-decoration: none;
}

/* Tint 4 for the surface and Base for the arrow, which is the pairing
   3375:18 draws in gold. The arrow is painted in currentColor so it follows
   the ramp; the type stays --rx-text in all three. */
.rx-header__card--gold {
  --rx-header-card-fill: var(--rx-gold-t4);
  --rx-header-card-accent: var(--rx-gold-base);
}

.rx-header__card--blue {
  --rx-header-card-fill: var(--rx-blue-t4);
  --rx-header-card-accent: var(--rx-blue-base);
}

.rx-header__card--green {
  --rx-header-card-fill: var(--rx-green-t4);
  --rx-header-card-accent: var(--rx-green-base);
}

/* THE CARD MOVES BY `order`, never by reversing the flex direction — the same
   call _accordion.css's --media-left makes. The card stays first in the DOM,
   so the reading and tab order are the panel's overview link and then its
   links, whichever end the card is drawn at. */
.rx-header__panel--card-end .rx-header__card {
  order: 1;
}

/* CLAMPED, because the heading is no longer always typed. A resource picked
   from the blog brings its real title: measured, one of the fixture's posts
   took the card from the drawn 160.419 to 350.41 and the panel with it, which
   is a menu that changes height depending on which article is current. Two
   lines for the title, three for the copy — the drawn card's own counts. */
.rx-header__card-heading {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  font-size: 15px;
  line-height: 1.1;
  font-weight: 600;
}

.rx-header__card-copy {
  /* Drawn 14.27 cap to cap, less 2.79 of the heading's descent leading and
     4.38 of this line box's ascent leading. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
  margin-block-start: 7.1px;
  font-size: 13px;
  line-height: 1.4;
  opacity: 0.75;
}

.rx-header__card-arrow {
  display: block;
  color: var(--rx-header-card-accent);
  inline-size: 31px;
  block-size: 31px;
  /* Drawn 21.5 from the copy's last baseline to the arrow's box, less this
     line box's 4.38 of descent leading. */
  margin-block-start: 16.41px;
  /* The glyph box is drawn 19.09 from the card's edge against the type's
     22.93, so it steps back out of the padding rather than aligning to it. */
  margin-inline-start: -3.84px;
  /* The RESOURCE CARD's nudge, not card-deck's. Those are the theme's two
     card arrows and they disagree — .rx-rcard__go travels 3px on
     --rx-duration/--rx-ease across five emitters, .rx-deck__arrow travels a
     --rx-space-2 on --rx-ease-standard in one. This was copied from the one,
     which made a third card behave unlike the five. */
  transition: transform var(--rx-duration) var(--rx-ease);
}

a.rx-header__card:hover .rx-header__card-arrow {
  transform: translateX(3px);
}

.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);
}

/* The list holds the card's width even when it is the only thing in the
   panel, so a dropdown does not change shape depending on whether a card is
   set on it. A min, not a width: a long label still widens its own column. */
.rx-header__sublist {
  min-inline-size: var(--rx-header-col-w);
}

/* --- Columns --------------------------------------------------------------
   A dropdown wide enough to show more than one set of links at once: each
   Grouped links entry becomes a column of its own, headed by its own link.

   IT IS THE SAME MARKUP as the one-list layout, laid out differently. The
   third level already emits a heading and a list per group, which is exactly
   a column — a separate emitter for this would be two renderings of one set
   of fields, and the two would drift.

   An entry with no group of its own is a single-link column. That is the
   honest result of laying siblings out in a row, and the field's help text
   says so; a menu set to Columns wants every entry grouped. */

.rx-header__panel--cols .rx-header__sublist {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: var(--rx-header-col-gap);
}

.rx-header__panel--cols .rx-header__subitem {
  flex: 0 1 auto;
  min-inline-size: var(--rx-header-col-w);
}

/* The indent and the rule are what carry the hierarchy when a group is one
   band inside a list. A column already reads as one, and its heading sits
   directly above it, so both come off — left in place they draw a vertical
   rule down the middle of the panel. */
.rx-header__panel--cols .rx-header__group {
  margin: 0;
  padding-left: 0;
  border-left: 0;
}

/* Same reason: the separation between one group and the next is the gutter
   here, not a gap in a stack. */
.rx-header__panel--cols .rx-header__subitem--group + .rx-header__subitem {
  margin-top: 0;
}

/* --- 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;
  }

  /* Stacked, the submenu is a sibling of the label row rather than an absolute
     panel, so the item has to go back to a column and hold the label and its
     caret in a row of their own. `:has()` scopes that to a parent that is a
     link — every other item is a single element and a plain block row. */
  .rx-header__item:has(.rx-header__link--caret) {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
  }

  /* The submenu spans both columns, under the label and the caret alike. */
  .rx-header__item:has(.rx-header__link--caret) .rx-header__submenu {
    grid-column: 1 / -1;
  }

  /* A full-height target at the row's right edge: the caret is the only way to
     open the panel here, since the label now navigates. */
  .rx-header__link--caret {
    justify-content: flex-end;
    padding-inline: var(--rx-space-4);
    margin-inline: calc(var(--rx-space-4) * -1) 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);
  }

  /* THE PANEL is what clips, not the list — a carded panel has two children
     and clipping only one of them would leave the card standing in a closed
     row. */
  .rx-header__panel {
    min-height: 0;
    overflow: hidden;
    visibility: hidden;
    transition:
      visibility var(--rx-header-accordion) var(--rx-header-accordion-ease);
  }

  /* Stacked there is no room beside the list, so the card sits above it at
     the width of the row. */
  .rx-header__panel--carded {
    flex-direction: column;
    align-items: stretch;
    gap: var(--rx-space-3);
  }

  .rx-header__card {
    inline-size: auto;
  }

  /* No room for columns at this width. The row goes back to a stack and the
     groups get their indent and rule back, which is the one-list layout —
     so a menu set to Columns is simply a stacked menu on a phone. */
  .rx-header__panel--cols .rx-header__sublist {
    flex-direction: column;
    gap: 0;
  }

  /* The panel is as wide as the row here, so nothing needs a floor. */
  .rx-header__sublist,
  .rx-header__panel--cols .rx-header__subitem {
    min-inline-size: 0;
  }

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

  .rx-header__panel--cols .rx-header__subitem--group + .rx-header__subitem {
    margin-top: var(--rx-space-2);
  }

  .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__panel {
    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 same hold .rx-rcard__go carries. Missed when the card was written,
     which is the other half of having copied the wrong arrow. */
  .rx-header__card-arrow {
    transition: none;
  }

  a.rx-header__card:hover .rx-header__card-arrow {
    transform: none;
  }

  /* 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;
  }
}
