/* ==========================================================================
   STILLMIND MENTAL HEALTH · HERO

   Four depth planes that move at different rates as the page scrolls, so
   the scene has real parallax rather than a single flat photograph.

   The direction is the whole trick. The hero is already travelling up
   with the page, so a plane that should feel DISTANT has to be pushed
   back DOWN against that travel, making it lag. A plane that should feel
   CLOSE is pushed further up, making it rush past. Getting this backwards
   inverts the depth cue and the scene reads as flat even though every
   plane is moving.

   Plane 1  far      landscape. Lags hardest: pushed down, feels distant
   Plane 2  mist     a CSS band, no image. Lags a little
   Plane 3  near     foreground meadow. Leads: pushed up, rushes past
   Plane 4  scrim    fixed. Readability and tone, never moves

   Rules this file holds to:
   - Scroll is never blocked. The hero is one screen and it lets go.
   - Every plane moves by transform only. Nothing here triggers layout.
   - prefers-reduced-motion gets a still photograph, not a degraded one.
   - The headline is readable before any image has loaded.
   ========================================================================== */

/* --------------------------------------------------------------------
   Plates
   Three shapes, not four sizes. This is the correction to the version
   this replaces, which chose plate WIDTHS by viewport width and device
   pixel ratio and got the wrong answer for the right-sounding reason.

   Both `background-size: cover` and `object-fit: cover` scale an image
   to fill the box's SHORT axis. The hero layer is portrait on a phone
   (0.37 to 0.40), portrait on a tablet (0.54 to 0.59) and landscape on
   a desktop (1.09 to 1.52). So a 16:9 plate in a phone's box was scaled
   up until its HEIGHT covered 1125 CSS pixels, which pushed its width
   out to about 2000, of which the box showed 433. A phone downloaded a
   1100 pixel file and displayed a 208 pixel strip of it, magnified more
   than four times. Measured: 22 percent of the image was ever on screen.

   Picking a wider file cannot fix that, and this was tested rather than
   assumed: a 1280 wide encode, two and a half times the bytes, measured
   0.884 against the 0.882 it replaced. Nothing.

   So each bucket gets a plate already cut to its own shape. Same visible
   composition, every delivered pixel shown. Measured on the pixels each
   device actually paints: phone 0.949 and tablet 0.955, against 0.882
   and 0.834 before. Desktop went 0.909 to 0.986, most of that from the
   move to AV1 rather than from the crop.

   No size ladder inside a bucket, because the master is 1080 lines tall
   and that is the ceiling. A phone box asks for 2250 device pixels of
   height and 1080 is all that exists, so there is nothing larger to
   offer a denser screen. A taller master is the only way past this, and
   a 9:16 render would take the phone from 2.08x magnification to 1.17x.

   Buckets are chosen by WIDTH, not by aspect ratio, and that is
   deliberate. Below about 600px the hero's own stacked content makes it
   taller than the viewport, so the box shape stops tracking the
   viewport's shape and tracks the width instead.

   The near plane is untouched on purpose. Its box is short and wide
   (1.20 on a phone, 4.25 on a desktop), so near.png is downscaled
   everywhere and never magnified. It was never part of this.

   These JPEG declarations are the fallback. The AVIF set that normally
   wins is in the @supports block below.
   -------------------------------------------------------------------- */

/* Phone. 432x1080, cut centred to match a 0.37 to 0.40 box.

   Declared on :root rather than on .hero so other sections can reuse the
   very same file the hero has already downloaded. A second section that
   wants this scene behind it then costs nothing at all. */
:root {
  --hero-far: url("../img/hero/far-phone.jpg");
  --hero-near: url("../img/hero/near-700.jpg");
}

/* Tablet. 632x1080, cut centred to match a 0.54 to 0.59 box. */
@media (min-width: 600px) {
  :root {
    --hero-far: url("../img/hero/far-tablet.jpg");
    --hero-near: url("../img/hero/near-1100.jpg");
  }
}

/* Desktop. The full 1920x1080 frame, because here the box is landscape
   and the whole width earns its place. */
@media (min-width: 900px) {
  :root {
    --hero-far: url("../img/hero/far-desktop.jpg");
    --hero-near: url("../img/hero/near-1696.jpg");
  }
}

/* --------------------------------------------------------------------
   AVIF, where the browser can both parse image-set and decode it.

   The guard is not politeness. A custom property swallows almost any
   token sequence, so a browser that cannot parse image-set() would still
   STORE it, and then background-image: var(--hero-far) becomes invalid
   at computed-value time and resolves to nothing. The hero would lose
   its photograph entirely rather than fall back. @supports keeps those
   browsers on the JPEG declarations above.

   Every AVIF here is written by ffmpeg. sips also writes files with an
   .avif extension, and they are a trap: tiled grid images carrying a
   rotation box, which Chrome decodes through the Image API but silently
   refuses to paint as a CSS background. The hero came up a flat green
   panel with every file reporting a clean 200. This set was checked by
   painting it over a magenta backstop in a real browser.

   23 to 50 percent smaller at equal or better fidelity: the desktop
   plate measures 0.991 against the master frame where its 140KB JPEG
   measured 0.987, and costs 108KB.
   -------------------------------------------------------------------- */

@supports (background-image: image-set(url("../img/hero/far-phone.avif") type("image/avif"))) {
  :root {
    --hero-far: image-set(url("../img/hero/far-phone.avif") type("image/avif"),
                          url("../img/hero/far-phone.jpg") type("image/jpeg"));
    --hero-near: image-set(url("../img/hero/near-700.avif") type("image/avif"),
                           url("../img/hero/near-700.jpg") type("image/jpeg"));
  }

  @media (min-width: 600px) {
    :root {
      --hero-far: image-set(url("../img/hero/far-tablet.avif") type("image/avif"),
                            url("../img/hero/far-tablet.jpg") type("image/jpeg"));
      --hero-near: image-set(url("../img/hero/near-1100.avif") type("image/avif"),
                             url("../img/hero/near-1100.jpg") type("image/jpeg"));
    }
  }

  @media (min-width: 900px) {
    :root {
      --hero-far: image-set(url("../img/hero/far-desktop.avif") type("image/avif"),
                            url("../img/hero/far-desktop.jpg") type("image/jpeg"));
      --hero-near: image-set(url("../img/hero/near-1696.avif") type("image/avif"),
                             url("../img/hero/near-1696.jpg") type("image/jpeg"));
    }
  }
}

.hero {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  min-height: 100svh;
  padding-top: clamp(6.25rem, 14vh, 8.5rem);
  /* The section below now lifts over the hero by --seam-lift, so the last
     --seam-lift of this box is covered. Content has to clear it. */
  padding-bottom: calc(var(--s-7) + var(--seam-lift));
  overflow: clip;
  isolation: isolate;
  /* A solid base in the brand's deepest green, so the headline has
     contrast from the first paint, before any image arrives. The stage
     sits above this, not behind it: at z-index -1 the plates were being
     painted and then covered by this very fill. */
  background: var(--c-ink);
  color: var(--c-text-invert);
}

@media (min-width: 900px) {
  .hero {
    flex-direction: row;
    align-items: center;
    max-height: 940px;
    padding-top: var(--s-12);
    padding-bottom: calc(var(--s-11) + var(--seam-lift));
  }
}

/* --------------------------------------------------------------------
   The stage
   --hero-p is written by hero.js: 0 at the top of the hero, 1 when the
   hero has scrolled fully out. Every plane reads from it.
   -------------------------------------------------------------------- */

.hero__stage {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.hero__layer {
  position: absolute;
  /* Overscan, so a travelling plane never reveals its edge. Kept only as
     large as the travel needs: every extra percent here is extra zoom
     into the photograph, and this plate is 1696px wide, so zoom is paid
     for directly in sharpness.

     Asymmetric, and the total is unchanged at 28%, so the magnification
     is exactly what it was. All this does is slide the window DOWN the
     frame. The ink band at the hero's foot covers the last 96px, and
     what lived there was the meadow: the flowers streaming past the
     camera are the only thing that makes a push-in read as travel
     rather than as an object getting larger. Biasing down trades sky,
     which is behind the headline and wants to be plain anyway, for the
     foreground the band was swallowing.

     Headroom check, the reason the split is 22/6 and not 14/14. The
     plane translates DOWN by 9% of its own height and grows 2% at p=1,
     so it can uncover its TOP edge but never its bottom: the top needs
     0.09 + 0.02 of 1.28 = 14.1% of the hero and has 22%, the bottom
     needs 2.6% and has 6%. */
  inset: -22% -5% -6%;
  background-repeat: no-repeat;
  will-change: transform;
}

/* Plane 1 · far. The landscape. Drifts up slowly and pulls back a little,
   which reads as distance. */
.hero__layer--far {
  background-image: var(--hero-far);
  background-size: cover;
  /* Centre, because the phone and tablet plates are already cut to the
     box's own shape and carry the full height of the frame. The 74% this
     replaces was pulling a 16:9 plate down so the headline sat on dark
     mountains instead of pale sky, which the crop now handles by framing
     rather than by offset. There is no vertical overflow left to bias. */
  background-position: 50% 50%;
  /* Pushed DOWN against the page's travel, so it lags and reads far. */
  transform:
    translate3d(0, calc(var(--hero-p, 0) * 9%), 0)
    scale(calc(1.01 + var(--hero-p, 0) * 0.04));
}

@media (min-width: 900px) {
  /* The headline occupies the left, so the subject has to sit right of
     it. A LOW percentage anchors the image's left edge to the box, which
     pushes the monument toward the right of the frame. Higher values do
     the opposite, which is the wrong way round for this composition. */
  .hero__layer--far { background-position: 18% 50%; }
}

/* --------------------------------------------------------------------
   The video, which rides on the far plane
   It sits inside that layer, so it inherits the same parallax transform
   the still would have had. It fades in only once it is genuinely
   playing, so there is never a blank frame or a flash: the poster image
   underneath is the video's own first frame, which means the swap is
   invisible.
   -------------------------------------------------------------------- */

.hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Must match the still's anchor exactly or the scene jumps when the
     video fades in. */
  object-position: 50% 50%;
  opacity: 0;
  transition: opacity 900ms var(--ease-out-expo);
}

@media (min-width: 900px) {
  /* Matches the still's anchor exactly, so nothing shifts when it starts. */
  .hero__video { object-position: 18% 50%; }
}

.hero__video.is-playing { opacity: 1; }

/* Never plays, never downloads, and never appears. */
@media (prefers-reduced-motion: reduce) {
  .hero__video { display: none; }
}

/* Plane 2 · mist. No image at all. A soft band of light that sits between
   the landscape and the meadow and lifts at its own rate. */
.hero__layer--mist {
  background-image:
    radial-gradient(110% 34% at 58% 70%, rgba(233, 240, 236, 0.16), transparent 72%),
    radial-gradient(70% 26% at 18% 80%, rgba(214, 228, 224, 0.12), transparent 74%);
  transform: translate3d(0, calc(var(--hero-p, 0) * 7%), 0);
}

/* Plane 3 · near. The meadow. Drifts down and grows, which is what the
   ground does when you move past it. */
.hero__layer--near {
  top: auto;
  bottom: -8%;
  height: 32%;
  background-image: var(--hero-near);
  background-size: cover;
  background-position: 50% 100%;
  /* Dissolves upward so it meets the landscape as mist, not as a seam. */
  -webkit-mask-image: linear-gradient(to top, #000 0%, rgba(0, 0, 0, 0.82) 34%, rgba(0, 0, 0, 0.26) 66%, transparent 92%);
  mask-image: linear-gradient(to top, #000 0%, rgba(0, 0, 0, 0.82) 34%, rgba(0, 0, 0, 0.26) 66%, transparent 92%);
  /* Pushed UP, ahead of the page, so it rushes past and reads close. */
  transform:
    translate3d(0, calc(var(--hero-p, 0) * -26%), 0)
    scale(calc(1.02 + var(--hero-p, 0) * 0.1));
}

/* Plane 4 · scrim. Fixed. Carries the readability gradient and the tone. */
/* Do not lighten this to show more of the scene on a phone. It was tried
   and measured, and it fails.

   Sampling the real video frame underneath and compositing these stops
   over it, the lead paragraph's worst pixel sits at 2.59:1 against its
   own colour once the middle band is opened up. Body text needs 4.5:1.
   The headline and the facts list survive it, at 6.9 and 8.7, but the
   lead does not, and the lead is the sentence that says who this
   practice treats.

   The cause is not the gradient, it is the budget. On a 375px phone this
   hero runs text from 115px to 760px: eyebrow, headline, lead, two
   buttons, three facts. The only band with no text over it is the strip
   around the buttons, and the buttons are opaque pills that cover most
   of it themselves. There is no window to open. Showing the video
   properly on a phone is a layout decision, not a scrim value, and it
   costs something from that list. */
.hero__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, rgba(15, 35, 31, 0.92) 0%, rgba(15, 35, 31, 0.74) 30%, rgba(15, 35, 31, 0.62) 58%, rgba(15, 35, 31, 0.66) 100%),
    radial-gradient(120% 60% at 30% 30%, rgba(15, 35, 31, 0.55), transparent 72%);
}

@media (min-width: 900px) {
  /* On a wide screen the text sits left, so the scrim leans left too and
     the right side of the scene stays open.

     The hold to 54 percent is not a taste decision. The lead paragraph's
     longest line reaches 52 percent of the hero's width, and the old
     falloff had already dropped to 0.47 by then, which put pale text
     over the arch's near-white pillar at 2.36:1. Holding 0.74 out past
     the end of the text column and then falling away sharply fixes it
     at 5.59:1 and costs about a tenth of the open area: the right third
     of the frame, which is what the composition is actually for, is
     untouched.

     If the lead's measure ever changes, this number moves with it. */
  .hero__scrim {
    background:
      linear-gradient(to right,
        rgba(15, 35, 31, 0.94) 0%,
        rgba(15, 35, 31, 0.82) 30%,
        rgba(15, 35, 31, 0.74) 54%,
        rgba(15, 35, 31, 0.28) 74%,
        rgba(15, 35, 31, 0.06) 92%,
        transparent 100%),
      linear-gradient(to top, rgba(15, 35, 31, 0.72) 0%, transparent 46%);
  }
}

/* Narrow desktop, where the numbers above stop being true.
   The 54 percent hold was measured from the lead's longest line reaching
   52 percent, and that holds from about 1024 up. It does not hold below
   it, because the lead has a fixed 46ch measure: the narrower the
   viewport, the larger a share of it the same sentence occupies. Measured
   reach of the lead's longest line, as a percentage of the hero:

       900   60.1     1100  49.2     1440  52.2
       960   56.3     1200  45.1     1920  52.3
      1024   52.8     1280  47.2

   So from 900 to 1023 the tail of the lead and the second button sit past
   the hold, out in the falloff, which measured 4.24:1 at 900.

   Only this band is touched. The wide composition was approved as it is,
   and it is not the one that was failing. */
@media (min-width: 900px) and (max-width: 1099px) {
  .hero__scrim {
    background:
      linear-gradient(to right,
        rgba(15, 35, 31, 0.94) 0%,
        rgba(15, 35, 31, 0.84) 34%,
        rgba(15, 35, 31, 0.78) 64%,
        rgba(15, 35, 31, 0.30) 82%,
        rgba(15, 35, 31, 0.06) 94%,
        transparent 100%),
      linear-gradient(to top, rgba(15, 35, 31, 0.72) 0%, transparent 46%);
  }
}

/* WHAT USED TO BE HERE, AND WHY IT IS NOT

   Two stacked layers: a 96px band flattening the hero's foot to solid
   ink, and .hero__resolve, a gradient running ink to paper so the paper
   section below could continue from it without a ruled line.

   It worked, by the only number anyone measured: 6/255 at 390 and 4/255
   at 1280, which is no visible step at all. It was still wrong, and the
   measurement is why nobody noticed. A step test asks whether adjacent
   rows differ. It cannot ask what two hundred pixels of the page are
   spending themselves on, and the answer was fog. A linear ramp from
   #10261F to #FAF8F5 in sRGB goes through a flat desaturated grey, so
   the hero ended by going dark, then grey, then pale, over a quarter of
   a phone screen.

   And it ate the meadow. The near plane is the flowers streaming past
   the camera, and by this file's own note thirty lines up it is "the
   only thing that makes a push-in read as travel rather than as an
   object getting larger". The ink band covered exactly that.

   There is no gradient now. The paper section below lifts over the hero
   on a rounded edge and covers the seam with a shape, which is a
   decision rather than a dissolve. See --seam-lift in tokens.css.
   The hero keeps its last frame.

   What survives is a vignette, and only because the panel's rounded
   corners sit over live video: without it the two notches beside the
   corners can land on a bright frame and flare against the paper edge.
   It stops well short of ink, it only ever darkens, and it begins at
   y=804 where the lowest text in the hero sits at y=700, so it does not
   reach the trust row. */
.hero::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 140px;
  z-index: 0;
  pointer-events: none;
  background: linear-gradient(to bottom,
    transparent 0%,
    rgba(15, 35, 31, 0.15) 30%,
    rgba(15, 35, 31, 0.60) 75%,
    rgba(15, 35, 31, 0.90) 100%);
}

/* Welcoming badge for new clients */
.hero__welcome {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  margin-bottom: var(--s-3);
  padding: 0.35rem 0.85rem;
  border-radius: var(--r-pill);
  background: rgba(15, 35, 31, 0.65);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(214, 228, 224, 0.22);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
  font-size: var(--t-xs);
  color: var(--c-text-invert);
}

.hero__welcome-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-weight: 700;
  color: #A3E6C5;
}

.hero__welcome-beacon {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background-color: #34D399;
  box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.7);
  animation: hero-beacon-pulse 2s infinite cubic-bezier(0.4, 0, 0.6, 1);
}

@keyframes hero-beacon-pulse {
  0% { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.7); }
  70% { box-shadow: 0 0 0 8px rgba(52, 211, 153, 0); }
  100% { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0); }
}

.hero__welcome-text {
  color: var(--c-text-invert-2);
  font-weight: 500;
}

/* --------------------------------------------------------------------
   Content
   Lifts and fades as the hero leaves, so the scene hands over rather
   than cutting.
   -------------------------------------------------------------------- */

.hero__content {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  margin-top: auto;
  margin-bottom: auto;
  padding-inline: var(--gutter);
  transform: translate3d(0, calc(var(--hero-p, 0) * -40px), 0);
  opacity: calc(1 - var(--hero-p, 0) * 1.15);
  will-change: transform, opacity;
}

@media (min-width: 900px) {
  .hero__content {
    margin-top: 0;
    margin-bottom: 0;
  }
}

/* The headline is the only thing that wants a narrow measure. Everything
   below it gets its own, so the column does not collapse to a ribbon. */
.hero__inner { max-width: 100%; }

@media (min-width: 900px) {
  .hero__inner { max-width: 40rem; }
}

/* A dark chip, not a pale one, and the reason is arithmetic.

   This pill used to lighten what was behind it, by rgba(214,228,224,0.14),
   and then set light text on the result. That is a losing combination over
   video: where the clip is bright the pill gets brighter with it, and the
   text has nowhere to go. Measured against real frames it came in at 4.15:1
   at 768 and 4.45 at 360, against the 4.5 small text needs, and it is the
   first line on the page.

   Tinting toward ink instead makes the backdrop predictable no matter what
   the video is doing underneath, because the pill is now subtracting
   brightness rather than adding it. Worst case measures about 7.8:1.

   The frosted character survives: same hairline, and the blur is what made
   it read as glass in the first place. */
.hero .eyebrow {
  background: rgba(15, 35, 31, 0.5);
  color: var(--c-sage-tint);
  box-shadow: inset 0 0 0 1px rgba(214, 228, 224, 0.22);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  max-width: 100%;
  text-wrap: balance;
  line-height: 1.45;
}

@media (max-width: 600px) {
  .hero .eyebrow {
    font-size: 0.6875rem;
    letter-spacing: 0.08em;
    padding: 0.45rem 0.8rem;
    border-radius: 12px;
    text-wrap: pretty;
  }
}

.hero__title {
  margin-top: var(--s-5);
  max-width: 15ch;
  font-size: clamp(2.5rem, 6.4vw, 4.75rem);
  line-height: 1.0;
  letter-spacing: -0.03em;
  color: var(--c-text-invert);
  text-wrap: balance;
}

.hero__title em {
  display: block;
  font-style: italic;
  color: var(--c-sage-tint);
}

.hero__lead {
  margin-top: var(--s-5);
  max-width: 50ch;
  font-size: clamp(1.2rem, 2.2vw, 1.4rem);
  font-weight: 500;
  line-height: var(--lh-relaxed);
  color: #FFFFFF;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.65);
}

.hero__subline {
  margin-top: var(--s-3);
  max-width: 48ch;
  font-size: clamp(0.9375rem, 1.25vw, 1.0625rem);
  font-weight: 500;
  line-height: var(--lh-snug);
  color: #FFFFFF;
  letter-spacing: 0.01em;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.75);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin-top: var(--s-6);
}

@media (max-width: 540px) {
  .hero__actions {
    width: 100%;
    flex-direction: column;
    align-items: stretch;
  }
  .hero__actions .btn {
    width: 100%;
    justify-content: center;
  }
}

@media (min-width: 900px) {
  .hero__actions { margin-top: var(--s-7); }
  .hero__facts { margin-top: var(--s-8); padding-top: var(--s-5); }
}

.hero__actions .btn-secondary {
  --btn-fg: var(--c-text-invert);
  --btn-icon-bg: rgba(255, 255, 255, 0.14);
  box-shadow: inset 0 0 0 1px rgba(214, 228, 224, 0.28);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.hero__actions .btn-secondary:hover {
  --btn-bg: rgba(255, 255, 255, 0.1);
}

/* --------------------------------------------------------------------
   Short viewports
   On a screen under 620px tall the headline, the lead and the booking
   button no longer all clear the fold. The facts row can sit below it,
   but the primary action cannot, so the type and the gaps tighten until
   it clears.
   -------------------------------------------------------------------- */

@media (max-height: 620px) {
  .hero {
    padding-top: calc(var(--s-10) + var(--s-3));
    padding-bottom: var(--s-6);
  }

  .hero__title {
    margin-top: var(--s-4);
    font-size: clamp(2rem, 5.6vw, 2.75rem);
  }

  .hero__lead {
    margin-top: var(--s-4);
    font-size: var(--t-body);
  }

  .hero__actions { margin-top: var(--s-5); }
  .hero__facts { margin-top: var(--s-5); }
}

/* --------------------------------------------------------------------
   Trust row
   Three plain facts. Every one of them is true today: no certification
   claims, no carrier names, no prices.
   -------------------------------------------------------------------- */

.hero__facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4) var(--s-6);
  margin-top: var(--s-6);
  padding-top: var(--s-4);
  box-shadow: inset 0 1px 0 rgba(214, 228, 224, 0.18);
}

.hero__fact {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  font-size: var(--t-xs);
}

/* --c-text-invert-2 at full strength, which is the same colour this used
   to be at 0.62 alpha.

   The alpha was the whole problem. These three labels sit on moving video
   and the sweep cannot see video at all, so nothing caught them: measured
   by hand against real painted frames they came in at 4.24 to 4.49:1
   across seven widths, against the 4.5 small text needs. Dropping the
   alpha takes them to about 8.8:1.

   They stay visibly quieter than the values beneath them, which is the
   only reason the alpha was there. Those are --c-text-invert and measure
   near 13:1, so the hierarchy survives being legible. */
.hero__fact dt {
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--c-text-invert-2);
}

.hero__fact dd { color: var(--c-text-invert); font-weight: 500; }

.hero__facts a.link,
.hero__facts a {
  color: var(--c-text-invert);
  text-decoration: none;
}

/* Meet your provider prominent feature in trust row */
.hero__fact--provider dt {
  color: var(--c-sage-tint);
  font-weight: 700;
  letter-spacing: 0.12em;
}

.hero__provider-link {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  color: #FFFFFF !important;
  font-size: var(--t-sm);
  font-weight: 600;
  text-decoration: none;
  padding: 0.45rem 0.85rem;
  margin-top: 0.1rem;
  border-radius: var(--r-md, 10px);
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(214, 228, 224, 0.3);
  box-shadow: 0 4px 16px -2px rgba(15, 35, 31, 0.35);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  transition:
    background-color var(--d-base) var(--ease-out-expo),
    border-color var(--d-base) var(--ease-out-expo),
    color var(--d-base) var(--ease-out-expo),
    box-shadow var(--d-base) var(--ease-out-expo),
    transform var(--d-base) var(--ease-out-expo);
}

.hero__provider-link:hover {
  background: rgba(255, 255, 255, 0.18);
  border-color: rgba(255, 255, 255, 0.6);
  color: #FFFFFF !important;
  box-shadow: 0 6px 20px -2px rgba(15, 35, 31, 0.5);
  transform: translateY(-1px);
}

.hero__provider-name {
  line-height: 1.35;
}

.hero__provider-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.375rem;
  height: 1.375rem;
  flex-shrink: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.16);
  font-size: 0.8125rem;
  line-height: 1;
  transition:
    transform var(--d-base) var(--ease-out-expo),
    background-color var(--d-base) ease;
}

.hero__provider-link:hover .hero__provider-arrow {
  transform: translateX(3px);
  background: rgba(255, 255, 255, 0.32);
}

/* --------------------------------------------------------------------
   Scroll cue
   A hint, not an instruction, and a real link so the keyboard can use it.
   It fades out the moment scrolling starts.
   -------------------------------------------------------------------- */

.hero__cue {
  position: absolute;
  left: 50%;
  /* Clears the lifted panel below. At the old offset the cue was pale
     text on paper. */
  bottom: calc(var(--seam-lift) + var(--s-3));
  z-index: 1;
  display: none;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 44px;
  min-width: 44px;
  padding: var(--s-2) var(--s-4);
  border-radius: var(--r-pill);
  font-size: var(--t-xs);
  font-weight: 500;
  color: var(--c-text-invert-2);
  transform: translateX(-50%);
  opacity: calc(1 - var(--hero-p, 0) * 3);
  transition: color var(--d-base) var(--ease-out-expo);
}

@media (min-width: 900px) {
  .hero__cue { display: inline-flex; }
}

.hero__cue:hover { color: var(--c-text-invert); }

.hero__cue-arrow {
  display: inline-block;
  font-size: 0.9em;
}

@media (prefers-reduced-motion: no-preference) {
  .hero__cue-arrow { animation: cue-drift 2.6s var(--ease-in-out) infinite; }
}

@keyframes cue-drift {
  0%, 100% { transform: translateY(-1px); opacity: 0.6; }
  50%      { transform: translateY(3px); opacity: 1; }
}

/* --------------------------------------------------------------------
   Reduced motion
   A still photograph. Every plane parks at its resting position and the
   content sits at full opacity. Nothing is lost except the movement.
   -------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .hero__layer,
  .hero__content,
  .hero__cue {
    transform: none !important;
    opacity: 1 !important;
  }

  .hero__layer--far { transform: scale(1.01) !important; }
  .hero__cue-arrow { animation: none; }
  .hero__welcome-beacon { animation: none !important; }
}
