/* ============================================================
   Ink & Intuition — hero (site/sections/01-hero.html)
   WebGL ink field + editorial headline + mood check-in + portrait.
   Source of truth: design_handoff_hero/README.md ("Hero 4a").

   Local design tokens: values below have no equivalent in the
   shared tokens.css (bespoke aura/bubble/mood hex pulled straight
   from the handoff spec), so they're named here rather than left
   as loose magic hex in the rules further down.
   ============================================================ */

.hero {
  --hero-aura-pink: #e79ab0;
  --hero-aura-pink-fade: rgba(210, 120, 160, 0);
  --hero-aura-amber: #f4b062;
  --hero-aura-amber-fade: rgba(239, 138, 95, 0);

  --hero-mood-anxious: #e0507f;
  --hero-mood-tender: #d97a9a;
  --hero-mood-numb: #9a8f88;

  /* WCAG AA override: the handoff spec's literal alpha (.5 / --ink-faint's .42)
     computes to ~3.0:1 / ~2.4:1 against --page-gradient's cream stops, failing
     the CONTRACT's 4.5:1 minimum for this 11px text. .68 clears 4.5:1 with
     margin against every gradient stop (incl. the darkest, #eee1cd, where the
     credential strip sits) while keeping the muted look. Used for both
     .hero-mood-label and .hero-credential-strip (not tokens.css --ink-faint,
     which other sections still rely on at its original value). */
  --hero-ink-faint: rgba(42, 34, 48, 0.68);
  /* Deepened from the prototype's #7a7080. That value measured 3.1:1 to 4.3:1
     against the live backdrop, because the pill's responsive offset lands this
     second line over the brightest, warmest patch of the painted top. Small
     text needs 4.5:1. */
  --hero-pill-cred-color: #443c4c;
  --hero-shadow-chip-active: 0 12px 24px -12px rgba(42, 34, 48, 0.55);

  position: relative;
  overflow: hidden;
  min-height: 100vh;
  min-height: max(720px, 100dvh);
  display: flex;
  flex-direction: column;
  justify-content: center;
  background: var(--page-gradient);
  padding-block: clamp(110px, 17vh, 172px) clamp(92px, 13vh, 130px);
}

/* Approved Hero transition: the paper narrative rises over this sticky
   underlay. Short windows, touch and reduced-motion retain normal flow. */
@media (min-width: 1081px) and (min-height: 730px) and (prefers-reduced-motion: no-preference) {
  .hero {
    position: sticky;
    top: 0;
    z-index: 1;
  }
}

/* ---------- WebGL ink canvas ---------- */

.hero-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}

/* .hero-filters was removed 2026-07-29. It hid an SVG <defs> block of
   turbulence filters that went with the old .hero-bubble--a/--b elements;
   those elements were replaced by the surface-tension blob canvases and the
   markup has carried no .hero-filters node since. Verified with
   tools/probes/deadSelectors.js: zero matches at 1440 and 390. */

.hero-grain {
  position: absolute;
  inset: 0;
  z-index: 30;
  pointer-events: none;
  background: url('../../assets/img/grain.png') center / 180px repeat;
  mix-blend-mode: soft-light;
  /* Was a hardcoded 0.4, which was the token's value when this was written.
     On 2026-07-27 --grain-opacity went to 0.30 to match the Cell Drift lab
     (its .grain is `180px repeat`, soft-light, opacity .30) after Daniel
     reported "there is a white softness going over everything including the
     text". This copy did not follow, so hero and About were left grainier
     than the four sections that read the token, which reads as the hero
     being a different finish from the rest of the page.

     This is the only edit to the locked hero this round and it is a
     consistency fix, not a redesign: grain is explicitly the SHARED sitewide
     finish, the local value was a stale duplicate of the token rather than a
     hero-specific decision, and --grain-size/-blend were already shared in
     spirit here. Nothing else about the hero moved. */
  opacity: var(--grain-opacity);
}

/* ---------- Content stage ----------
   Hero 4a uses a deliberately roomier 1,316px composition band than the
   rest of the page: its copy begins 96px into the 1,400px reference canvas.
   This preserves the generous left/right weighting from the approved handoff
   without changing the shared site container used by every other section. */
.hero-stage {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: calc(var(--container) + 76px);
  margin-inline: auto;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* ---------- Text column ---------- */

.hero-row {
  position: relative;
  z-index: 15;
  width: 100%;
  max-width: none;   /* fill the stage; the .container gutter still insets it */
  margin-inline: 0;  /* left-anchor within the stage (no shrink-to-fit centering) */
}

.hero-content { max-width: min(560px, 44vw); }

.hero-eyebrow { margin: 0; }

.hero-heading {
  margin: 20px 0 0;
  line-height: 1.04;
}
.hero-heading-line { display: block; }
.hero-heading-accent { font-style: italic; }

.hero-sub {
  margin-top: 22px;
  max-width: 452px;
  /* font-family/size/line-height/color inherit body defaults (Hanken 18px/1.55, ink-600) */
}

.hero-ctas {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 28px;
}

.hero-cta-secondary { gap: 9px; }
.hero-cta-arrow {
  display: inline-block;
  font-size: 17px;
  transition: transform var(--dur-quick) var(--ease-brand);
}
.hero-cta-secondary:hover .hero-cta-arrow { transform: translateX(5px); }

/* KNOWN AND ACCEPTED, NOT AN OVERSIGHT. Do not change this without asking
   Daniel first.

   White text on the approved --grad-cta arc (tools/hero-cta-contrast.mjs)
   measures roughly 1.8 to 1.9:1 at the amber stop, short of the 4.5:1 this
   15-16px/600-weight button text needs (too small and not bold enough for
   the 3:1 large-text exception either). On 2026-07-27 four real options were
   rendered at full size against the real hero background and measured: the
   original gradient with white text (this one, fails), the original
   gradient with dark ink-900 text (passes at roughly 4.9:1), the same white
   text made large-text size (still fails, 1.9:1 against a 3:1 bar), and the
   lightest possible darkening of the gradient that gets white to pass
   (passes at roughly 4.6:1, but reads as a muddy brown-wine pill, not
   pink-to-amber). Daniel saw all four, including the numbers, and chose
   white on the untouched gradient anyway. This button ships with a real,
   measured contrast failure at the amber end because that is the tradeoff
   he picked over losing the pill's colour identity. */
.hero .btn-primary,
.hero .btn-primary:hover { color: #fff; }

/* ---------- Mood check-in ---------- */

.hero-mood { margin-top: 30px; }

.hero-mood-label {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--hero-ink-faint);
}

.hero-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  margin-top: 13px;
}

.hero-chip {
  -webkit-appearance: none;
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 15px;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.5);
  border: 1px solid var(--ink-soft);
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 13px;
  color: var(--ink-700);
  cursor: pointer;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  transition:
    background-color var(--dur-quick) var(--ease-brand),
    color var(--dur-quick) var(--ease-brand),
    border-color var(--dur-quick) var(--ease-brand),
    box-shadow var(--dur-quick) var(--ease-brand),
    transform var(--dur-quick) var(--ease-brand);
}
.hero-chip:hover { background: rgba(255, 255, 255, 0.82); transform: translateY(-1px); }
.hero-chip:active { transform: scale(0.98); }
/* Comfortable touch target on coarse pointers (keeps the exact designed height
   on mouse/desktop) */
@media (pointer: coarse) { .hero-chip { min-height: 44px; } }

.hero-chip.is-active {
  background: rgba(42, 34, 48, 0.9);
  color: var(--cream-50);
  border-color: transparent;
  box-shadow: var(--hero-shadow-chip-active);
}
.hero-chip.is-active:hover { background: rgba(42, 34, 48, 0.9); }

.hero-chip-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.hero-chip-dot--overwhelmed { background: var(--violet-ink); }
.hero-chip-dot--anxious { background: var(--hero-mood-anxious); }
.hero-chip-dot--tender { background: var(--hero-mood-tender); }
.hero-chip-dot--curious { background: var(--teal); }
.hero-chip-dot--numb { background: var(--hero-mood-numb); }

.hero-mood-line {
  margin: 14px 0 0;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 17px;
  line-height: 1.4;
  color: var(--mood-line);
  min-height: 24px;
  transition: opacity 0.3s ease;
}

/* ---------- Visual layer (portrait, auras, bubbles, pill) ---------- */

.hero-visual {
  position: absolute;
  inset: 0;
  /* Portrait + decorative layers live in a slightly wider centred band than
     the text so the arch isn't cramped against the copy, but still tracks the
     composition centre instead of gluing to the far viewport edge on wide
     screens. left/right:0 (from inset) + max-width + auto margins = centred.
     Tied to --container (the text band's own max-width) rather than a fixed
     px value: a flat 1560px only capped this above 1560px viewports, so on
     ordinary desktop widths (1081-1559px, incl. common 1440px screens) the
     box filled edge-to-edge instead of staying centred with the text. */
  max-width: 1400px;
  margin-inline: auto;
  z-index: 1;
  pointer-events: none;
}

/* Vertically centre the cluster instead of the inset:0 default of stretching
   to the hero's full height. Every child below (portrait/aura/bubble/pill)
   is positioned via top/bottom offsets tuned against the design spec's fixed
   880px-tall reference canvas; left to stretch full-height, any viewport
   taller than 880px (i.e. almost every real desktop window) dumped 100% of
   the extra space above the portrait, growing an ever-larger, off-centre gap
   the taller the window got. Capping the box's own height and centring it
   redistributes that extra space evenly instead. 820px comfortably fits the
   tallest child (aura--a, up to 700px + its own bottom offset); below that,
   min() falls back to 100% so short/mobile-ish desktop heights are unaffected.
   margin-block:auto, not transform: hero.js's initHeroRecede() scrubs this
   same element's `transform` (scale + yPercent) on scroll via GSAP, which
   sets it as an inline style and completely replaces (not composes with) any
   transform from this stylesheet — a translateY(-50%) here fought that scroll
   animation and caused the flicker/drift bug. top+bottom+margin never touch
   `transform`, so the two systems can't collide. */
@media (min-width: 1081px) {
  .hero-stage { top: clamp(0px, 2vh, 18px); }

  .hero-visual {
    top: 0;
    bottom: 0;
    margin-block: auto;
    height: min(100%, 880px);
  }
}

.hero-aura { position: absolute; }
.hero-aura-inner { width: 100%; height: 100%; }

.hero-aura--a {
  right: clamp(-20px, 5vw, 70px);
  bottom: clamp(0px, 7vh, 58px);
  width: clamp(260px, 47vw, 660px);
  aspect-ratio: 660 / 700;
  z-index: 1;
}
.hero-aura--a .hero-aura-inner {
  background: radial-gradient(68% 56% at 44% 40%, var(--hero-aura-pink), var(--hero-aura-pink-fade) 72%);
  filter: blur(42px);
  opacity: 0.3;
  border-radius: 56% 44% 58% 42% / 46% 54% 46% 54%;
  animation: hero-float-b 24s ease-in-out 1.7s infinite;
}

.hero-aura--b {
  right: clamp(10px, 11vw, 150px);
  bottom: clamp(-20px, 1vh, 6px);
  width: clamp(180px, 32vw, 452px);
  aspect-ratio: 452 / 470;
  z-index: 2;
}
.hero-aura--b .hero-aura-inner {
  background: radial-gradient(60% 60% at 50% 62%, var(--hero-aura-amber), var(--hero-aura-amber-fade) 74%);
  filter: blur(32px);
  opacity: 0.32;
  border-radius: 56% 44% 48% 52% / 54% 46% 55% 45%;
  animation: hero-float-c 26s ease-in-out 2s infinite;
}

/* Jess, her glass arch, teal blob and credential are one responsive scene.
   Their internal offsets are expressed as percentages of the portrait frame,
   so resizing the browser cannot pull the arch and portrait apart again. */
.hero-portrait-scene {
  /* The top corners must each consume half the shape's width. Fixed-pixel
     radii leave a visible straight segment at larger portrait sizes. */
  --hero-arch-radius: 50% 50% 44px 44px / 34% 34% 44px 44px;
  position: absolute;
  right: clamp(-40px, 1vw, 16px);
  bottom: clamp(12px, 6vh, 64px);
  width: clamp(320px, min(35vw, 50vh), 600px);
  aspect-ratio: 452 / 648;
  z-index: 3;
  pointer-events: none;
}

/* The glass shares Jess's exact arch silhouette. It is a true backing layer
   rather than a shifted card, so its rim stays visually attached to her at
   every scale. */
.hero-portrait-aura {
  position: absolute;
  top: -7%;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: auto;
  aspect-ratio: auto;
  z-index: 2;
  pointer-events: none;
}
/* The perpetual drift lives on this inner layer rather than on
   .hero-portrait-aura itself: the entrance bloom() in hero.js animates that
   outer element's own transform via GSAP, and a CSS keyframe animation on the
   same property of the same element fights a concurrently-running GSAP tween
   instead of composing with it (the aura/portrait/bubble accents elsewhere in
   this file all use the same outer-entrance / inner-drift split for the same
   reason). */
.hero-portrait-aura-inner {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.5);
  border-radius: var(--hero-arch-radius);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0) 32%),
    linear-gradient(156deg, rgba(236, 95, 156, 0.5) 0%, rgba(180, 138, 224, 0.4) 40%, rgba(245, 168, 108, 0.46) 76%, rgba(236, 118, 150, 0.5) 100%);
  -webkit-backdrop-filter: blur(22px) saturate(1.55);
  backdrop-filter: blur(22px) saturate(1.55);
  box-shadow: 0 46px 92px -34px rgba(120, 50, 110, 0.5), inset 0 2px 1px rgba(255, 255, 255, 0.72), inset 0 -34px 60px -34px rgba(120, 40, 90, 0.28);
  animation: none;
}
.hero-portrait-aura-inner::before,
.hero-portrait-aura-inner::after {
  content: '';
  position: absolute;
  pointer-events: none;
}
.hero-portrait-aura-inner::before {
  top: -16%;
  left: -34%;
  width: 86%;
  height: 150%;
  background: linear-gradient(104deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.42) 46%, rgba(255, 255, 255, 0) 62%);
  transform: rotate(8deg);
}
.hero-portrait-aura-inner::after {
  inset: 0;
  background: url('../../assets/img/grain.png') center / 190px repeat;
  /* This grain sits inside a clipped glass arch whose GSAP-transformed outer
     wrapper is its nearest stacking context. That wrapper paints no opaque
     backdrop, so soft-light can fall through to the grey source texture.
     A calibrated normal-alpha pass keeps the same restrained texture without
     relying on backdrop blending. Headed-Chrome parity from 768 through
     2552px: mean delta <= 0.60 RGB, p95 3.33, max 8, zero pixels over 10. */
  mix-blend-mode: normal;
  opacity: 0.018;
}

.hero-portrait-wrap {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 100%;
  aspect-ratio: 452 / 648;
  z-index: 4;
}
.hero-portrait-frame {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: var(--hero-arch-radius);
  animation: hero-breathe 15s ease-in-out 1.8s infinite;
}
.hero-portrait-img {
  position: absolute;
  /* 2026-07-27, narrow authorised exception to the hero lock. Two passes.

     PASS 1 read "Hero section arch is not centred on Jess needs to go to the
     right a touch" as "move Jess right" and set this to 53.5%. That was the
     wrong half of the sentence. The arch needed to look centred ON HER; moving
     her right took her head 4.7% of the frame width PAST the arch's centre.

     PASS 2, the current value, after "align Jess' head to the centre of the
     arch and adjust her arm crop if needed to be centred with it".

     The arch (.hero-portrait-aura) and the portrait frame
     (.hero-portrait-wrap) are pixel-coincident, measured not assumed: centre
     delta 0.00px at both 2560x1440 and 1440x900, and at 390 the aura collapses
     so the frame IS the arch. So "the centre of the arch" is the frame's 50%.

     Where her head actually is was measured off the asset's own alpha channel
     rather than by eye: over the top 16% of the silhouette (rows 17-296 of
     jess.webp), the alpha-weighted horizontal centroid sits at 51.07% of the
     image width. She is very nearly centred in her own photograph.

     This element is 115% of the frame wide and is centred on `left` by the
     translateX(-50%) below, so a head at image fraction h lands at
         frame% = left + (h - 0.5) * 115
     Setting that to 50 gives left = 50 - (0.51072 - 0.5) * 115 = 48.77.
     48.8 is used, which puts the head 0.03% off the arch's centre, i.e. under
     a fifth of a pixel at 2560. Confirmed after the change at all three widths.

     THE ARM CROP came right with the same number, which is why there is no
     second correction here. The figure spans image columns 19-1081 of 1100, so
     it is wider than the frame and .hero-portrait-frame's overflow:hidden
     always trims both sleeves. What changed is the balance:
         at 53.5%  left sleeve trimmed 1.99%, right sleeve 9.01%  (7.0% apart)
         at 48.8%  left sleeve trimmed 6.71%, right sleeve 4.31%  (2.4% apart)

     Kept in % rather than px on purpose: a fixed nudge reads right at one width
     and wrong at another, and the offset above measured 4.73 / 4.75 / 4.73% at
     2560 / 1440 / 390, i.e. genuinely proportional. Nothing else changed. */
  left: 48.8%;
  top: 1.8%;
  transform: translateX(-50%);
  width: 115%;
  max-width: none;
  filter: drop-shadow(var(--shadow-portrait));
}

/* The original Surface Tension Blob replaces the two small decorative
   metaballs. Its CSS paint remains as the no-JS/reduced-motion fallback;
   hero.js paints the low-resolution animated field over this surface. */
.hero-surface-tension-blob {
  position: absolute;
  display: block;
  aspect-ratio: 1;
  max-width: none;
  border-radius: 46% 54% 57% 43% / 47% 43% 57% 53%;
  pointer-events: none;
}
.hero-surface-tension-blob.is-surface-tension-ready { background: none; }
.hero-surface-tension-blob--coral {
  right: clamp(278px, 35vw, 500px);
  top: clamp(84px, 16.6vh, 146px);
  z-index: 5;
  width: clamp(94px, 10.5vw, 152px);
  background: radial-gradient(circle at 34% 25%, #ffd29b 0%, #f49a62 30%, #ef7a4f 61%, #d95664 100%);
  filter: drop-shadow(0 24px 19px rgb(205 76 71 / 24%));
}
.hero-surface-tension-blob--teal {
  right: -18%;
  bottom: 16%;
  /* Above the glass arch, but below Jess: visible at the lower-right edge
     without ever sitting on top of the portrait. */
  z-index: 3;
  width: 36.3%;
  background: radial-gradient(circle at 34% 25%, #9ce5d4 0%, #48b9ae 27%, #199c99 58%, #17788c 100%);
  filter: drop-shadow(0 24px 19px rgb(20 87 105 / 24%));
}

/* Plain frosted glass, reproducing the approved recipe verbatim (raw values,
   not tokens, for that reason): a real-time refraction read of Jess's portrait
   behind this pill is too high-contrast for small dark text to stay legible
   at every position the pill's responsive offset can land on, so this stays
   a CSS material rather than a WebGL one. */
.hero-pill {
  position: absolute;
  right: 65%;
  bottom: 4%;
  z-index: 4;
  width: max-content;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 20px 12px 12px;
  border-radius: var(--radius-pill);
  /* Top of the brand kit's .5 to .55 GLASS-PILL range, plus a touch more, so
     the veil is thick enough to hold a stable backdrop wherever the pill lands
     on the portrait. Legibility of a credential line outranks the last 0.07 of
     translucency here. */
  background: rgba(255, 255, 255, 0.62);
  -webkit-backdrop-filter: blur(16px) saturate(1.3);
  backdrop-filter: blur(16px) saturate(1.3);
  border: 1px solid rgba(255, 255, 255, 0.92);
  box-shadow: 0 20px 40px -16px rgba(42, 34, 48, 0.35), inset 0 0 0 1px rgba(255, 255, 255, 0.4), inset 0 1px 1px rgba(255, 255, 255, 0.85);
}
.hero-pill-avatar {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--grad-monogram);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 21px;
  color: #fff;
}
.hero-pill-text { display: flex; flex-direction: column; line-height: 1.25; }
.hero-pill-years { font-family: var(--font-sans); font-weight: 600; font-size: 13px; color: var(--ink-900); }
.hero-pill-cred { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.05em; color: var(--hero-pill-cred-color); }

/* ---------- Credential strip ---------- */

.hero-credential-row {
  position: absolute;
  left: 0;
  right: 0;
  max-width: calc(var(--container) + 76px);
  bottom: clamp(20px, 4.5vh, 34px);
  z-index: 8;
  pointer-events: none;
}
.hero-credential-strip {
  margin: 0;
  max-width: 900px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.15em;
  line-height: 1.9;
  color: var(--hero-ink-faint);
}

/* ---------- Perpetual ambient motion (resting state under reduced-motion
   thanks to base.css's global animation-duration:0.01ms override — every
   keyframe below is a symmetric 0%/50%/100% loop that lands back on its
   resting value) ---------- */

/* hero-float-a was removed 2026-07-29: defined here but referenced by nothing
   (HANDOFF "Still open" item 23). hero-float-b / -c / hero-breathe below are
   all live. */
@keyframes hero-float-b { 0%, 100% { transform: translateY(0) rotate(0deg); } 50% { transform: translateY(14px) rotate(3deg); } }
@keyframes hero-float-c { 0%, 100% { transform: translate(0, 0) rotate(0deg); } 50% { transform: translate(10px, -12px) rotate(-4deg); } }
@keyframes hero-breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.03); } }

/* ============================================================
   Responsive
   ============================================================ */

/* Keep the portrait scene centred and legible on square-ish tablets. The
   compact, stacked mobile composition only begins once both columns no
   longer have enough room to breathe. */
@media (min-width: 768px) and (max-width: 1080px) {
  .hero-content { max-width: min(440px, 48vw); }

  .hero-visual {
    top: 0;
    bottom: 0;
    height: min(100%, 880px);
    margin-block: auto;
  }

  .hero-portrait-scene {
    right: clamp(-26px, 1vw, 12px);
    /* A bottom anchor made the scene progressively read as a footer element
       on tall, near-square tablets. Pin its visual centre instead, so its
       relationship to the copy holds while the two-column layout narrows. */
    top: min(58%, 540px);
    bottom: auto;
    transform: translateY(-50%);
    width: clamp(320px, min(35vw, 50vh), 390px);
  }
}

/* Tighten the two-zone composition before it has room to collide */
@media (max-width: 767px) {
  .hero-content { max-width: min(440px, 48vw); }

  .hero-portrait-wrap {
    right: clamp(8px, 5vw, 60px);
    width: clamp(200px, 30vw, 320px);
  }
  .hero-portrait-aura {
    right: clamp(12px, 5vw, 64px);
    width: clamp(200px, 30vw, 320px);
  }
  .hero-aura--a { right: clamp(-40px, 2vw, 0px); width: clamp(220px, 50vw, 420px); }
  .hero-aura--b { right: clamp(-10px, 4vw, 30px); width: clamp(160px, 38vw, 300px); }
  .hero-surface-tension-blob--coral { right: clamp(190px, 27vw, 290px); }
  .hero-surface-tension-blob--teal { right: clamp(-8px, 3vw, 34px); }
  .hero-pill { right: clamp(16px, 10vw, 120px); bottom: clamp(16px, 9vh, 60px); }
}

/* Single column below 768px: text stacks full-width, portrait becomes a
   smaller arch below the copy, blobs simplify, pill hides, strip wraps. */
@media (max-width: 767px) {
  .hero {
    padding-block: clamp(96px, 22vh, 140px) 48px;
    display: block;
  }

  .hero-content { max-width: 100%; }

  .hero-heading { line-height: 1.08; }

  .hero-visual {
    position: relative;
    inset: auto;
    display: flex;
    justify-content: center;
    margin-top: 40px;
    pointer-events: none;
  }

  .hero-portrait-scene {
    position: relative;
    inset: auto;
    width: auto;
    aspect-ratio: auto;
    display: contents;
  }

  .hero-portrait-wrap {
    position: relative;
    top: auto;
    right: auto;
    bottom: auto;
    width: min(64vw, 320px);
    aspect-ratio: 452 / 648;
  }

  .hero-portrait-frame {
    background: linear-gradient(158deg, #9a8ee6, var(--pink));
    box-shadow: 0 30px 60px -26px rgba(143, 60, 120, 0.5), inset 0 2px 0 rgba(255, 255, 255, 0.4);
  }

  /* Simplify to one soft aura. The ANZACATA credential remains paired with
     Jess in the mobile mockup, so it is restored just below this rule. */
  .hero-aura--b,
  .hero-surface-tension-blob,
  .hero-portrait-aura,
  .hero-pill { display: none; }

  .hero-aura--a {
    right: auto;
    left: 50%;
    bottom: auto;
    top: 50%;
    transform: translate(-50%, -50%);
    width: min(84vw, 480px);
  }

  .hero-pill {
    display: flex;
    right: max(16px, calc(50% - min(32vw, 160px)));
    bottom: clamp(12px, 4vw, 24px);
    z-index: 7;
    gap: 9px;
    padding: 9px 14px 9px 9px;
  }
  .hero-pill-avatar { width: 34px; height: 34px; font-size: 19px; }
  .hero-pill-years { font-size: 11.5px; }
  .hero-pill-cred { font-size: 9.5px; }

  .hero-credential-row {
    position: relative;
    left: auto;
    right: auto;
    bottom: auto;
    margin-top: 36px;
  }
  .hero-credential-strip { line-height: 2.1; }
}

@media (prefers-reduced-transparency: reduce) {
  .hero-chip,
  .hero-pill {
    background: #fffaf6;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .hero-pill {
    box-shadow: 0 14px 29px -13px rgba(42, 34, 48, 0.28), inset 0 1px 0 rgba(255, 255, 255, 0.86);
  }
  .hero-portrait-aura-inner {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .hero-pill {
    background: #fffaf6;
    box-shadow: 0 14px 29px -13px rgba(42, 34, 48, 0.28), inset 0 1px 0 rgba(255, 255, 255, 0.86);
  }
}

/* 1440p is a true large-format canvas, not just a wider version of a laptop.
   Give the editorial copy a little more presence while the grouped portrait
   scene above grows smoothly and retains its internal proportions. */
@media (min-width: 1920px) and (min-height: 1080px) {
  .hero-stage,
  .hero-credential-row { max-width: 1700px; }

  .hero-content { max-width: 680px; }
  .hero-heading { font-size: clamp(4rem, 3.35vw, 5rem); }
  .hero-sub { max-width: 520px; font-size: 20px; }

  /* On a 1440p canvas, keep the connected portrait-and-arch shape low in
     the field, while preserving its shared silhouette. */
  .hero-portrait-scene { right: -32px; bottom: 28px; }

  .hero .btn { font-size: 16px; }
  .hero .btn-primary { padding: 18px 31px; }
  .hero .btn-glass { padding: 17px 25px; }

  .hero-chip { padding: 10px 16px; font-size: 14px; }
  .hero-mood-label { font-size: 12px; }
}
