/* rx-block: rx-shero */

/* ==========================================================================
   Stacked hero — Figma 3111:5937 (Platform Alt frame)
   --------------------------------------------------------------------------
   Centred type, then a gold panel with two white cards stacked on it.

   ONE UNIT, --rx-shero-u, is one design pixel, damped above the design frame
   exactly the way the home hero's is: below 1512 the whole composition is
   viewport-relative and scales down as one drawing; above it, growth is
   halved so a 2560 display gets a larger panel rather than a panel-shaped
   billboard. Every number below is a measurement off the 1512 frame in that
   unit, so the file reads as the design does and nothing here is a ratio
   someone has to reverse-engineer.

   THE PANEL IS THE ANCHOR, not the section. The cards are positioned from the
   panel's own corner, so the spacing fields can make the section's padding
   asymmetric without the stack drifting off its base.
   ========================================================================== */

.rx-shero {
  position: relative;
  text-align: center;

  /* Same damping as .rx-hero: 1px per design pixel up to the frame, then half
     a pixel per pixel of viewport past it. Keeping the two identical is the
     point — a reader scrolling from the home hero into this one should not see
     the drawing change scale between them. */
  --rx-shero-u: var(--rx-u);

  /* The gap between the header pill and the heading. Figma has the pill's
     bottom at 119.90 and the heading's box at 215.18 — 95.28 between them, and
     the section owes 95.28 plus the pill's AT-REST OFFSET.

     Only the offset. The pill is position: sticky, so its 77px height is
     already in the flow above and charging for it again put the heading 85
     low; but the 43px it floats down by is a `top`, costs the page no flow
     height, and is not there. Measured both ways: with the full header tokens
     the pill-to-heading gap read 55 against the drawn 95, with neither it read
     55 the other way. --rx-header-top alone lands on it.

     Set on --rx-section-pt rather than as a padding, so an editor's "space
     above" choice still wins — that is the contract .rx-section documents. */
  --rx-section-pt: calc(var(--rx-header-top) + max(var(--rx-space-7), var(--rx-shero-u) * 95.28));

  /* Type. 56/1.02 is measured (3111:5983) and is not a step on the scale —
     held here rather than added to _tokens.css, the same call cta-band makes
     for its 54 and feature-card for its 48. It rides u so it shrinks with the
     composition, with a floor at the section-heading size so a phone gets
     readable type rather than a scaled-down poster. */
  --rx-shero-h1: max(var(--rx-text-3xl), calc(var(--rx-shero-u) * 56));

  /* Panel and the two cards, measured off 3111:5996 / 6001 / 6012. Card
     positions are offsets from the PANEL's top-left, not the frame's. */
  --rx-shero-panel-w: calc(var(--rx-shero-u) * 1050);
  --rx-shero-panel-h: calc(var(--rx-shero-u) * 520);
  --rx-shero-panel-r: calc(var(--rx-shero-u) * 14);

  /* How much scroll the panel's travel and the rings' drift are spent over.
     ON THE SECTION, not on the stack. The rings are a direct child of the
     section and the stack is inside .rx-shero__inner, so they are sibling
     branches — declared on the stack, this never reached the rings, their
     animation-range resolved to `0px <undefined>`, the whole declaration was
     invalid, and they silently fell back to the FULL page timeline. Which
     looks exactly like the drift not being wired up at all: over a 9000px
     document the first 500px of scroll moves them about five pixels. */
  --rx-shero-open-range: 520px;

}

/* --- Background rings (3111:5938 / 5939) ---------------------------------
   Two concentric hairlines, 1174 and 1330 across, centred at (756, 293.87) on
   the frame — i.e. behind the heading, and running off the TOP of the page.
   Gold Tint 3 at 2px, read off the exported SVG (#f1ebdc) rather than assumed
   from the neighbouring band.

   THE SECTION MUST NOT CLIP THEM. They are drawn cropped by the frame's own
   top edge, which is the page's top edge — `overflow: hidden` here would cut
   them at the section's box instead, which is a different and visible line.
   _base.css already contains the horizontal overflow on the root.

   Centred on the VIEWPORT, not the content column: the rings are wider than
   the container, so hanging them inside it would clip the part meant to run
   past it. Their vertical centre is 293.87 from the top of the page and the
   section starts at the page top, so the offset is measured straight down. */
/* Drawn by the SHARED css/_rings.css — this block says only where the centre is
   and how heavy the stroke. The construction it used to carry (the absolute box,
   the aspect-ratio circle, the -50% centring, the Gold Tint 3 border) is that
   file's job now, and deleting the copy is what makes the .rx-ring--c-* ramp
   modifiers reachable from the editor.

   293.87 below the section's top, on its centre line — a point BEHIND THE
   HEADING, so the pair is cropped by the top of the page rather than sitting on
   the panel. --rx-rings-y is multiplied by --rx-u and --rx-shero-u is an alias
   of it, so the drawn number carries over unchanged.

   The 2px stroke is measured, where _rings.css defaults to 1.5. The colour is
   not restated: Gold Tint 3 is already that file's default, which is why
   "default" in the editor emits no class at all. */
.rx-shero__point {
  --rx-rings-y: 293.87;
  --rx-rings-w: 2;
}

/* EXPANDING OUTWARD, innermost first — each starts under scale 1 and grows.
   This is the post-hero's gesture (see its module.css), not the home hero's,
   which starts at 1.75 and contracts inward.

   The two heroes deliberately differ and it is worth saying why rather than
   treating one as a mistake: the home hero's rings CLOSE around a collage that
   is already there, and this one's OPEN around a panel that expands with the
   scroll. Rings tightening onto a widening panel are two gestures arguing;
   both opening is one. */
/* Both scales are stated, overriding _rings.css's generic 0.7 / 0.62 ramp. That
   ramp is tuned for a cluster cropped by a section edge; these two are 1174 and
   1330 across on a point behind the headline, where the same scale is hundreds
   of pixels of travel and reads as a swell rather than an expansion. */
.rx-shero__ring--inner { --rx-reveal-from: 0.82; }
.rx-shero__ring--outer { --rx-reveal-from: 0.88; --rx-reveal-delay: 90ms; }

/* Above the rings. Both are children of the section and paint in DOM order,
   so without this the panel would sit under the hairlines rather than over
   them where they cross it. */
.rx-shero__inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.rx-shero__headline {
  margin: 0;
  /* 771 / 56 in em, not u: the type is floored and u is not, so a u
     measure squeezed the heading on a phone. */
  max-width: 13.77em;
  font-size: var(--rx-shero-h1);
  font-weight: 400;
  line-height: 1.02; /* measured 3111:5983 */
  color: var(--rx-heading); /* Figma #302b20 — the uncodified heading hex */
}

/* Figma draws 25 between the heading's box and the lead's CAP TOP. The lead is
   17/1.5, so its line box starts ((1.5 - 1.21) / 2 + .242) x 17 = 6.6 above
   that cap — a CSS margin of 25 would put 6.6 too much air in. 25 - 6.6 = 18.4
   (Inter metrics are in CLAUDE.md; leave the arithmetic here so the next
   person can check it rather than re-derive it). */
.rx-shero__lead {
  margin: max(var(--rx-space-4), calc(var(--rx-shero-u) * 18.4)) 0 0;
  max-width: max(calc(var(--rx-shero-u) * 578), 20em);
}

.rx-shero__eyebrow {
  margin: 0 0 var(--rx-space-4);
}

.rx-shero__actions {
  margin-top: var(--rx-space-6);
  justify-content: center;
}

/* --- The stack -----------------------------------------------------------
   Lead's trimmed baseline sits at 419.76 and its line box ends 6.6 below that
   (426.3); the panel starts at 501.05. 74.7 between them.

   THE PANEL WIDENS TO WIDTH 3 AS THE PAGE SCROLLS. It starts at the drawn
   1050 and travels to --rx-container-max, the theme's width 3 — the same
   width the footer panel and the CTA band's closed state take, so it lands on
   a width that already exists rather than on a number of its own.

   IT RESIZES FOR REAL rather than being clipped. .rx-frame would be cheaper —
   no layout per scroll frame — but a clip cuts the two floating cards off at
   the panel's old edge instead of carrying them, and they are the point of the
   block. Same trade rx-tm makes, and for the same reason; see the long note in
   css/_text-media.css. The cards' offsets are measured from the panel's
   top-left corner, so they stay put while the panel's right edge travels,
   which is what the design's composition wants.

   ON A scroll() TIMELINE, NOT view(). This block is at the top of the page, so
   it is already in view at load and its `entry` range never runs — a view()
   animation would be finished before the reader arrives. The travel is a
   function of how far the page has been scrolled, which is what scroll() says. */
@property --rx-shero-open {
  syntax: "<number>";
  inherits: false;
  /* 0, not 1: without scroll-timeline support the panel stays at the width
     Figma draws. rx-tm's equivalent rests at 1 because ITS settled state is
     the designed one; here the designed state is the start of the travel, so
     the safe fallback is the other end. */
  initial-value: 0;
}

.rx-shero__stack {
  --rx-shero-w-start: var(--rx-shero-panel-w);
  /* Plain 100%, NOT min(100% - gutter*2, --rx-container-max). The stack is
     already inside .rx-container, which IS width 3 — so the container's own
     gutter has been taken once and repeating the expression here takes it
     twice. Measured: the panel settled at 1192 instead of 1240 at a 1512
     viewport, which is exactly one gutter pair short. */
  --rx-shero-w-end: 100%;

  position: relative;
  margin-top: max(var(--rx-space-8), calc(var(--rx-shero-u) * 74.7));
  width: 100%;
  max-width: calc(
    var(--rx-shero-w-start) +
    (var(--rx-shero-w-end) - var(--rx-shero-w-start)) * var(--rx-shero-open)
  );
}

@keyframes rx-shero-open {
  from { --rx-shero-open: 0; }
  to   { --rx-shero-open: 1; }
}

/* The rings drift UP as the panel widens — they are behind the type and above
   the panel, so lifting them opens the gap the panel is growing into. Half the
   distance of an ordinary parallax: these are hairlines, and a fast one reads
   as a rendering artefact rather than as depth.

   On the WRAPPER, not the rings. The reveal driver owns `transform` on
   anything carrying data-rx-reveal, and the rings carry it — a second
   animation on the same property would replace the entrance rather than
   compose with it. A translate on the parent composes by construction. */
@keyframes rx-shero-ring-drift {
  to { translate: 0 calc(var(--rx-shero-ring-drift) * -1); }
}

@supports (animation-timeline: scroll()) {
  .rx-shero__stack {
    animation: rx-shero-open linear both;
    animation-timeline: scroll(root block);
    animation-range: 0px var(--rx-shero-open-range);
  }

  .rx-shero__rings {
    --rx-shero-ring-drift: calc(var(--rx-shero-u) * 90);
    animation: rx-shero-ring-drift linear both;
    animation-timeline: scroll(root block);
    animation-range: 0px var(--rx-shero-open-range);
  }
}

/* Reduced motion holds the DRAWN state — panel at 1050, rings where Figma puts
   them. Not the open state: "expand as you scroll" is the motion, and the
   thing to remove for a reader who has asked for less of it is the travel, not
   the block. */
@media (prefers-reduced-motion: reduce) {
  .rx-shero__stack {
    animation: none;
    --rx-shero-open: 0;
  }

  .rx-shero__rings { animation: none; }
}

/* _rings.css DROPS EVERY CLUSTER BELOW 767 and this pair is the exception, so
   the opt-out is stated here rather than the policy weakened there.

   That rule is right for the blocks it was written for: their rings are edge
   furniture measured against the 1512 frame, and at phone widths they stop
   running behind the content and start crossing it. This pair is concentric on
   a point behind the HEADLINE and sized in --rx-u, so as the screen narrows it
   stays a symmetric frame around the type — there is nothing for it to cross.
   Verified at 760: identical to what the block drew before it migrated onto the
   shared file.

   Later in the cascade at equal specificity, which is what wins here — module
   stylesheets are concatenated after css/_rings.css. */
@media (max-width: 767px) {
  .rx-shero__rings { display: block; }

  /* The drawn measures are a desktop line length; on a phone the column is
     already narrower than any of them, so a cap only squeezes the copy. */
  .rx-shero__headline,
  .rx-shero__lead { max-width: none; }
}

/* ASPECT, NOT A FIXED HEIGHT. The panel travels from 1050 to 1240 wide, and a
   fixed 520 height would have it stretch from the drawn 2.019:1 to 2.385:1 —
   the drawing would get letterboxed as it opened. Tying height to width keeps
   the frame the shape Figma draws at every point in the travel; at width 3 it
   stands 614 tall instead of 520.

   --rx-shero-panel-h is still the drawn height and is what the ratio is built
   from, so the two cannot drift. */
/* NO background-color here. The fill comes from the shared .rx-bg--* utility
   on the same element (see module.html): both are one class, so specificity
   ties and source order decides — and a module stylesheet is bundled after
   _utilities.css, so a declaration here would win every time and the editor's
   colour choice would do nothing. Gold/Base is the drawn value (3111:5996) and
   is the field's default instead. */
.rx-shero__panel {
  position: relative;
  overflow: hidden;
  width: 100%;
  aspect-ratio: 1050 / 520; /* measured 3111:5996 */
  border-radius: var(--rx-shero-panel-r);

  /* Centres the screenshot. The drawn abstraction is absolutely positioned and
     is unaffected by this. */
  display: flex;
  align-items: center;
  justify-content: center;
}

/* A real screenshot, when there is one. It replaces the drawn abstraction
   rather than sitting over it — see module.html.

   IN FLOW, not absolutely positioned as it used to be. Inset 0 + cover is the
   one arrangement that cannot be centred or padded: the box IS the panel, so
   there is no room around it to leave. As a flex child the panel centres it
   and the fit/inset pair below decide how much of it fills the panel — the
   same two controls, and the same reasoning, as feature-card's media panel
   (css/_feature-card.css). */
.rx-shero__shot {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --- Image fit ------------------------------------------------------------
   A product screenshot is a drawing, not a photograph: cover enlarges it until
   its height fills a 2:1 panel and throws most of its width off the sides.
   Contain is therefore the default here, where feature-card defaults to cover
   — that panel is portrait and takes photography, this one does not. */
.rx-shero__panel--fit-contain .rx-shero__shot {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* --- Image inset ----------------------------------------------------------
   CONTAIN ON ITS OWN DOES NOT MAKE A WIDE IMAGE SMALL — it fits the image to
   the panel, so a landscape screenshot fills the width and touches both edges.
   Leaving panel colour around it is the only thing that does, and how much is
   a composition decision, so it is a field.

   The padding is on the IMAGE, not the panel: the panel also holds the drawn
   abstraction, which is registered to the panel's own box and would be shrunk
   by a padding meant for a screenshot. Under border-box it comes out of the
   100% rather than adding to it, so the panel's measured size is untouched.

   Steps are the design-pixel unit, so they scale with the composition exactly
   as everything else in this block does — feature-card reaches for cqw only
   because its card has no such unit. They are feature-card's drawn 24/48/96
   over its 1257 card, restated against this panel's 1050 (20/40/80). The
   max() floor keeps a step visible as colour on a phone, where u is small. */
.rx-shero__panel--inset-small .rx-shero__shot {
  padding: max(0.75rem, calc(var(--rx-shero-u) * 20));
}

.rx-shero__panel--inset-medium .rx-shero__shot {
  padding: max(1rem, calc(var(--rx-shero-u) * 40));
}

.rx-shero__panel--inset-large .rx-shero__shot {
  padding: max(1.25rem, calc(var(--rx-shero-u) * 80));
}

/* --- The drawn app surface -----------------------------------------------
   3111:5997 / 5998 / 5999 / 6000. Four rectangles and a rule, every one of
   them running out to the panel's own right and bottom edges, which is what
   makes it read as a window onto something larger rather than as four shapes
   arranged on a background.

   The opacities are the design's (50% on the tint, 18% on the two panes).
   The rule's colour was SAMPLED off the render, not read from a variable —
   it is an untitled line in an abstraction, so there is no ramp value to
   resolve it to; white at low strength is what it looks like on the gold. */
.rx-shero__surface,
.rx-shero__rule,
.rx-shero__pane {
  position: absolute;
  display: block;
}

.rx-shero__surface {
  inset:
    calc(var(--rx-shero-u) * 136.9) 0 0
    calc(var(--rx-shero-u) * 220.84);
  border-start-start-radius: calc(var(--rx-shero-u) * 34);
  background-color: var(--rx-gold-t2);
  opacity: 0.5;
}

.rx-shero__rule {
  inset:
    calc(var(--rx-shero-u) * 225.28) 0 auto
    calc(var(--rx-shero-u) * 217.84);
  height: 1px;
  background-color: var(--rx-white);
  opacity: 0.35;
}

.rx-shero__pane {
  bottom: 0;
  top: calc(var(--rx-shero-u) * 256.95);
  background-color: var(--rx-white);
  opacity: 0.18;
}

.rx-shero__pane--a {
  left: calc(var(--rx-shero-u) * 252.95);
  width: calc(var(--rx-shero-u) * 282.05);
  border-start-start-radius: calc(var(--rx-shero-u) * 20);
  border-start-end-radius: calc(var(--rx-shero-u) * 20);
}

.rx-shero__pane--b {
  left: calc(var(--rx-shero-u) * 546);
  right: 0;
  border-start-start-radius: calc(var(--rx-shero-u) * 20);
}

/* --- The floating cards ---------------------------------------------------
   Positioned from the panel's corner. Both carry the panel's own deep glow
   (Figma draws it as a second, inset white rectangle behind each card with a
   178px / 146px blur — that is a shadow modelled as a shape, and a shadow is
   what it should be). */
/* ANCHORED TO THE PANEL'S CENTRE, not its top-left corner. The panel grows to
   the right as it travels; corner-anchored, the two cards sat still and the
   whole composition drifted left inside a widening frame. Offset from the
   centre, the extra width opens evenly on both sides and the cards stay put
   in the middle of it — which is the rule CLAUDE.md's "50% of the wrong box"
   section arrives at, applied to a box that MOVES rather than one that is
   ambiguous.

   Offsets are the measured card centres against the panel's (525, 260):
     recap  85.44 + 483.43/2 = 327.155  ->  -197.845
            52.64 + 302.31/2 = 203.795  ->   -56.205
     stats  587   + 398.45/2 = 786.225  ->  +261.225
            291.84 + 127.38/2 = 355.53  ->   +95.53

   `translate`, not a translate inside `transform`: the reveal driver owns
   `transform` on anything carrying data-rx-reveal and these do, so centring
   has to live on its own property or the two fight. Same construction the CTA
   band's tiles use. */
.rx-shero__card {
  position: absolute;
  left: 50%;
  top: 50%;
  translate:
    calc(-50% + var(--rx-shero-u) * var(--rx-shero-card-x))
    calc(-50% + var(--rx-shero-u) * var(--rx-shero-card-y));
  text-align: left;
  background-color: var(--rx-white);
  box-shadow: var(--rx-shadow-lg);
}

.rx-shero__card--recap {
  --rx-shero-card-x: -197.845;
  --rx-shero-card-y: -56.205;
  width: calc(var(--rx-shero-u) * 483.43);
  min-height: calc(var(--rx-shero-u) * 302.31);
  padding:
    calc(var(--rx-shero-u) * 21.82)
    calc(var(--rx-shero-u) * 25.58)
    calc(var(--rx-shero-u) * 24);
  border-radius: calc(var(--rx-shero-u) * 14.34);
}

.rx-shero__card-title {
  display: flex;
  align-items: center;
  gap: calc(var(--rx-shero-u) * 6);
  margin: 0 0 calc(var(--rx-shero-u) * 10);
  padding-bottom: calc(var(--rx-shero-u) * 12);
  border-bottom: 1px solid var(--rx-rule);
  font-size: calc(var(--rx-shero-u) * 13.32); /* measured 3111:6009 */
  font-weight: 600;
  line-height: var(--rx-leading-snug);
  color: var(--rx-heading);
}

.rx-shero__card-icon {
  flex: none;
  width: calc(var(--rx-shero-u) * 24.59);
  height: calc(var(--rx-shero-u) * 24.59);
  color: var(--rx-heading);
}

/* The fade. See module.html for why this is a mask and not five coloured
   spans. Ends at 60% so the first sentence is at full strength and the tail
   is gone by the card's floor — Figma's five ramp steps run out at the same
   place. -webkit- first: Safari still needs the prefixed property, and an
   unprefixed-only declaration there leaves the copy at full strength, which
   is legible and merely undesigned rather than broken. */
.rx-shero__card-body {
  -webkit-mask-image: linear-gradient(to bottom, var(--rx-white) 18%, transparent 92%);
  mask-image: linear-gradient(to bottom, var(--rx-white) 18%, transparent 92%);
  font-size: calc(var(--rx-shero-u) * 16.39); /* measured 3111:6011 */
  line-height: 1.5;
  color: var(--rx-heading);
}

.rx-shero__card-body p {
  margin: 0 0 calc(var(--rx-shero-u) * 16);
}

.rx-shero__card-body p:last-child { margin-bottom: 0; }

/* --- Stats card (3111:6012) ---------------------------------------------- */

.rx-shero__card--stats {
  --rx-shero-card-x: 261.225;
  --rx-shero-card-y: 95.53;
  width: calc(var(--rx-shero-u) * 398.45);
  min-height: calc(var(--rx-shero-u) * 127.38);
  padding: calc(var(--rx-shero-u) * 26.33) calc(var(--rx-shero-u) * 28.84);
  border-radius: calc(var(--rx-shero-u) * 11.75);

  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  gap: calc(var(--rx-shero-u) * 28.84);
}

/* The divider is Figma's Line 82 (3111:6056), a full-height rule between the
   two tiles. A border on every tile but the first gives the same line at any
   tile count, and none at one. */
.rx-shero__stat + .rx-shero__stat {
  padding-inline-start: calc(var(--rx-shero-u) * 28.84);
  border-inline-start: 1px solid var(--rx-rule);
}

.rx-shero__stat-label {
  margin: 0;
  font-size: calc(var(--rx-shero-u) * 10.91); /* measured 3111:6052 */
  font-weight: 600;
  line-height: var(--rx-leading-snug);
  color: var(--rx-text-muted);
}

.rx-shero__stat-figure {
  margin: calc(var(--rx-shero-u) * 5) 0 calc(var(--rx-shero-u) * 14);
  font-size: calc(var(--rx-shero-u) * 20.99); /* measured 3111:6054 */
  font-weight: 500;
  line-height: 1.1;
  color: var(--rx-heading);
}

.rx-shero__stat-foot {
  display: flex;
  align-items: center;
  gap: calc(var(--rx-shero-u) * 10);
}

.rx-shero__spark {
  flex: none;
  width: calc(var(--rx-shero-u) * 54.26);
  height: calc(var(--rx-shero-u) * 27.19);
  color: var(--rx-gold-t1);
}

.rx-shero__delta {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--rx-shero-u) * 5);
  font-size: calc(var(--rx-shero-u) * 9.23); /* measured 3111:6034 */
  font-weight: 500;
  color: var(--rx-text-muted);
  white-space: nowrap;
}

.rx-shero__delta-mark {
  display: grid;
  place-items: center;
  width: calc(var(--rx-shero-u) * 15.73);
  height: calc(var(--rx-shero-u) * 15.73);
  border-radius: var(--rx-radius-pill);
  background-color: var(--rx-gold-base);
  color: var(--rx-white);
}

.rx-shero__delta-mark svg {
  width: calc(var(--rx-shero-u) * 11.86);
  height: calc(var(--rx-shero-u) * 11.86);
}

/* One arrow drawn once and turned, rather than two paths that have to be kept
   consistent with each other. Down-right is the drawn state (3111:6032); up is
   the same mark rotated a quarter turn (3111:6049 is drawn as exactly that). */
.rx-shero__delta--up .rx-shero__delta-mark svg { transform: rotate(-90deg); }

/* --- Entrance ------------------------------------------------------------
   The panel arrives first and the cards push out from its centre after it, so
   the stack assembles front-to-back instead of landing all at once. The type
   is a fade only — --rx-reveal-from: 1 is the shared reveal's opt-out from the
   scale, and a zoom on a 56px line reads as the text resizing, not arriving. */
/* The type expands from ITS OWN centre. Two halves to that:

   data-rx-reveal-origin="self" in the markup opts each line out of the
   section's focal origin — this section's focus is .rx-shero__panel, which is
   BELOW the type, so without the opt-out every line scaled about a point off
   the bottom of the screen and slid rather than grew.

   And --rx-reveal-from is under 1 so there is something to grow. An earlier
   pass held these at 1 (fade only) on the argument that a zoom on a 56px line
   reads as the text resizing; at 0.94 about its own centre it reads as
   arriving, because the whole centred column moves together rather than one
   line changing size against its neighbours. */
.rx-shero__eyebrow,
.rx-shero__headline,
.rx-shero__lead,
.rx-shero__actions {
  --rx-reveal-from: 0.94;
}

.rx-shero__headline { --rx-reveal-delay: 60ms; }
.rx-shero__lead     { --rx-reveal-delay: 120ms; }
.rx-shero__actions  { --rx-reveal-delay: 180ms; }
.rx-shero__panel    { --rx-reveal-delay: 240ms; --rx-reveal-from: 0.96; }

.rx-shero__card--recap { --rx-reveal-delay: 400ms; --rx-reveal-from: 0.9; }
.rx-shero__card--stats { --rx-reveal-delay: 480ms; --rx-reveal-from: 0.9; }

/* --- Responsive ----------------------------------------------------------
   Above 767 the whole composition is one drawing and shrinks as one, which is
   what u already does. Below it, u has taken the card type under 8px — small
   enough that it stops being copy and starts being texture. So the cards come
   off the panel and become ordinary cards under it, at their own readable
   size, and the panel keeps the abstraction on its own.

   The panel also loses its fixed height there: at phone widths 520u is a
   sliver, and a picture with nothing in it is better as a shorter band. */
@media (max-width: 767px) {
  .rx-shero__stack {
    display: flex;
    flex-direction: column;
    gap: var(--rx-space-5);
    max-width: 100%;
  }

  .rx-shero__panel {
    height: auto;
    aspect-ratio: 1050 / 520;
    border-radius: var(--rx-radius-card);
  }

  .rx-shero__card {
    position: static;
    translate: none;
    width: 100%;
    padding: var(--rx-space-5);
    border-radius: var(--rx-radius-card);
  }

  .rx-shero__card--recap,
  .rx-shero__card--stats {
    min-height: 0;
  }

  .rx-shero__card-title { font-size: var(--rx-text-sm); }
  .rx-shero__card-body { font-size: var(--rx-text-base); }
  .rx-shero__card-body p { margin-bottom: var(--rx-space-4); }
  .rx-shero__stat-label { font-size: var(--rx-text-xs); }
  .rx-shero__stat-figure { font-size: var(--rx-text-xl); margin-block: var(--rx-space-1) var(--rx-space-3); }
  .rx-shero__delta { font-size: var(--rx-text-xs); }

  .rx-shero__delta-mark { width: 20px; height: 20px; }
  .rx-shero__delta-mark svg { width: 14px; height: 14px; }
  .rx-shero__spark { width: 64px; height: 28px; }

  .rx-shero__stat + .rx-shero__stat {
    padding-inline-start: var(--rx-space-5);
  }

  .rx-shero__card--stats { gap: var(--rx-space-5); }
}
