/* Homepage story: full photo → X-ray scan → content */

/* —— 1. Impact hero — tall portrait (lumin_index) —— */

.hero-splash {
  position: relative;
  /* Establish an explicit z-index AND a self-contained stacking context.
     Without this, .hero-splash__content (z-index: 2 below) escapes into
     the document stacking context and competes with the about-reveal
     section's headline (z-index: 20), which on desktop SITS ON TOP of
     the hero during the -15vh overlap. Pinning hero to z-index: 1 +
     isolating it means the whole hero block is a single z-layer at
     z=1, and about-reveal (z=5 in css/about-reveal.css) cleanly stacks
     above it during the overlap. */
  z-index: 1;
  isolation: isolate;
  /* Hard paint/layout containment — keeps the per-frame blur + transform
     writes from invalidating any layout/paint outside this section.
     Major flicker reduction on Lenis-scrolled blurred heroes. */
  contain: layout paint;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  height: 100vh;
  height: 100dvh;
  min-height: 480px;
  overflow: hidden;
  /* Match the page background so the bottom fade doesn't leave a visible color step. */
  background: var(--bg);
}

.hero-splash__media {
  position: absolute;
  inset: -4% 0;
  /* Promote to its own GPU layer + suppress back-face passes so the
     per-frame filter blur doesn't kick the entire stacking context into
     a re-rasterise loop. */
  will-change: filter;
  transform: translateZ(0);
  backface-visibility: hidden;
  /* Upward-blur on scroll — written DIRECTLY from js/hero-parallax.js as
     `filter: blur(Npx)` (integer px). The previous CSS-var setup
     (`filter: blur(calc(var(--hero-p) * 14px))`) recomputed the blur
     pipeline every time the var changed AND on every scroll event,
     producing the visible flicker. Inline-from-JS batches the write with
     the inner img's transform write → one style mutation per paint. */
}

.hero-splash__img {
  width: 100%;
  height: 108%;
  object-fit: cover;
  /* Tall 2:3 image — frame is wider than image, so top+bottom get cropped.
     HIGHER Y% = crop more from TOP, image content shifts UP, face moves UP on the page. */
  object-position: center 45%;
  transform: scale(1.06) translateZ(0);
  backface-visibility: hidden;
  will-change: transform;
}

.hero-splash__shade {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(8, 10, 15, 0.2) 0%,
    rgba(8, 10, 15, 0.08) 40%,
    rgba(8, 10, 15, 0.08) 60%,
    rgba(8, 10, 15, 0.35) 100%
  );
  pointer-events: none;
}

/* Bottom 50% of the hero gets a var(--bg) wash that's 100% opaque at the
 * very bottom edge and fades to 0% opacity 50vh above it (= midline of
 * the hero). Sits at z-index 1 so it covers the photo + shade but stays
 * under .hero-splash__content (z: 2) — the LUMIN text remains crisp
 * on top. */
.hero-splash::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 50vh;
  background: linear-gradient(to top, var(--bg) 0%, transparent 100%);
  pointer-events: none;
  z-index: 1;
}

.hero-splash__content {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: clamp(1.5rem, 5vw, 3rem);
  /* --hero-p (0 → 1) is written by js/hero-parallax.js based on scroll progress. */
  --hero-p: 0;
}

.hero-splash__name {
  margin: 0 0 0.5rem;
  /* TITLE FONT — DM Sans 600 (medium weight, wider via letter-spacing).
     User wants "wider, not thicker", so we keep a regular weight and let
     the tracking carry the size.
     Pre-loaded display alternates (swap by replacing the font-family line):
       font-family: "DM Sans", system-ui, sans-serif;                   (default, weight 600)
       font-family: "Archivo Black", "DM Sans", sans-serif;             (chunky, drop weight to 400)
       font-family: "Anton", "DM Sans", sans-serif;                     (condensed, drop weight to 400)
       font-family: "Big Shoulders Display", "DM Sans", sans-serif;     (narrow with attitude, weight 800)
       font-family: "Bebas Neue", "DM Sans", sans-serif;                (editorial all-caps)
       font-family: "Fraunces", Georgia, serif;                         (display serif, weight 900) */
  font-family: "DM Sans", system-ui, sans-serif;
  font-size: clamp(5rem, 22vw, 14rem);
  font-weight: 600;                          /* mid-weight: presence without bulk */
  letter-spacing: 0.26em;                    /* wide tracking carries the title */
  line-height: 1;
  white-space: nowrap;
  /* Knob: overall title visibility (1 = full, 0 = invisible). */
  --title-opacity: 0.45;                     /* softer presence, lets the photo breathe */
  opacity: var(--title-opacity);
  /* Mid-scatter (--hero-p around 0.4–0.7) used to look messy because heavy
     blur + intense cyan + gold glow all ramped together. Toned down so the
     letters stay clean as they fly out, with a faint warm halo only. */
  filter: blur(calc(var(--hero-p) * 6px));
  text-shadow:
    0 0 calc(6px + var(--hero-p) * 18px) rgba(255, 240, 220, calc(var(--hero-p) * 0.25)),
    0 6px 22px rgba(0, 0, 0, 0.45);
  will-change: filter, opacity;
}

/* Per-letter spans injected by js/hero-parallax.js.
   --ci = index from center (e.g. for "LUMIN": L=-2, U=-1, M=0, I=1, N=2).
   --hero-spread (set in JS) controls how far each letter flies (vw). */
.hero-splash__char {
  display: inline-block;
  transform: translateX(
    calc(var(--ci, 0) * var(--hero-p, 0) * var(--hero-spread, 12vw))
  );
  will-change: transform;
}

/* Stacked hero title ("LUMIN" / "AFTER DARK") — performance.html only.
   Moved to css/performance.css. */

.hero-splash__role {
  margin: 0;
  font-size: clamp(0.78rem, 2vw, 0.95rem);
  font-weight: 500;
  color: rgba(232, 236, 239, 0.82);
  max-width: 42ch;
  letter-spacing: 0.06em;
}

/* Watermark cover + subject zoom (.hero-splash--watermark-bl) —
   performance.html only. Moved to css/performance.css. */

/* —— About me — plain reading block ——
   Deliberately stripped: body font everywhere (no display serif), no accent
   colour, no bold, no eyebrow labels. Just two short paragraphs in a wide
   reading column. */

.about-me {
  padding: clamp(5rem, 12vw, 8rem) 0;
  text-align: center;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}

.about-me__container {
  max-width: 880px;                            /* wider reading box (was 680) */
  margin: 0 auto;
  padding: 0 clamp(1.5rem, 5vw, 2.5rem);
  display: grid;
  gap: clamp(2.5rem, 6vh, 4rem);
}

.about-block {
  text-align: center;
}

/* Three-tier type ramp inside the X-ray panel:
     phrase  — extremely large display heading, gets the X-ray scan effect
               ("Have we met?")
     intro   — "smaller large" subtitle copy, a clear step down from phrase
               but still oversized vs body
     bio     — regular body copy
   Phrase font (Fraunces) carries weight against the sans intro/bio. */
.about-block__phrase {
  margin: 0 0 1.6rem;
  font-family: var(--font-display, "Fraunces", serif);
  /* "Extremely large" — successive bumps requested by user:
       v0  clamp(2.4rem, 5.5vw, 4.6rem)
       v1  clamp(3.2rem, 8.4vw, 7rem)
       v2  current — headline now eats the panel at full-bleed sizes. */
  font-size: clamp(3.8rem, 12vw, 10rem);
  font-weight: 600;
  line-height: 0.94;
  letter-spacing: -0.02em;
  color: var(--text);
}

.about-block__phrase em {
  font-style: normal;
  color: inherit;
  font-weight: inherit;
}

/* "Smaller large" — sits between the display heading and the body copy.
   Bumped from clamp(1.05rem, 1.6vw, 1.3rem) so the size hierarchy reads
   clearly even on small screens. Slightly tighter letter-spacing keeps
   it from feeling thin against the heavy phrase above. */
.about-block__intro {
  margin: 0 auto 0.65rem;
  font-size: clamp(1.25rem, 2.1vw, 1.75rem);
  font-weight: 500;
  line-height: 1.4;
  color: var(--text);
  max-width: 56ch;
}

/* Extra breathing room before the regular bio paragraphs begin, so the
   intro-vs-bio tier transition reads as a deliberate hierarchy step. */
.about-block__intro:last-of-type {
  margin-bottom: 1.8rem;
}

.about-block__bio {
  margin: 0 auto 1rem;
  font-size: clamp(0.98rem, 1.2vw, 1.08rem);
  font-weight: 400;
  line-height: 1.75;
  color: var(--text-muted, var(--text));
  max-width: 62ch;
}

.about-block__bio:last-of-type {
  margin-bottom: 0;
}

.about-block__bio em,
.about-block__intro em {
  font-style: normal;
  color: inherit;
  font-weight: inherit;
}

.about-block__bio strong,
.about-block__intro strong {
  color: inherit;
  font-weight: 600;
  font-style: normal;
}

/* —— 2. X-ray scan — page-scroll parallax
   Image scrolls with the page at full speed.
   Scan line is absolute inside .portrait-scan__rig and gets a translateY()
   pushing it DOWN inside the rig as you scroll, so its net upward viewport
   speed is < 1.0 → line drifts down relative to image, performing the scan. */

.hero-scan {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  padding: 22vh 0 22vh;
  background: var(--bg);
  --scan: 0;
  --scan-px: 0px;
}

.hero-scan__layout {
  display: grid;
  /* Image column gets more of the row than the text column now that the
     X-ray panel is bigger. Was 1fr 1fr (50/50). */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: clamp(2rem, 5vw, 5rem);
  /* Positioning ancestor for the shared scan line, which is absolutely
     positioned and spans both columns. */
  position: relative;
  /* Top-aligned so the text's top is at the same y as the rig's top —
     this is what makes --scan-px (in rig-relative pixels) work as the y
     coordinate inside the text container too. */
  align-items: start;
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 clamp(1.5rem, 5vw, 3rem);
}

.hero-scan__text {
  text-align: left;
}

/* ---------------------------------------------------------------------------
   Scan-reveal text: two stacked copies of the same article.
   - .scan-text__layer--outline is absolutely positioned behind, rendered as
     stroke-only (transparent fill + -webkit-text-stroke).
   - .scan-text__layer--fill is the real article, on top, with a vertical
     gradient mask anchored to --scan-px so it disappears above the scan
     line and stays visible below.
   --------------------------------------------------------------------------- */
.scan-text {
  position: relative;
}

.scan-text .about-block {
  text-align: left;
}

.scan-text__layer--outline {
  position: absolute;
  inset: 0;
  margin: 0;
  pointer-events: none;
  z-index: 1;
}

/* Phrase ("Have we met?") is a PERMANENT X-ray — not a transient scan
   reveal. The fill layer's phrase is made transparent below so the
   outline copy in the layer behind is the only visible version, and it
   stays X-ray regardless of where the scan line is. Intro/bio still
   ride the regular fill mask, so they appear as the line passes them. */
.scan-text__layer--outline .about-block__phrase,
.scan-text__layer--outline .about-block__phrase em,
.scan-text__layer--outline .about-block__phrase strong {
  color: transparent;
  /* Stroke width bumped 1.4px → 2px and alpha pushed to a full 1 so the
     outline reads cleanly at the 10rem display size. Layered amber +
     near-white double shadow imitates a slight chromatic spread on a
     CRT scan line, selling the X-ray look stronger than a flat
     outline. */
  -webkit-text-stroke: 2px rgba(232, 234, 239, 1);
  text-shadow:
    0 0 0 rgba(232, 234, 239, 1),
    0 0 14px rgba(232, 234, 239, 0.18),
    0 0 2px rgba(212, 151, 100, 0.55);
}

/* Make the phrase in the fill layer invisible so only the outline layer
   renders — guarantees "Have we met?" is always in X-ray mode. */
.scan-text__layer--fill .about-block__phrase,
.scan-text__layer--fill .about-block__phrase em,
.scan-text__layer--fill .about-block__phrase strong {
  color: transparent;
  -webkit-text-stroke: 0;
}

.scan-text__layer--fill {
  position: relative;
  z-index: 2;
  /* The mask transition band is a 50px-wide soft zone centred on the scan
     line. Above the line: transparent (outline shows through). Below the
     line: opaque (filled text). --scan-edge tunes the softness of the
     hand-off (smaller = sharper line of conversion). */
  --scan-edge: 25px;
  -webkit-mask-image: linear-gradient(
    to bottom,
    transparent 0,
    transparent calc(var(--scan-px, 0px) - var(--scan-edge)),
    #000 calc(var(--scan-px, 0px) + var(--scan-edge)),
    #000 100%
  );
  mask-image: linear-gradient(
    to bottom,
    transparent 0,
    transparent calc(var(--scan-px, 0px) - var(--scan-edge)),
    #000 calc(var(--scan-px, 0px) + var(--scan-edge)),
    #000 100%
  );
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.hero-scan__eyebrow {
  margin: 0 0 1.1rem;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--accent);
  opacity: 0.85;
}

.hero-scan__phrase {
  margin: 0 0 1.75rem;
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 4vw, 2.85rem);
  font-weight: 600;
  line-height: 1.1;
  color: var(--text);
  letter-spacing: -0.01em;
}

.hero-scan__phrase em {
  color: inherit;
  font-style: normal;
}

.hero-scan__body {
  display: grid;
  gap: 1rem;
  font-size: clamp(0.95rem, 1.4vw, 1.05rem);
  line-height: 1.7;
  color: var(--text-muted);
  max-width: 44ch;
}

.hero-scan__tagline {
  margin-top: 0.75rem;
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 1.6vw, 1.25rem);
  color: var(--text);
  line-height: 1.4;
}

.hero-scan__tagline em {
  color: inherit;
  font-style: normal;
}

@media (max-width: 880px) {
  .hero-scan__layout {
    grid-template-columns: 1fr;
    gap: 3rem;
  }
  .hero-scan__text {
    text-align: center;
    margin-left: auto;
    margin-right: auto;
  }
  .scan-text .about-block {
    text-align: center;
  }
  /* When stacked, scan-px (rig-relative) no longer maps to text y — drop
     the outline layer and the mask, just show plain filled text. */
  .scan-text__layer--outline {
    display: none;
  }
  .scan-text__layer--fill {
    -webkit-mask-image: none;
    mask-image: none;
  }
  /* But: on desktop the phrase is rendered exclusively by the outline
     layer (fill phrase made invisible above). With the outline layer
     hidden in stacked mode, we'd lose the phrase entirely. Restore the
     X-ray treatment directly on the fill phrase so mobile still sees
     the "Have we met?" outline. */
  .scan-text__layer--fill .about-block__phrase,
  .scan-text__layer--fill .about-block__phrase em,
  .scan-text__layer--fill .about-block__phrase strong {
    color: transparent;
    -webkit-text-stroke: 2px rgba(232, 234, 239, 1);
    text-shadow:
      0 0 0 rgba(232, 234, 239, 1),
      0 0 14px rgba(232, 234, 239, 0.18),
      0 0 2px rgba(212, 151, 100, 0.55);
  }
  /* The shared scan line lives in the layout container and is anchored to
     layout-top + scan-px. In stacked mode the rig is BELOW the text, so
     that anchor no longer aligns with the image. Hide the line; the image
     still cross-fades photo → xray on its own via clip-path. */
  .hero-scan .portrait-scan__line {
    display: none;
  }
}

/* rig: frame + scan line that extends past the image. Was capped at 460px;
   widened so the X-ray panel becomes the dominant element on the right,
   matching the bumped grid ratio above. */
.portrait-scan__rig {
  position: relative;
  width: min(98%, 620px);
  margin: 0 auto;
}

.portrait-scan__frame--pole {
  width: 100%;
  aspect-ratio: 2 / 3;
  height: auto;
  max-height: none;
}

.portrait-scan__frame--pole .portrait-scan__layer--photo img {
  object-position: 52% 8%;
}

.portrait-scan__frame--pole .portrait-scan__layer--anatomy img {
  object-position: 52% 8%;
}

.hero-scan .portrait-scan__frame--pole {
  box-shadow:
    0 0 0 1px rgba(94, 224, 255, calc(0.08 + var(--scan) * 0.25)),
    0 40px 80px rgba(0, 0, 0, 0.55),
    0 0 calc(var(--scan) * 60px) rgba(110, 240, 255, calc(var(--scan) * 0.35));
}

.home-portrait--feature .portrait-scan__frame {
  border-radius: var(--radius-lg);
  box-shadow:
    0 0 0 1px rgba(94, 224, 255, 0.1),
    0 40px 80px rgba(0, 0, 0, 0.55);
}

/* Scan line — now a child of .hero-scan__layout (not the rig), so it spans
   BOTH the text column (left) and the image rig (right). As --scan-px
   drifts the line downward, it visibly passes over the text at the same y
   as it sweeps the photo, tying the two scan effects together visually. */
.hero-scan .portrait-scan__line {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 5;
  height: 2px;
  pointer-events: none;
  transform: translate3d(0, var(--scan-px, 0), 0);
  will-change: transform;
}

/* Gradient: soft fade at the outer 5%, full intensity across both columns
   in between. Slightly brighter over the image half (right) since that's
   where the scan visibly hits a surface — text scan is the consequence. */
.hero-scan .portrait-scan__line span {
  display: block;
  width: 100%;
  height: 100%;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(110, 240, 255, 0.4) 5%,
    rgba(110, 240, 255, 0.85) 18%,
    rgba(110, 240, 255, 0.95) 45%,
    #6ef0ff 65%,
    rgba(110, 240, 255, 0.85) 88%,
    rgba(110, 240, 255, 0.4) 96%,
    transparent 100%
  );
  box-shadow:
    0 0 14px rgba(110, 240, 255, 0.55),
    0 0 36px rgba(232, 184, 74, 0.18);
}

.hero-scan .portrait-scan__line::before,
.hero-scan .portrait-scan__line::after {
  display: none;
}

/* —— 3. Intro —— */

.hero-intro {
  padding: 4.5rem 0 2rem;
  text-align: center;
  border-bottom: 1px solid var(--border);
}

.hero-intro .container {
  max-width: 720px;
}

.hero-intro__eyebrow {
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 1rem;
}

.hero-intro h1 {
  font-size: clamp(2rem, 5vw, 3rem);
  margin-bottom: 1rem;
}

.hero-intro__tagline {
  font-size: clamp(1.05rem, 2.5vw, 1.3rem);
  color: var(--text-muted);
  margin: 0 auto 1rem;
  max-width: 42ch;
}

.hero-intro__identity {
  font-size: 0.95rem;
  color: var(--text-muted);
  margin-bottom: 2rem;
}

.hero-intro__identity strong {
  color: var(--text);
  font-weight: 500;
}

.hero-intro__cta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1rem;
  justify-content: center;
}

/* Header over hero */

/* Site header now defaults to a smooth fade/slide transition. While the hero
   is on screen we hide it entirely (via .site-header--hidden) and use the
   scattered .hero-nav inside the hero instead. Once you scroll past hero,
   site-header re-enters from the top as a functional sticky nav. */
.site-header {
  transition:
    opacity 0.35s ease,
    transform 0.35s ease,
    background 0.35s,
    border-color 0.35s;
}

.site-header--hidden {
  opacity: 0;
  pointer-events: none;
  transform: translateY(-100%);
}

body.is-work-immersive .site-header {
  opacity: 0;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Floating hero-nav that DOCKS to a top sticky nav bar as you scroll.

   - Container is position:fixed so the nav survives the hero scrolling out.
   - Each item has a distinct horizontal slot (--x) and a scattered initial
     vertical (--scatter-y). JS writes --p (0 → 1) onto the nav as splash
     scroll progresses, interpolating every item's top from --scatter-y to
     --nav-y. Backdrop blur/tint also fades in with --p.
   -------------------------------------------------------------------------- */

.hero-nav {
  position: fixed;
  inset: 0;
  z-index: 50;
  pointer-events: none;
  --p: 0;
  /* Bar height is 4.2rem (see .hero-nav::before); --nav-y points at the
     bar's vertical centre so items, with their translateY(-50%) at
     --p=1, end up centred in the bar. Was 1.5rem (top edge anchor),
     which left items looking bottom-aligned. */
  --nav-y: 2.1rem;
}

/* Top sticky nav backdrop. Stays invisible while the hero is on screen
   (the floating tabs sit on the portrait, no frosted bar yet) and only
   appears once the hero has almost fully scrolled away.

   --nav-bar-p ramps 0 → 1 across the last 12% of the hero scroll, using
   max() to clamp anything below the threshold to 0. Bump the threshold
   (0.88) up to delay the bar further, or down to make it appear earlier. */
.hero-nav {
  --nav-bar-threshold: 0.88;
  --nav-bar-p: max(0, calc((var(--p) - var(--nav-bar-threshold)) / (1 - var(--nav-bar-threshold))));
}

.hero-nav::before {
  content: "";
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  /* Bar is taller than the visual "label band" (still ~4.2rem tall in
     practice) so the mask gradient below has room to fade out smoothly
     under the labels — labels stay sharp, frosted glass bleeds away. */
  height: 6.4rem;
  background: rgba(12, 14, 20, calc(var(--nav-bar-p) * 0.72));
  backdrop-filter: blur(calc(var(--nav-bar-p) * 14px));
  -webkit-backdrop-filter: blur(calc(var(--nav-bar-p) * 14px));
  /* Mask the bar so BOTH the dark wash AND the backdrop-filter blur fade
     to nothing toward the bottom — no hard edge, no grey baseline. The
     mask masks the element itself, so anything past the gradient stop
     gets no frost / no fill, blending invisibly into the page below. */
  mask-image: linear-gradient(
    to bottom,
    black 0%,
    black 55%,
    transparent 100%
  );
  -webkit-mask-image: linear-gradient(
    to bottom,
    black 0%,
    black 55%,
    transparent 100%
  );
  pointer-events: none;
  z-index: -1;
  transition: background 0.15s linear, border-color 0.15s linear;
}

.hero-nav__items {
  list-style: none;
  margin: 0;
  padding: 0;
}

.hero-nav__item {
  position: absolute;
  --x: 50vw;
  --scatter-y: 50vh;
  left: var(--x);
  top: calc(var(--scatter-y) + (var(--nav-y) - var(--scatter-y)) * var(--p));
  /* X: centre the item ON its --x anchor (was left-anchored, so labels
     visually drifted right after the meta numbers were dropped).
     Y: lerp the vertical anchor from "top edge at --scatter-y" (--p=0,
     scattered hero state) to "centre at --nav-y" (--p=1, docked top
     bar). Without this lerp the docked items sat with their top edge
     on --nav-y, which made them look bottom-heavy in the 4.2rem bar.
     --nav-y is now set to the bar's vertical centre (2.1rem). */
  transform:
    translateX(-50%)
    translateY(calc(var(--p) * -50%));
  will-change: top, transform;
}

.hero-nav__item a {
  position: relative;                                /* anchors ::after tooltip */
  pointer-events: auto;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
  padding: 0.4rem 0.55rem;
  text-decoration: none;
  font-family: var(--font-body);
  font-size: clamp(1rem, 1.7vw, 1.3rem);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* Consistent ivory across all tabs (was per-pillar color). */
  color: rgba(255, 255, 255, 0.92);
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.55);
  transition: transform 0.25s ease, color 0.25s ease, letter-spacing 0.25s ease;
}

.hero-nav__item a:hover {
  transform: translateY(-3px);
  color: var(--accent);
  letter-spacing: 0.2em;
}

.hero-nav__meta {
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.35em;
  opacity: 0.5;
  color: rgba(255, 255, 255, 0.65);
}

.hero-nav__label {
  white-space: nowrap;
}

/* Hover tooltip: rendered from each <a data-tip="…">. Replace the data-tip
   attribute values in index.html when real copy is ready (the placeholder
   is "descriptions to be provided").
   data-tip-align="left|right" anchors the tip to the item's left/right edge
   instead of centering — used for the leftmost (About) and rightmost
   (Walk with Me) tabs so the tooltip doesn't run off the viewport. */
.hero-nav__item a[data-tip]::after {
  content: attr(data-tip);
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translate(-50%, 4px);
  margin-top: 0.55rem;
  padding: 0.5rem 0.7rem;
  width: max-content;
  max-width: 220px;
  font-family: var(--font-body);
  font-size: 0.7rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: none;
  text-align: center;
  white-space: normal;
  line-height: 1.45;
  color: rgba(255, 255, 255, 0.88);
  background: rgba(12, 14, 20, 0.92);
  border: 1px solid rgba(232, 184, 74, 0.22);
  border-radius: 4px;
  text-shadow: none;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
  z-index: 10;
}

.hero-nav__item a[data-tip]:hover::after,
.hero-nav__item a[data-tip]:focus-visible::after {
  opacity: 1;
  transform: translate(-50%, 0);
}

.hero-nav__item a[data-tip-align="left"]::after {
  left: 0;
  transform: translate(0, 4px);
}
.hero-nav__item a[data-tip-align="left"]:hover::after,
.hero-nav__item a[data-tip-align="left"]:focus-visible::after {
  transform: translate(0, 0);
}

.hero-nav__item a[data-tip-align="right"]::after {
  left: auto;
  right: 0;
  transform: translate(0, 4px);
}
.hero-nav__item a[data-tip-align="right"]:hover::after,
.hero-nav__item a[data-tip-align="right"]:focus-visible::after {
  transform: translate(0, 0);
}

/* Per-pillar color modifiers kept (but unused now that all tabs share one
   color). Re-enable by un-commenting `color: var(--tab-color)` above and
   these lines will take effect again.

   .hero-nav__item--feel     { --tab-color: var(--feel); }
   .hero-nav__item--ask      { --tab-color: var(--ask); }
   .hero-nav__item--evidence { --tab-color: var(--evidence); }
   .hero-nav__item--recovery { --tab-color: var(--recovery); }
   .hero-nav__item--work     { --tab-color: var(--accent); }
   .hero-nav__item--about    { --tab-color: rgba(255, 255, 255, 0.7); }
*/

/* Right-side items: when the inline style uses `right:` the item still
   anchors top-left of its bbox, so width-content alignment looks fine. */

/* Below 720px: 6 long labels won't fit horizontally as a top bar; instead,
   shrink tabs and keep them scattered (they scroll away with the hero,
   no docking). Footer is the navigation fallback. */
@media (max-width: 720px) {
  .hero-nav {
    /* Disable docking by pinning --nav-y to scatter-y via overshoot */
    --nav-y-disabled: 1;
  }
  .hero-nav__item {
    top: var(--scatter-y);
  }
  .hero-nav::before {
    display: none;
  }
  .hero-nav__item a {
    font-size: clamp(0.85rem, 3.6vw, 1.05rem);
    letter-spacing: 0.12em;
    padding: 0.3rem 0.4rem;
  }
  .hero-nav__meta { font-size: 0.55rem; }
}

@media (max-width: 700px) {
  .hero-scan {
    padding: 25vh 0 25vh;
  }

  .portrait-scan__rig {
    width: min(96vw, 460px);
  }

  .hero-splash__img {
    object-position: center 50%;
  }

  .hero-splash__name {
    letter-spacing: 0.18em;
  }
}
