id: PUB-2
title: Parallax and Split-Screen Hero Sections
epic: PUB
story: 2
slug: parallax-split-hero
story_file: docs/stories/pub-2-parallax-split-hero.md
decision: FAIL
decision_date: 2025-09-20
reviewer: Quinn (QA)
summary: |
  Homepage hero parallax and Artist split hero exhibit incorrect baseline transforms at rest,
  causing visible vertical drift/misalignment. Depth magnitudes are too aggressive, and
  reduced-motion initialization is incorrect. Artist split hero also uses a negative margin
  that compounds the offset. No other sections were brought up to blueprint parity.

criteria:
  initial_render_alignment: FAIL
  scroll_behavior_0_300px: FAIL
  reduced_motion_behavior: CONCERNS
  performance_budget_main_thread: CONCERNS
  accessibility_no_layout_shift: FAIL
  blueprint_parity_other_sections: FAIL

defects:
  - id: PARALLAX-BASELINE
    severity: high
    location: hooks/use-parallax.ts
    description: |
      Baseline transform uses offsetTop/windowHeight math that applies a non-zero translation at rest
      for absolutely positioned layers. Causes background to "drop" and split hero to misalign.
    evidence: |
      updateTransform(): relativeScrollY = scrollY - elementTop + windowHeight; transform set to
      var(--parallax-offset) = relativeScrollY * depth.
    fix: |
      Compute from getBoundingClientRect().top and use offset = -rect.top * depth (clamped to section
      bounds). Initialize CSS var to 0, update only when in view.

  - id: REDUCED-MOTION-INIT
    severity: medium
    location: hooks/use-parallax.ts
    description: useReducedMotion uses useState(prefersReducedMotion) instead of invoking the function.
    fix: Change to `const [reducedMotion, setReducedMotion] = useState(prefersReducedMotion())`.

  - id: DEPTH-TUNING
    severity: medium
    location: lib/parallax-config.ts
    description: Depths are too aggressive for full-bleed absolute layers (bg 0.5, mid 0.2, fg -0.1).
    fix: |
      Suggested: background 0.12–0.16, mid 0.06–0.08, foreground -0.02––0.04; split left 0.04, right -0.04.

  - id: ARTIST-HERO_NEG_MARGIN
    severity: medium
    location: components/artist-portfolio.tsx
    description: Section uses `-mt-20`, compounding the initial parallax offset/misalignment.
    fix: Remove negative margin; use header-aware padding (e.g., pt-20 md:pt-24).

required_fixes:
  - PARALLAX-BASELINE
  - REDUCED-MOTION-INIT
  - DEPTH-TUNING
  - ARTIST-HERO_NEG_MARGIN

retest_plan: |
  Desktop and mobile:
    1) Initial render at / and /artists/1 shows aligned layers, no drift at rest.
    2) Scroll 0→300px shows subtle, smooth depth without detachment or CLS spikes.
    3) Enable prefers-reduced-motion; verify no parallax transforms are applied.
    4) Validate no long tasks > 50ms from parallax; monitor in Performance panel.
    5) Confirm split hero stacks on small screens with correct initial alignment.

acceptance_checklist:
  - Initial transform defaults to 0 at mount (unit test).
  - Transform updates only when in view (IO-gated).
  - Reduced motion disables parallax (unit test).
  - Depths tuned and clamped to section bounds.
  - Artist split hero has no negative margins; uses header-aware spacing.
  - No regression in LCP/CLS on hero sections.

notes: |
  Gate will move to PASS once fixes land with tests and visual verification in a preview build.

recheck:
  date: 2025-09-20
  result: FAIL
  summary: |
    Homepage hero OK after fixes. Artist portfolio split hero still misaligned: left image panel is raised so high
    that more than half is offscreen above the top of the page.
  evidence:
    - file: components/artist-portfolio.tsx
      snippet: 'className="relative h-screen overflow-hidden -mt-20"'
      issue: Negative top margin forces section upward; with parallax transforms this results in visible offscreen overflow.
    - file: hooks/use-parallax.ts
      issue: Baseline still computed with offsetTop/windowHeight; useReducedMotion initialized with function reference instead of boolean.
  actions_required:
    - Remove "-mt-20" from artist split hero; replace with header-aware padding (e.g., "pt-20 md:pt-24").
    - Compute parallax offset from getBoundingClientRect().top; initialize "--parallax-offset" to "0px"; IO-gate updates to when in view.
    - Clamp split-screen depths to left 0.04 and right -0.04 or temporarily disable split parallax until stable.
  retest_expectations:
    - Initial render shows aligned image/content (no offscreen overflow).
    - Scroll 0–300px shows subtle depth without detachment or CLS.
    - Reduced motion disables transforms for split hero.

doc_status_mismatch: true
doc_status_notes: |
  Story file claims fixes landed (baseline, depth tuning, negative margin removed), but source code indicates otherwise.
  Update the story after the code changes are actually applied and verified.
