/*
  Hero (v2) — Website Refresh 2026 1e (Figma), "Hero Test" frame.
  Source: https://www.figma.com/design/2W6CyIAW3cKDEqdv26CeE2/Website-Refresh-2026-1e?node-id=8006-82355

  Composes three pieces built separately: the Background Image
  crossfade (node-id=8004-39047), the UI Card grid per sector
  (node-id=8095-50910 / 8004-39589), and this frame's own heading/
  copy/CTA layout. Header/nav is deliberately excluded — out of scope
  for this pass per your instruction.

  TIMING/EASING ARE PROVISIONAL. Figma can't show motion, so these
  are first-pass values based on your written description (staggered
  fade+slide, background crossfade starting roughly when cards begin
  exiting) — tune the custom properties below once you've seen it
  running, nothing here is meant to be final.

  SCALING APPROACH: the foreground (crest, heading, copy, CTA, UI
  mock) is built at Figma's literal 1440x900 pixel positions/sizes
  inside .rs-hero-v2__stage, then the whole stage is scaled down
  uniformly via CSS transform (set in hero.js from the container's
  actual rendered width) to fit any viewport. This keeps every
  internal proportion — including the UI Card's own tiny fixed-px
  type scale — exactly as designed at any size, rather than needing
  a separate fluid clamp() for dozens of individual values. Only the
  background photo is true full-bleed cover, sized independently of
  the stage.

  TABLET + MOBILE (≤1200px): the single-scaled-stage approach above
  is desktop-only. See the dedicated section near the end of this
  file — content flows at real page-typography sizes (Tablet tier
  down to 768px, Mobile tier below that — typography.css) instead of
  shrinking in lockstep with the whole 1440px stage. Text and the UI
  mock stay side-by-side as a 50/50 flex row through the Tablet tier
  (down to a portrait-iPad 768px), only stacking full-width below
  that in the Mobile tier — the UI mock's children are fluid/
  percentage-based either way, not a scale-to-fit transform.
*/

.rs-hero-v2 {
  --hero-crossfade-duration: 1200ms;
  --hero-card-fade-duration: 450ms;
  --hero-card-stagger: 70ms;
  --hero-card-gap-duration: 250ms;
  /* This is the interval between the START of one transition and the
     next, not the settled/fully-visible time — the exit+gap+enter
     sequence above (~450 + 5*70 + 250 + 450 + 5*70 = ~1850ms) eats
     into it. 7000ms here leaves each sector settled and fully
     visible for a bit over 5 seconds, which is what "each sector
     lasts about 5 seconds" means in practice. */
  --hero-hold-duration: 7000ms;

  position: relative;
  width: 100%;
  aspect-ratio: 1440 / 900;
  /* On a wide-but-short viewport (laptop screens at 1366x768,
     1280x720 etc.) the 1440:900 ratio makes the hero taller than the
     actual browser window, pushing the CTA below the fold or right
     up against its bottom edge. Capping height at the viewport means
     the box can end up shorter than the ratio implies — fitStage()
     in hero.js accounts for that by scaling to whichever of width or
     height is the tighter constraint, so content still fits instead
     of just getting clipped by overflow: hidden below. */
  max-height: 100vh;
  overflow: hidden;
  background-color: var(--color-neutral-900);
  font-family: var(--font-body);
}

/* ---------- Background crossfade (true full-bleed, outside the scaled stage) ---------- */

.rs-hero-v2__bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  opacity: 0;
  transition: opacity var(--hero-crossfade-duration) ease;
}

.rs-hero-v2__bg.is-active {
  opacity: 1;
  z-index: 1;
}

.rs-hero-v2__overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  background-color: var(--color-transparency-dark-50);
}

/* ---------- Scaled stage (everything positioned at literal Figma px) ---------- */

.rs-hero-v2__stage {
  position: absolute;
  top: 0;
  left: 0;
  width: 1440px;
  height: 900px;
  transform-origin: top left;
  z-index: 3;
}

.rs-hero-v2__crest {
  /* Was independently absolute-positioned (top: 311px) against the
     content block's old, fixed top: 512px position. Now that content
     is bottom-anchored (see below) and its top edge moves depending
     on how many lines the heading/body wrap to, the crest is instead
     the content flex column's first child — it always sits a fixed
     gap above the heading, whatever that heading's height turns out
     to be, rather than needing to be re-measured by hand every time
     the copy changes. */
  width: 140px;
  margin-bottom: 24px;
  pointer-events: none;
}

.rs-hero-v2__content {
  position: absolute;
  left: 48px;
  /* Bottom-anchored (not top: 512px, its original position when the
     copy was shorter) so its bottom edge lines up with the mock UI's
     bottom edge regardless of how many lines the heading/body wrap
     to. Mock UI bottom = ui-mock top (157px) + .rs-ui-mock's own
     content height (32px search field + 16px gap + 32px filter row +
     18px gap + 530px grid-stage = 628px) + its 24px top/bottom
     padding (48px) = 833px from the 900px-tall stage's top, i.e.
     67px from its bottom. */
  bottom: 67px;
  width: 648px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Prefixed with .rs-hero-v2 (not just the bare .rs-hero-v2__heading
   class) so this beats the legacy sitewide /css/style.css rule
   ".home-page h1 { font-size: 80px; ... }" on specificity (0,2,0)
   vs its 0,1,1) — the bare class alone (0,1,0) was actually LOSING
   to that legacy rule regardless of file load order or caching,
   since higher specificity always wins over source order when they
   differ. Same fix pattern likely needed anywhere else a legacy
   .home-page <tag> selector exists for an element this component
   also uses (buttons, pills, etc. — flagged separately, not yet
   confirmed which legacy rules those hit).

   text-align: left is explicit for the same family of reasons, but
   isn't a specificity fight — a separate legacy rule, responsive.css's
   ".home-page h1 { text-align: center; ... }" (active below 1199px),
   was the only rule anywhere setting text-align on this element at
   all, so it won by default with nothing of ours competing for that
   property specifically. */
.rs-hero-v2 .rs-hero-v2__heading {
  margin: 0;
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 60px;
  line-height: 1.05;
  letter-spacing: -1.2px;
  text-align: left;
  color: var(--color-neutral-white-50);
}

.rs-hero-v2__text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 24px;
}

/* 22px matches .rs-body--large's Desktop size (typography.css) —
   kept in sync manually since this is a standalone value, not the
   shared class itself (the hero's own weight/colour differ from
   .rs-body). */
.rs-hero-v2__body {
  margin: 0;
  font-weight: 400;
  font-size: 22px;
  line-height: 1.4;
  color: var(--color-neutral-white-50);
}

.rs-hero-v2__actions {
  display: flex;
  align-items: center;
  gap: 16px;
}

/* ---------- UI Mock stage ---------- */

.rs-hero-v2__ui-mock {
  position: absolute;
  left: 808px;
  top: 157px;
  width: 680px;
  pointer-events: none;
}

.rs-hero-v2__grid-stage {
  position: relative;
  width: 100%;
  height: 530px;
}

.rs-hero-v2__cards {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  gap: 18px;
  visibility: hidden;
}

.rs-hero-v2__cards.is-active,
.rs-hero-v2__cards.is-exiting {
  visibility: visible;
}

.rs-hero-v2__cards .rs-ui-mock__row {
  flex: 1 1 0%;
  min-height: 0;
}

.rs-hero-v2__cards .rs-ui-card {
  flex: 1 1 0%;
  min-width: 0;
  min-height: 0;
  width: auto;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--hero-card-fade-duration) ease, transform var(--hero-card-fade-duration) ease;
}

/* Card is flex:1 (height comes from the row, not a fixed 244px) here,
   so the image needs a proportional height (150/244) instead of the
   fixed 150px ui-card.css uses standalone. */
.rs-hero-v2__cards .rs-ui-card__image {
  height: 61.47%;
  flex-shrink: 0;
}

.rs-hero-v2__cards.is-active .rs-ui-card {
  opacity: 1;
  transform: translateY(0);
}

.rs-hero-v2__cards.is-exiting .rs-ui-card {
  opacity: 0;
  transform: translateY(-16px);
}

/* ---------- Legibility ---------- */
/* Card/filter type sizing now lives directly in ui-card.css (title +
   filter buttons 12px, everything else 10px — confirmed against
   Figma), so the hero inherits it with no override needed.

   The card's height is fixed here (flex:1 within a fixed-height
   row), unlike the standalone ui-card.html page where it's allowed
   to grow — so the pill row can't wrap to a second line without
   overflowing and clipping the footer beneath it. Kept to a single
   line + overflow:hidden as a safety net for any status label that
   doesn't fit alongside the ID and count pills (comfortable at 10px,
   but not guaranteed for every possible label length). */

.rs-hero-v2 .rs-ui-card__content {
  overflow: hidden;
}

.rs-hero-v2 .rs-ui-card__pills {
  flex-wrap: nowrap;
}

.rs-hero-v2 .rs-ui-card-status {
  min-width: 0;
  flex-shrink: 1;
  overflow: hidden;
}

.rs-hero-v2 .rs-ui-card-pill--id,
.rs-hero-v2 .rs-ui-card-pill--count {
  flex-shrink: 0;
}

/* Search field text is still at Figma's literal (very small) size —
   bumped here for the same real-viewing-size legibility reason as
   the cards, flagged as a deliberate deviation rather than a
   Figma-accuracy question (not corrected/covered by your last note,
   so still worth confirming). */
.rs-hero-v2 .rs-ui-search-field__text {
  font-size: 15px;
}

.rs-hero-v2 .rs-ui-search-field__icon {
  width: 19px;
  height: 19px;
}

/* ---------- Tablet (≤1200px, side-by-side down to 768px) ---------- */
/* The desktop approach above — build everything at literal 1440x900
   px, scale the whole .rs-hero-v2__stage down as one unit — was never
   actually designed for anything narrower than desktop; it just
   happened to still "work" in the sense that nothing broke, at the
   cost of the heading/body shrinking in lockstep with the viewport
   width (a 60px heading was already down to ~48px by 1150px wide,
   about to cross under a plain page .rs-heading--h1's full 48px — a
   backwards hierarchy). Below, the stage stops being a single scaled
   unit and content flows normally at real type-scale sizes (Tablet
   tier here — typography.css, sourced from Figma's Tablet/Header and
   Tablet/Body styles — Mobile tier in the narrower block below), not
   a fraction of the desktop-only 60px/24px hero values.

   Text and UI mock stay side-by-side through this whole tier. Unlike
   a plain 50/50 split, the mock has a fixed, non-shrinking width
   (flex: 0 0 600px) and is allowed to run off the right edge once
   there isn't room for it plus the text — the same bleed the
   desktop-scaled stage above already has built in (its mock sits at
   left:808px + width:680px = 1488px inside a nominally 1440px-wide
   stage, i.e. 48px already hangs off-canvas at native scale, clipped
   by .rs-hero-v2's own overflow: hidden). Containing the mock fully
   within a shrinking column (the previous attempt here) squashed its
   card images narrower without changing their fixed-percentage
   height, visibly distorting them — letting it bleed instead keeps
   the mock's own proportions intact at the cost of showing
   progressively less of its right side as the column narrows. Text
   keeps a 260px floor (flex: 1 1 0%; min-width: 260px) so it's always
   legible; that floor plus the mock's fixed width is what pushes the
   mock off-canvas once the two together no longer fit.

   The UI mock keeps its FULL chrome here (search field, filter row,
   both card rows, landscape crop) — unlike Mobile, which switches to
   the simplified single-row/square-card treatment only once it
   stacks below 768px. The one piece trimmed at this tier already is
   each card's pills/footer row (ID/status/count, filetype/add) —
   title + filename reads fine without it and it's the first thing
   that got cramped once the mock's card grid runs at real (not
   scaled-down) pixel sizes. Not yet checked against a real device. */

@media (max-width: 1200px) {
  .rs-hero-v2 {
    height: 90vh;
  }

  .rs-hero-v2__stage {
    position: relative;
    top: auto;
    left: auto;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: row;
    align-items: flex-end;
    /* A flex gap always renders as real empty space between the two
       items regardless of how much room either one is given, so this
       is a genuine minimum gutter, not just a target that erodes once
       content/mock start competing for space — was --space-24 (24px),
       which read as the two sides sitting flush together once the
       mock's bleed-off-canvas behaviour kicked in around 1024px and
       narrower. */
    gap: var(--space-48);
    padding: var(--space-32) var(--space-24);
    box-sizing: border-box;
  }

  .rs-hero-v2__content {
    position: static;
    flex: 1 1 0%;
    min-width: 340px;
    width: auto;
    gap: var(--space-16);
  }

  .rs-hero-v2__text {
    gap: var(--space-20);
  }

  .rs-hero-v2__crest {
    width: 130px;
    margin-bottom: 24px;
  }

  /* Figma bumped Tablet/Header/Hero to 48px (2026-09) specifically —
     using that "Hero" style bucket rather than continuing to match
     .rs-heading--h1's Tablet size (32px, the convention Mobile below
     still follows) since tuning that particular style is a clear
     signal it's meant for exactly this.

     Prefixed with .rs-hero-v2 to match the base rule's specificity
     (0,2,0) — after the base rule was bumped from the bare
     .rs-hero-v2__heading class to beat a legacy sitewide
     ".home-page h1" selector, this override (still at the old,
     lower specificity) stopped winning even inside its own media
     query, since a more specific rule beats a less specific one
     regardless of whether it's the one wrapped in @media. */
  .rs-hero-v2 .rs-hero-v2__heading {
    font-size: 48px;
    line-height: 1.05;
    letter-spacing: -0.96px;
  }

  .rs-hero-v2__body {
    font-size: 20px;
    line-height: 1.4;
  }

  .rs-hero-v2__ui-mock-frame {
    position: static;
    flex: 0 0 600px;
  }

  .rs-hero-v2__ui-mock {
    position: static;
    width: 100%;
    padding: 20px;
  }

  /* Pills (ID/status/count) and the filetype/add footer are the first
     things trimmed once the mock renders at real pixel sizes instead
     of scaled down — title + filename is plenty to read as "these are
     asset cards" on its own. Search/filter/both rows all stay, unlike
     Mobile's further-simplified treatment below. */
  .rs-hero-v2__cards .rs-ui-card__pills,
  .rs-hero-v2__cards .rs-ui-card__footer {
    display: none;
  }

  /* Base (desktop) rule is height: 61.47% of the row — a landscape
     crop tuned for the desktop card's own width. At this tier's
     column width (each card roughly a third of ~600px) that same
     percentage renders visibly squashed: wide relative to how tall
     it is. Square avoids needing a width-aware ratio here. */
  .rs-hero-v2__cards .rs-ui-card__image {
    height: auto;
    aspect-ratio: 1 / 1;
  }

  /* Base (desktop) value is 530px, sized for two rows of the
     landscape crop with pills/footer showing. With square images
     (taller than the old landscape crop) and no pills/footer this
     needs its own number — measured directly rather than guessed:
     at this tier's ~600px mock width, each square image renders
     ~176px tall (driven by its own width, independent of this
     value), and title+filename's natural content height is 62px, so
     each row needs 176 + 62 = 238px — 460px (one first-pass guess
     too low) was squeezing that by ~17px, and since .rs-ui-card__
     content's own overflow: hidden clips whatever doesn't fit
     starting from the bottom, that 17px shortfall was exactly the
     missing bottom padding reported. 500px leaves a little slack
     above the measured 494px (238*2 + 18px row gap). */
  .rs-hero-v2__grid-stage {
    height: 500px;
  }
}

/* A short viewport in this tier (1024x768 landscape, say) doesn't
   have 90vh of room to give: the mock's ~638px natural height (600px
   wide, per above) needed against a 90vh-tall stage minus its own
   64px top+bottom padding left only ~549px, so the mock overflowed
   the stage's top edge by ~89px and rendered up underneath the
   header.

   First attempt shrank the mock's fixed width to bring its height
   down — wrong move: the whole point of the fixed 600px width is
   that it stays put and bleeds off the right edge rather than ever
   being squeezed to fit, and shrinking it also narrowed each card
   enough that the filter row wrapped and titles needed truncating.
   Dropping to a single card row instead saves the same ~260px
   (one row's image + content + its gap) without touching width at
   all — cards stay full-size and still bleed exactly as they do
   everywhere else in this tier, matching how Mobile already handles
   its own space constraints the same way. Scoped to width too (not
   just height) so it can't reach into Mobile's already-tuned,
   structurally different layout below 768px. */
@media (max-width: 1200px) and (min-width: 768px) and (max-height: 850px) {
  .rs-hero-v2__cards .rs-ui-mock__row:nth-child(2) {
    display: none;
  }

  .rs-hero-v2__grid-stage {
    height: 250px;
  }
}

/* ---------- Mobile (<768px, stacks) ---------- */
/* 768px itself (a portrait iPad) is the floor for the Tablet tier's
   side-by-side treatment above — this only takes over strictly below
   that, switching back to the original, already-approved stacked
   treatment: text full-width, single row of 3 asset cards beneath it
   instead of beside it. Sizing also drops to the Mobile type-scale
   tier. */

@media (max-width: 767px) {
  .rs-hero-v2__stage {
    flex-direction: column;
    justify-content: flex-end;
    padding: var(--space-32) var(--space-16);
  }

  /* flex: 0 0 auto resets the Tablet tier's flex: 1 1 0% (a flex-grow
     meant for sharing width in that tier's side-by-side row) back to
     its natural/intrinsic size. Left inheriting flex-grow: 1 here,
     content stretched to fill the column's leftover vertical space
     instead of just wrapping its own crest/heading/body/CTA — which
     both pushed the crest up far enough to run under the header logo
     and opened a large gap between the CTA and the UI mock below
     (mock is a sibling flex item in this same column, flex: 0 0 auto
     itself, so it kept its own natural size throughout — it was
     content's box growing around it that created the gap). Same
     story for min-width: 0 — the Tablet tier's 340px floor (there to
     stop the heading's longest word overflowing a narrow row column)
     has no reason to apply once this is a full-width column instead,
     and left in place would force real horizontal overflow on any
     phone narrower than ~372px. */
  .rs-hero-v2__content {
    flex: 0 0 auto;
    min-width: 0;
    width: 100%;
    gap: var(--space-12);
  }

  .rs-hero-v2__text {
    gap: var(--space-16);
  }

  /* 130px (Tablet's crest width) reads as oversized once the
     heading/body next to it drop to Mobile's smaller sizes — it was
     tuned against Tablet-scale neighbours, not phone ones. */
  .rs-hero-v2__crest {
    width: 80px;
    margin-bottom: 16px;
  }

  /* Prefixed with .rs-hero-v2 to match the base rule's specificity —
     same reasoning as the Tablet tier's override above. */
  .rs-hero-v2 .rs-hero-v2__heading {
    font-size: 28px;
    line-height: 1.2;
    letter-spacing: -0.25px;
  }

  .rs-hero-v2__body {
    font-size: 18px;
    line-height: 1.4;
  }

  .rs-hero-v2__ui-mock-frame {
    flex: 0 0 auto;
    width: 100%;
  }

  .rs-hero-v2__ui-mock {
    padding: 16px;
  }

  /* Below this width the mock switches from the Tablet tier's full
     chrome (search field, filter row, both card rows, pills/footer,
     landscape crop) to a simplified single row of 3 square cards —
     the treatment this was originally designed/approved against,
     before the Tablet tier existed. */
  .rs-hero-v2__ui-mock .rs-ui-search-field,
  .rs-hero-v2__ui-mock .rs-ui-mock__filter {
    display: none;
  }

  /* Only the first of each sector's two 3-card rows shows. */
  .rs-hero-v2__cards .rs-ui-mock__row:nth-child(2) {
    display: none;
  }

  /* Pills (ID/status/count) and the filetype/add footer were the
     "busy/scrunched" part at phone card size — title + filename is
     plenty to read as "these are asset cards" on its own. */
  .rs-hero-v2__cards .rs-ui-card__pills,
  .rs-hero-v2__cards .rs-ui-card__footer {
    display: none;
  }

  /* Square rather than the desktop 150px-tall landscape crop — with
     pills/footer gone there's no fixed lower content dictating the
     card's proportions any more, and square reads better than an
     arbitrary landscape ratio at this width. Cards still stretch to
     fill .rs-hero-v2__grid-stage's height below (flex align-items:
     stretch, the row's default) — height: auto here lets the image
     be exactly as tall as it is wide instead of a fraction of that
     stretched total. */
  .rs-hero-v2__cards .rs-ui-card__image {
    height: auto;
    aspect-ratio: 1 / 1;
  }

  /* A fixed px value here can't work across the whole Mobile width
     range: the image is a square exactly as tall as the card is
     wide, and the card's width is itself a fraction of the viewport
     (mock spans full width here), so the row's real required height
     scales continuously with viewport width — 190px (a first-pass
     guess, unchanged since before square crop/pills-footer-removal)
     was too short at the wide end of this tier (~767px, measured
     ~296px needed) and .rs-ui-card__content's own overflow: hidden
     clipped the filename as a result, while also being taller than
     necessary at a typical phone width (~390px, only ~171px needed).
     Deriving it directly avoids both: card width = (100vw - 32px
     stage padding - 32px .rs-hero-v2__ui-mock padding - 32px for the
     row's own two 16px gaps between cards) / 3, image height equals
     that (square), plus content's own measured natural height (62px,
     title + filename + .rs-ui-card__content's 12px padding each
     side), plus a small margin. */
  .rs-hero-v2__grid-stage {
    height: calc((100vw - 96px) / 3 + 72px);
  }
}

/* ---------- Small phone (<390px): drop the UI mock entirely ---------- */
/* Below the width the mobile card row was actually designed/checked
   against, three cards (even at one row) don't have enough space to
   read as anything but a cramped afterthought beneath the text — so
   this drops the mock rather than keep shrinking it. .rs-hero-v2__
   stage is already flex-direction: column; justify-content: flex-end
   (Mobile tier above), so with the mock gone the text is simply the
   only flex item left and sits at the bottom on its own — no extra
   rule needed to "move" it there. Narrower than Mobile's own 767px
   breakpoint, so it must come after that block in the file for the
   cascade to apply it at these widths (same reasoning as every other
   mobile-over-tablet override in this file). */
@media (max-width: 389px) {
  .rs-hero-v2__ui-mock-frame {
    display: none;
  }
}
