/* ============================================================
   SNS Valley View — Hero
   Ported from design_handoff_sns_valley_view/styles.css lines 184-255,
   593-627, and the hero portion of the reduced-motion block (682-694).

   --i, each headline letter's stagger index, is emitted below as
   nth-child rules rather than the handoff's inline style="--i:N"
   attributes — this site's CSP has no 'unsafe-inline' in style-src,
   which drops inline styles outright (decided in phase 0b). The nth-child
   positions are the hero__title's DOM child order as
   web/templates/hero.templ's heroHeadline generates it: one .word span per
   word — "Where" (5 letters, then the gap), "silence" (7 letters), a <br>,
   then "speaks" (6 letters) — with the letters inside each word.
   See docs/DECISIONS.md for the full derivation.
   ============================================================ */

.hero {
  position: relative;
  height: 880px;
  margin-top: -80px; /* pulls the header over the image */
  overflow: hidden;
}

.hero__media,
.hero__scrim,
.hero__inner { position: absolute; inset: 0; }

.hero__media { overflow: hidden; }

/* The hero image is now a ResponsiveImage's <picture> wrapped in a blur
   placeholder, not a single <img> — see
   web/templates/responsive_image.templ. Both the blur and the real image
   fill this box identically so the blur-to-real paint-order reveal stays
   seamless under the same crop and pan. */
.hero__media .responsive-image,
.hero__media .responsive-image__real,
.hero__media .responsive-image__blur {
  width: 100%;
  height: 100%;
}
.hero__media .responsive-image__real,
.hero__media .responsive-image__blur {
  object-fit: cover;
  object-position: center 62%;
  filter: brightness(0.92) saturate(1.08);
  animation: heroPan 46s var(--ease) infinite alternate;
}

.hero__scrim {
  background: linear-gradient(
    to bottom,
    rgba(9, 9, 9, 0.45) 0%,
    rgba(9, 9, 9, 0.12) 42%,
    rgba(9, 9, 9, 0.70) 100%
  );
  animation: heroScrim 15s var(--ease) infinite;
}

.hero__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
  padding: 48px;
  text-align: center;
}

.hero__eyebrow {
  font-size: 10px;
  letter-spacing: 0.5em;
  text-transform: uppercase;
  /* Cream, not the gold the section overlines use: at 10px with 0.5em
     tracking over the brightest band of the hero photograph, gold read
     as washed out. Cream is the headline's own colour, so the two lines
     now read as one block and gold stays the accent on the button
     below. Client-directed — see docs/DECISIONS.md. */
  color: var(--c-cream);
  margin-bottom: 36px;
  animation: heroChrome 15s var(--ease) infinite;
}

.hero__title {
  /* Full width, not the shrink-to-fit width a flex item with
     align-items: center gets by default. Shrink-to-fit sized this h1 to
     exactly its max-content width — 232.78px of text in a 232.78px box,
     zero slack — and WebKit, measuring the run of inline-blocks a hair
     differently from the box it had just computed, wrapped the line
     anyway: iOS Safari rendered "Where si / lence / speaks" at 393px
     where Chromium rendered the authored two lines. Letting the h1 fill
     the 345px content box instead leaves the line breaker over 100px of
     room, so both engines lay the headline out as composed. The text
     stays centred on text-align: center, inherited from .hero__inner, so
     nothing about the composition moves. */
  width: 100%;
  margin: 0 0 52px;
  font-family: var(--f-display);
  font-size: clamp(48px, 7.5vw, 96px);
  font-weight: 300;
  line-height: 0.95;
  letter-spacing: -0.01em;
  color: var(--c-cream);
}

/* The hero's two actions, stacked: the primary CTA and, below it, the
   feedback link added at the client's direction. Column rather than a row
   so the primary action keeps the centre line the design composed it on at
   every width, and so the phone tier needs no separate rule — a row would
   have had to become a column here anyway, at which point the two tiers
   would disagree about which is the exception.

   The 20px gap is the 8px spacing base's nearest step that still reads as
   "one of these is the main one" — tighter and the pair reads as a single
   control, looser and the second link detaches from the hero entirely. */
.hero__actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
}

/* .btn--ghost verbatim (base.css) apart from these two: the hero's own
   tracking, matching .btn--hero's 0.25em rather than the header's 0.16em,
   and cream instead of gold. Gold on gold directly beneath the gold CTA
   made the pair read as one two-line button; cream at the body tier is
   the same "secondary, still legible over the photograph" register the
   eyebrow above already uses. The border and the hover state are
   .btn--ghost's own, untouched — the accent is still the only accent. */
.hero__feedback {
  letter-spacing: 0.25em;
  color: var(--c-cream-55);
}
.hero__feedback:hover { color: var(--c-bg); }

/* A word is one unbreakable inline-block. Its letters are inline-blocks
   too — adjacent inline-blocks are a break opportunity, which is how a
   phone came to split "silence" across two lines — so nowrap here is what
   guarantees a word stays whole at every width. The only break
   opportunities left in the headline are the two between words. */
.hero__title .word {
  display: inline-block;
  white-space: nowrap;
}

/* Each letter is its own inline-block so it can drift independently.
   --i is the letter's stagger index, counted from the RIGHT of each
   line, so the dissolve sweeps right-to-left like a breeze. */
.hero__title .word > span {
  display: inline-block;
  animation: sandDrift 15s var(--ease) infinite;
  animation-delay: calc(var(--i, 0) * 50ms);
  will-change: transform, opacity, filter;
}

/* The word gap rides inside the word it follows, not between the two, so
   a wrap can never strand it at the start of the next line. */
.hero__title .gap { width: 0.3em; animation: none; }

/* Line 1, "Where silence" — .word 1 "Where" (5 letters, then the gap as
   its 6th child, which needs no --i) and .word 2 "silence" (7 letters).
   Index counted from the right of the 13-character line, unchanged from
   the flat-span mapping this replaced. */
.hero__title .word:nth-child(1) > span:nth-child(1) { --i: 12; }
.hero__title .word:nth-child(1) > span:nth-child(2) { --i: 11; }
.hero__title .word:nth-child(1) > span:nth-child(3) { --i: 10; }
.hero__title .word:nth-child(1) > span:nth-child(4) { --i: 9; }
.hero__title .word:nth-child(1) > span:nth-child(5) { --i: 8; }
.hero__title .word:nth-child(2) > span:nth-child(1) { --i: 6; }
.hero__title .word:nth-child(2) > span:nth-child(2) { --i: 5; }
.hero__title .word:nth-child(2) > span:nth-child(3) { --i: 4; }
.hero__title .word:nth-child(2) > span:nth-child(4) { --i: 3; }
.hero__title .word:nth-child(2) > span:nth-child(5) { --i: 2; }
.hero__title .word:nth-child(2) > span:nth-child(6) { --i: 1; }
.hero__title .word:nth-child(2) > span:nth-child(7) { --i: 0; }

/* Child 3 is the <br>. Line 2, "speaks" — .word 4, 6 letters, no gap. */
.hero__title .word:nth-child(4) > span:nth-child(1) { --i: 5; }
.hero__title .word:nth-child(4) > span:nth-child(2) { --i: 4; }
.hero__title .word:nth-child(4) > span:nth-child(3) { --i: 3; }
.hero__title .word:nth-child(4) > span:nth-child(4) { --i: 2; }
.hero__title .word:nth-child(4) > span:nth-child(5) { --i: 1; }
.hero__title .word:nth-child(4) > span:nth-child(6) { --i: 0; }

/* ============================================================
   Keyframes
   ============================================================ */

/* Hero headline: letters blur and blow leftward, hold clear so the
   photograph is briefly unobstructed, then blow back in from the
   right — one continuous leftward breeze. The 52% jump from -44px to
   +52px (opacity still 0) is what makes the return read as "from the
   right"; removing it inverts the motion into a left-to-right wipe.
   The 52%-60% static hold (fully gone, not moving) was shortened from
   its original 52%-66% at the client's request, 2026-08-12 — see
   docs/DECISIONS.md — to trim how long the letters sit disappeared.
   The fade-out (18%-40%) and fade-in (60%-80%, still a 20%-wide window,
   same as the original 66%-86%) are untouched; the saved 6% rolled into
   the closing hold-clear instead of shortening the 15s cycle. */
@keyframes sandDrift {
  0%, 18%   { opacity: 1; filter: blur(0);    transform: translate(0, 0); }
  40%       { opacity: 0; filter: blur(14px); transform: translate(-44px, -16px); }
  52%       { opacity: 0; filter: blur(14px); transform: translate(52px, 12px); }
  60%       { opacity: 0; filter: blur(14px); transform: translate(52px, 12px); }
  80%, 100% { opacity: 1; filter: blur(0);    transform: translate(0, 0); }
}

/* Eyebrow fades with the headline so the clear frame is truly clear */
@keyframes heroChrome {
  0%, 18%   { opacity: 1; }
  38%       { opacity: 0; }
  62%       { opacity: 0; }
  82%, 100% { opacity: 1; }
}

/* Scrim lifts during the clear frame so the photo reads at full strength */
@keyframes heroScrim {
  0%, 18%   { opacity: 1; }
  40%       { opacity: 0.3; }
  60%       { opacity: 0.3; }
  80%, 100% { opacity: 1; }
}

@keyframes heroPan {
  0%   { transform: scale(1.04); }
  100% { transform: scale(1.11); }
}

/* ============================================================
   Responsive
   Shares the 1024px/680px edges the rest of the page uses (see
   base.css) — the hero has no image-column concern (its sizes string is
   already viewport-relative, "100vw" below the 1280px canvas, valid at
   any width), so this is free to choose its own scale independent of
   the grid-affecting breakpoints. Tracking values (0.5em eyebrow, -0.01em
   h1) are untouched at every size — only the size clamp's floor and the
   surrounding padding change.
   ============================================================ */
@media (max-width: 1024px) {
  .hero { height: 700px; }
}

@media (max-width: 680px) {
  .hero { height: 560px; }
  .hero__inner { padding: 32px 24px; }
  .hero__eyebrow { margin-bottom: 24px; }
  .hero__title {
    /* 96px (the 1280px-canvas value) badly overflows a 342px text
       column (390px viewport minus 24px padding each side); 48px was
       measured against a real render as the largest size "Where
       silence" still fits on one line at 390px without wrapping mid-word
       — see docs/DECISIONS.md for the render this was checked against. */
    font-size: clamp(30px, 11vw, 48px);
    margin-bottom: 32px;
  }
}

/* Respect the OS reduced-motion setting — the dissolve is decorative */
@media (prefers-reduced-motion: reduce) {
  .hero__media .responsive-image__real,
  .hero__media .responsive-image__blur,
  .hero__scrim,
  .hero__eyebrow,
  .hero__title span {
    animation: none !important;
  }
}
