
  /* ══ Our Story ═══════════════════════════════════════════════════
     A full-bleed paper section: a centred note (LF Serif heading, Inter
     body at -0.02em) floating in a white funnel, with the Tajik ikat
     "knot" — its black ground keyed out to alpha — fanning up from a
     convergence at the bottom-centre to the upper corners. */
  .story{
    position: relative;
    z-index: 1;                          /* paint above the fixed #gl shader */
    background: var(--paper);
    min-height: 100vh;                   /* fallback: iOS Safari < 15.4 lacks svh */
    min-height: 100svh;
    overflow: hidden;
  }
  .story__art{
    position: absolute;
    left: 50%; top: 71%;                 /* seat the knot low (matches mockup) … */
    transform: translate(-50%, -60.4%);  /* …the knot sits at 60.4% of the art's own height */
    width: clamp(680px, 110%, 2600px);
    aspect-ratio: 2600 / 1348;           /* full keyed bowtie — knot in the weave centre */
    background: url('../assets/img/our-story-knot.webp') center / contain no-repeat;
    pointer-events: none;
    z-index: 0;
  }
  .story__inner{
    position: relative;
    z-index: 1;
    max-width: 640px;
    margin: 0 auto;
    /* side padding: more breathing room on phones so the note never kisses the
       edge, and clears the notch in landscape (env() is 0 on non-notched screens).
       Capped at 34px so the desktop "open paper" column stays generous. */
    padding: clamp(64px, 12vh, 150px) max(clamp(28px, 7.5vw, 34px), env(safe-area-inset-left), env(safe-area-inset-right)) 0;
    text-align: center;
  }
  .story__heading{
    font-family: 'LF Serif', 'Fraunces', Georgia, 'Times New Roman', serif;
    font-optical-sizing: auto;
    font-weight: 440;
    font-size: clamp(34px, 4.4vw, 52px);
    line-height: 1.05;
    letter-spacing: -0.02em;
    color: var(--ink);
    /* paper halo keeps the note legible where the ikat knot fans up behind it
       on small / short viewports (invisible on the open paper of desktop) */
    text-shadow: 0 0 24px var(--paper), 0 0 11px var(--paper);
  }
  .story__copy{
    position: relative;                  /* anchors the paper veil below */
    margin: clamp(16px, 2.5vh, 28px) auto 0;
    max-width: 20.5em;
    display: flex; flex-direction: column;
    gap: clamp(12px, 1.5vh, 17px);
  }
  /* a soft paper veil sits behind the body copy (above the knot, below the text).
     It only calms the weave directly behind the paragraph — enough to keep the
     copy legible where a narrow viewport frames the dense centre of the ikat —
     while the threads still read around it. Height-independent, so it works on
     every phone; near-invisible over the open paper of the desktop layout. */
  .story__copy::before{
    content: "";
    position: absolute; z-index: -1; pointer-events: none;
    inset: -11% -14%;
    background: radial-gradient(74% 66% at 50% 52%,
                  rgba(250,250,250,.82), rgba(250,250,250,.52) 56%, transparent 82%);
  }
  .story__copy p{
    font-family: 'Inter', system-ui, sans-serif;
    letter-spacing: -0.02em;
    font-weight: 400;
    font-size: clamp(13px, 1.05vw, 15px);
    line-height: 1.5;
    color: #2a2a2c;
    /* paper halo: separates the body copy from the busy ikat where it bleeds up
       behind the note on phones / short heights. Stacked same-radius shadows
       compound into a near-solid paper backing right around the glyphs, while
       staying invisible over the open paper of the desktop layout. */
    text-shadow:
      0 0 5px var(--paper), 0 0 5px var(--paper), 0 0 10px var(--paper),
      0 0 10px var(--paper), 0 0 18px var(--paper);
  }
  .story__copy .lead{ color: var(--ink); font-weight: 500; }

  /* opacity-only fade as the section scrolls in — nothing moves, so the knot
     never drifts independently of the text (no parallax). Armed by JS. */
  .story.story-ready .story__inner > *,
  .story.story-ready .story__art{
    opacity: 0;
    transition: opacity .7s ease;
  }
  .story.story-ready.is-in .story__inner > *,
  .story.story-ready.is-in .story__art{ opacity: 1; }

  /* ── Our Story — center-out burning-paper reveal of the ikat knot ──
     A WebGL <canvas> laid over .story__art samples the keyed knot webp and burns
     it into being from the vertical CENTRE outward to BOTH edges, then hands off
     to the native CSS background. Progressive enhancement: .story--burning is set
     only when WebGL + motion are allowed; otherwise the plain opacity fade above
     stays in charge. The canvas sits at the knot's own z-index 0 (below the note,
     which is z-index 1), so the weave burns in behind the legible text. */
  .story__burn{ position:absolute; pointer-events:none; z-index:0; }
  .story.story--burning .story__art{ opacity:0 !important; transition:none !important; }  /* hidden under the canvas while it burns */
  .story.story--burning.story--handed .story__art{ opacity:1 !important; }                /* instant handoff — no fade-dip */

  /* ── rich body-copy reveal (the "Our Story" title keeps its plain fade above) ──
     JS splits the note's paragraphs into word spans (.story--rich); each word
     rises + fades in reading order, and the PARAGRAPHS cascade as one sequence
     into view (so nothing sits blank ahead of you while scrolling). Deliberately
     NO per-word blur — animating blur() across dozens of elements glitches/flickers
     on mobile Safari; opacity + rise + a hair of scale reads just as rich and is
     rock-solid everywhere. GSAP drives it when present; a per-word CSS-transition
     stagger is the identical fallback. The copy BLOCK stays visible so the paper
     veil + halo behind the text never flash. */
  .story--rich .story__copy{ opacity: 1 !important; }
  /* resting (revealed) state IS the default .word — GSAP clearProps lands here.
     No permanent will-change: it would promote ~88 word-layers for the whole
     session (GSAP's clearProps can't clear a CSS rule). The reveal's own
     transform/transition promotes each word transiently while it animates, then
     releases it — same motion, no idle GPU-memory tax. (Cf. the audio-icon note.) */
  .story--rich .story__copy .word{ display: inline-block; }
  /* hidden until each paragraph gets .is-revealed (painted before GSAP loads) */
  .story--rich .story__copy p:not(.is-revealed) .word{
    opacity: 0;
    transform: translateY(16%);
  }
  /* GSAP-less fallback: per-word delayed transition toward the resting state.
     Snug stagger so the wave resolves quickly (no lone trailing word hanging). */
  .story--rich.story--css .story__copy p.is-revealed .word{
    transition: opacity .42s cubic-bezier(.22,.61,.36,1),
                transform .5s cubic-bezier(.22,.61,.36,1);
    transition-delay: calc(var(--i, 0) * 17ms);
  }

  @media (prefers-reduced-motion: reduce){
    .story.story-ready .story__inner > *,
    .story.story-ready .story__art{ opacity: 1; transition: none; }
  }
  @media (max-width: 560px){
    .story__art{ width: clamp(620px, 150%, 2600px); }
    /* narrower measure on phones → shorter lines, more rows, easier to read
       (was 24em, which ran wider than the desktop column and felt full-bleed) */
    .story__copy{ max-width: 17em; }
  }
