/* ============================================================
   10 — HOME HERO
   Dark full-bleed canvas that runs up behind the transparent nav
   and is cut off by a ~6deg diagonal at the bottom.

   The right-hand artefact is a sample savings analysis. Every figure in
   it is computed at runtime from window.Pyncht, which the partial loads
   with `defer` and reads on DOMContentLoaded; the literals in the markup
   are only the SSR fallback.
   ============================================================ */

.hero {
  --hero-nav: var(--s-11);                    /* nav height the canvas sits under */
  --hero-slant: min(10.5vw, 150px);           /* ≈ 6deg cut */
  --hero-blob: clamp(340px, 46vw, 780px);
  --hero-blur: 72px;                          /* mesh softness */
  --hero-glow-blur: 46px;                     /* glow behind the product visual */
  --hero-vis: 29rem;                          /* savings artefact measure */

  position: relative;
  isolation: isolate;
  overflow: hidden;                            /* blobs never widen the page */
  padding-block: calc(var(--hero-nav) + var(--s-11))
                 calc(var(--s-10) + var(--hero-slant));
  color: var(--text-invert-body);
}

/* ---------- canvas: base + blobs + grain, diagonally clipped ---------- */

.hero__canvas {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(168deg, var(--c-navy) 0%, var(--c-navy-deep) 62%, var(--c-navy-deep) 100%);
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--hero-slant)), 0 100%);
  overflow: hidden;
}

.hero__blob {
  position: absolute;
  width: var(--hero-blob);
  height: var(--hero-blob);
  border-radius: 50%;
  mix-blend-mode: screen;
  filter: blur(var(--hero-blur));
}

/* Every core sits inside the clip polygon: centre y < height - slant * (cx / width). */
.hero__blob--brand {
  top: -18%; left: -12%;
  background: radial-gradient(circle at 50% 50%, var(--c-brand) 0%, transparent 68%);
  opacity: .60;
  animation: hero-drift-a 31s var(--ease-inout) infinite alternate;
}
/* Core sits right of the copy column and drifts up-right, never across the
   lead — screen-blended cyan under 17-21px text would fail 4.5:1. */
.hero__blob--cyan {
  top: 4%; left: 38%;
  width: calc(var(--hero-blob) * .82); height: calc(var(--hero-blob) * .82);
  background: radial-gradient(circle at 50% 50%, var(--c-cyan) 0%, transparent 66%);
  opacity: .26;
  animation: hero-drift-b 27s var(--ease-inout) infinite alternate;
}
.hero__blob--teal {
  top: -26%; right: -14%;
  width: calc(var(--hero-blob) * 1.1); height: calc(var(--hero-blob) * 1.1);
  background: radial-gradient(circle at 50% 50%, var(--c-teal) 0%, transparent 64%);
  opacity: .28;
  animation: hero-drift-c 38s var(--ease-inout) infinite alternate;
}
/* Core pushed below/left of the clip edge — only the dim outer falloff
   reaches the trust line, so its small text stays ≥ 4.5:1 at every
   keyframe position (drift-d moves it further down-right, never up). */
.hero__blob--magenta {
  bottom: -20%; left: -10%;
  background: radial-gradient(circle at 50% 50%, var(--c-magenta) 0%, transparent 66%);
  opacity: .22;
  animation: hero-drift-d 44s var(--ease-inout) infinite alternate;
}
/* right: 28% rather than 12% — at 12% the core lands behind the opaque
   checkout card and renders nothing. Here it lights the open lower-centre. */
.hero__blob--orange {
  bottom: 6%; right: 28%;
  width: calc(var(--hero-blob) * .72); height: calc(var(--hero-blob) * .72);
  background: radial-gradient(circle at 50% 50%, var(--c-orange) 0%, transparent 68%);
  opacity: .28;
  animation: hero-drift-e 35s var(--ease-inout) infinite alternate;
}

@keyframes hero-drift-a {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(14%, 10%, 0) scale(1.16); }
}
@keyframes hero-drift-b {
  from { transform: translate3d(0, 0, 0) scale(1.06); }
  to   { transform: translate3d(10%, -9%, 0) scale(.9); }
}
@keyframes hero-drift-c {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(-11%, 18%, 0) scale(1.2); }
}
@keyframes hero-drift-d {
  from { transform: translate3d(0, 0, 0) scale(1.1); }
  to   { transform: translate3d(12%, 9%, 0) scale(.94); }
}
@keyframes hero-drift-e {
  from { transform: translate3d(0, 0, 0) scale(.96); }
  to   { transform: translate3d(-13%, -14%, 0) scale(1.14); }
}

/* Off-screen the mesh stops: no blend/blur recomposite for the other 9k px
   of page. Class is toggled by the IIFE at the end of the partial. */
.hero--still .hero__blob,
.hero--still .hero__stack { animation-play-state: paused; }

/* fine grain — kills gradient banding */
.hero__grain {
  position: absolute;
  inset: 0;
  opacity: .04;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- layout ---------- */

.hero__inner {
  display: grid;
  grid-template-columns: minmax(0, 60fr) minmax(0, 40fr);
  align-items: center;
  gap: clamp(var(--s-9), 4vw, var(--s-11));
}

/* ---------- copy ---------- */

/* No data-reveal: the headline and lead are the LCP and must paint
   without JS. Full --fs-display (44 → 84px), matching the benchmark hero;
   at 84px the copy column (~700px at 1440) sets it in three lines,
   at stacked widths it relaxes to two. text-wrap: balance from base.css
   keeps the rag even either way. */
/* No max-width: the 60fr copy column is 537px at 1024 and 709px at 1440,
   so any em cap at --fs-display would never bind. The column IS the measure. */
.hero__title {
  font-size: var(--fs-display);
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--text-invert);
}

.hero__lead {
  margin-top: var(--s-6);
  max-width: 58ch;
  font-size: var(--fs-lead);
  line-height: var(--lh-normal);
  color: var(--text-invert-body);
}

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

.hero__chev {
  margin-right: calc(var(--s-1) * -1);
  transition: transform var(--t-fast) var(--ease-out);
}
.hero__cta:hover .hero__chev { transform: translateX(var(--s-1)); }

/* Third tier is smaller, not fainter: 13px text needs the full
   --text-invert-body alpha to hold ≥ 4.5:1 over the blob falloff. */
.hero__trust {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin-top: var(--s-6);
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
  color: var(--text-invert-body);
  letter-spacing: var(--tracking-snug);
}
.hero__trust-item { display: inline-flex; align-items: center; gap: var(--s-2); }
.hero__trust-item svg { flex: none; color: var(--c-teal); }
.hero__trust-dot {
  width: var(--s-1); height: var(--s-1);
  border-radius: var(--r-pill);
  background: currentColor;
  opacity: .4;
}

/* ---------- product visual ---------- */

.hero__visual {
  justify-self: end;
  width: 100%;
  max-width: var(--hero-vis);
  /* CSS-only entrance — no JS dependency, ends visible under reduced motion */
  animation: hero-rise var(--t-slower) var(--ease-out) both;
}

@keyframes hero-rise {
  from { opacity: 0; transform: translate3d(0, 18px, 0); }
}

.hero__stack {
  position: relative;
  animation: hero-bob 8s var(--ease-inout) infinite alternate;
}

@keyframes hero-bob {
  from { transform: translate3d(0, -6px, 0); }
  to   { transform: translate3d(0, 8px, 0); }
}

.hero__glow {
  position: absolute;
  inset: 12% -8% -14%;
  border-radius: var(--r-pill);
  background: radial-gradient(ellipse at 50% 50%,
              color-mix(in srgb, var(--c-brand) 55%, transparent) 0%,
              color-mix(in srgb, var(--c-cyan) 22%, transparent) 45%,
              transparent 72%);
  filter: blur(var(--hero-glow-blur));
  z-index: -1;
}

/* card peeking behind — `right` accounts for the -3deg rotation growing
   the bounding box by height*sin(3deg)/2, so the corner lands on the edge.
   -3deg, not -6: across a ~300px card a 6deg tilt drops each row's name
   ~17px below its own amount, and this card's whole job is pairing the two. */
.hero__peek {
  position: absolute;
  /* -132 puts both rows clear of the card top once the -3deg rotation has
     moved the outer corner by width/2 × sin(3deg) ≈ 7px; the deep
     padding-bottom is what stays tucked behind, so it still reads as a card */
  top: calc((var(--s-13) + var(--s-3)) * -1);
  right: var(--s-2);
  width: 62%;
  padding: var(--s-5) var(--s-6) var(--s-10);
  border-radius: var(--r-lg);
  background: var(--c-white);
  box-shadow: var(--sh-lg);
  transform: rotate(-3deg);
  color: var(--text-body);
}
.hero__peek-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
}
/* --text-muted (#6b7c93) on white is 4.26:1 — under 4.5:1, so every
   informational line in this card sits on --text-body instead; the size
   and weight steps carry the hierarchy on their own. */
.hero__peek-label {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--text-body);
  letter-spacing: var(--tracking-snug);
}
/* count chip — square-ish so a one- or two-digit total reads as a badge */
.hero__peek-delta {
  display: inline-grid;
  place-items: center;
  min-width: var(--s-5);
  height: var(--s-5);
  padding-inline: var(--s-1);
  border-radius: var(--r-pill);
  background: var(--c-brand-tint);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  color: var(--c-brand-press);       /* 5.4:1 on the tint; --c-brand is 4.1 */
  font-variant-numeric: tabular-nums;
}

.hero__peek-list { margin-top: var(--s-3); }
.hero__peek-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
}
.hero__peek-row + .hero__peek-row {
  margin-top: var(--s-2);
  padding-top: var(--s-2);
  border-top: 1px solid var(--c-hairline-soft);
}
.hero__peek-name {
  color: var(--text-body);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hero__peek-amt {
  flex: none;
  font-weight: var(--fw-semi);
  color: var(--text-strong);
  letter-spacing: var(--tracking-snug);
  font-variant-numeric: tabular-nums;
}

/* the "/yr" is set apart by weight and colour, not size: the row is already
   at --fs-xs (13px) and .8em of that is 10.4px, below any usable floor */
.hero__per {
  margin-left: .08em;
  font-weight: var(--fw-medium);
  color: var(--text-body);
  letter-spacing: var(--tracking-normal);
}

/* analysis card */
.hero__card {
  position: relative;
  padding: var(--s-6);
  border-radius: var(--r-xl);
  background: var(--c-white);
  box-shadow: var(--sh-xl), 0 0 0 1px color-mix(in srgb, var(--c-navy) 4%, transparent);
  color: var(--text-body);
}

.hero__card-head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
}
.hero__mark {
  display: grid;
  place-items: center;
  width: var(--s-7); height: var(--s-7);
  flex: none;
  border-radius: var(--r-md);
  background: var(--grad-brand);
  color: var(--c-white);
}
.hero__merchant { display: grid; min-width: 0; }
.hero__merchant strong {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semi);
  color: var(--text-strong);
  letter-spacing: var(--tracking-snug);
  line-height: var(--lh-snug);
}
/* Wraps rather than truncates. This line is the honesty disclosure — the only
   place in the hero that states the scale the annual impact belongs to — and
   at 360px the box is ~144px against ~180px of text, so nowrap+ellipsis ate
   the denominator. Two lines is the correct answer to not enough width. */
.hero__merchant span {
  font-size: var(--fs-xs);
  color: var(--text-body);
  line-height: var(--lh-snug);
}
.hero__secure {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  margin-left: auto;
  padding: var(--s-1) var(--s-2);
  flex: none;
  border-radius: var(--r-pill);
  border: 1px solid var(--c-hairline);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--text-body);
}

.hero__rule {
  height: 1px;
  margin-block: var(--s-5);
  background: var(--c-hairline-soft);
}

/* ---------- the rate reading ---------- */

.hero__reading { margin-top: var(--s-6); }

.hero__label {
  display: block;
  margin-bottom: var(--s-2);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--text-body);
  letter-spacing: var(--tracking-snug);
}

.hero__rate {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
  font-variant-numeric: tabular-nums;
}
/* The old reading is struck, not merely faded — at --fs-h4 a 13px-equivalent
   grey still reads as a live figure, and two live rates side by side is
   ambiguous about which one is the offer. */
.hero__rate-from {
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  color: var(--text-body);
  letter-spacing: var(--tracking-tight);
  text-decoration: line-through;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, var(--c-slate-light) 60%, transparent);
}
.hero__rate-arrow { flex: none; color: var(--text-muted); }
.hero__rate-to {
  font-size: var(--fs-h3);
  font-weight: var(--fw-semi);
  color: var(--text-strong);
  letter-spacing: var(--tracking-tight);
  line-height: var(--lh-snug);
}
.hero__rate-delta {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  height: var(--s-6);
  padding-inline: var(--s-2);
  border-radius: var(--r-pill);
  background: var(--c-brand-tint);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  color: var(--c-brand-press);       /* 5.4:1 on the tint; --c-brand is 4.1 */
  letter-spacing: var(--tracking-snug);
}

/* the card's own --sh-xl carries the elevation; no coloured halo on a
   summary strip nested inside an already-elevated surface */
.hero__total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  min-height: var(--s-9);
  padding-inline: var(--s-4);
  margin-top: var(--s-6);
  border-radius: var(--r-md);
  background: var(--c-brand);
  color: var(--c-white);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semi);
  letter-spacing: var(--tracking-snug);
  box-shadow: var(--sh-xs);
}
.hero__total-label {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
}
.hero__total-label svg { flex: none; opacity: .8; }
.hero__total-amount {
  flex: none;
  font-size: var(--fs-h4);
  letter-spacing: var(--tracking-tight);
  font-variant-numeric: tabular-nums;
}

/* ---------- responsive ---------- */

/* Stacking at 1060 (not 900) also removes the band where "infrastructure"
   overset its own column. */
@media (max-width: 1060px) {
  .hero {
    --hero-blob: clamp(300px, 68vw, 560px);
    --hero-blur: 54px;
    --hero-vis: 25rem;
    padding-block: calc(var(--hero-nav) + var(--s-10))
                   calc(var(--s-10) + var(--hero-slant));
  }
  .hero__inner {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-13);
  }
  /* The peek is absolutely offset by -(s-13 + s-3) from the card top, so its
     bounding box reaches that far above .hero__visual's own box. Repay it
     exactly: the margin cancels the negative offset and the grid's s-13 gap
     is then the real, measured distance from the trust line to the peek's
     top edge — the same rhythm the rest of the stacked layout uses. */
  .hero__visual {
    justify-self: center;
    margin-top: calc(var(--s-13) + var(--s-3));
  }
}

@media (max-width: 560px) {
  .hero { --hero-vis: 21rem; }
  .hero__card { padding: var(--s-5); }
  /* 72% of 21rem less 32px of inset leaves ~210px for "Account updater" plus
     "$32,253/yr", which measures ~185px in Inter — enough headroom that a
     fallback font does not tip it into the name's ellipsis. */
  .hero__peek {
    right: var(--s-4);
    width: 72%;
    padding: var(--s-4) var(--s-4) var(--s-9);
  }
  .hero__cta { flex: 1 1 auto; }
  .hero__trust { gap: var(--s-2) var(--s-4); }
  .hero__trust-dot { display: none; }
  /* 300px of usable card width: the strip keeps the label and the figure
     on one line only once the icon and half the inset come out */
  .hero__total { padding-inline: var(--s-3); }
  .hero__total-label svg { display: none; }
}

/* ---------- reduced motion: keep the gradient, drop the movement ---------- */

@media (prefers-reduced-motion: reduce) {
  .hero__blob, .hero__stack, .hero__visual { animation: none; }
  .hero__stack { transform: none; }
  .hero__chev { transition: none; }
}
