/* Tracklist — Home page sections */

// Section 1: Hero with parallax glow
const Hero = () => {
  const [scroll, setScroll] = React.useState(0);
  React.useEffect(() => {
    const onScroll = () => setScroll(window.scrollY);
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  return (
    <section style={{ padding: '40px var(--pad) 20px', position: 'relative', overflow: 'hidden', fontWeight: "400" }}>
<h1 className="display hero-title" style={{ margin: '0 0 24px', position: 'relative', fontWeight: 600 }}>
        Music is better together
      </h1>
      <p style={{ margin: '0 auto', fontSize: 'clamp(12px, 2vw, 18px)', color: 'var(--text-secondary, #888)', maxWidth: 480, lineHeight: 1.5, textAlign: 'center' }}>
        See what events your friends are going to. No more FOMO.<br className="hero-caption-break" /> Hit them up and make some new memories
      </p>
    </section>);

};

// Section 2: Horizontal infinite marquee
const Marquee = () => {
  const items = [
  { name: 'COACHELLA', date: '04.11', venue: 'Indio', img: 'uploads/coachella.JPG' },
  { name: 'PORTOLA', date: '09.28', venue: 'San Francisco', img: 'uploads/portola_2024.jpg' },
  { name: 'EDC', date: '05.21', venue: 'Las Vegas', img: 'uploads/edc.jpeg', imgPosition: '65% bottom', imgSize: '170%' },
  { name: 'CORSICA', date: '04.18', venue: 'London' },
  { name: 'BOILER ROOM', date: '04.22', venue: 'NYC' },
  { name: 'FABRIC', date: '05.04', venue: 'London' }];

  return (
    <section style={{ padding: '40px 0 60px', overflow: 'hidden' }}>
      <div style={{ display: 'flex', gap: 28, animation: 'marquee 40s linear infinite', width: 'max-content' }}>
        {[...items, ...items, ...items].map((item, i) =>
        <div key={i} style={{
          width: 220,
          flexShrink: 0,
          display: 'flex', flexDirection: 'column', gap: 10
        }}>
            {item.img
              ? <div role="img" aria-label={item.name} style={{
                  width: '100%', aspectRatio: '4/5', borderRadius: 12,
                  backgroundImage: `url(${item.img})`,
                  backgroundSize: item.imgSize || 'cover',
                  backgroundPosition: item.imgPosition || 'center center',
                  backgroundRepeat: 'no-repeat'
                }} />
              : <div className="ph ph-purple" style={{ width: '100%', aspectRatio: '4/5', borderRadius: 12 }} data-label={item.name.toLowerCase()} />
            }
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', padding: '0 4px' }}>
              <div className="display" style={{ fontSize: 15, fontWeight: 600, letterSpacing: '-0.01em' }}>{item.name}</div>
              <div className="mono" style={{ fontSize: 10, color: 'var(--brand-soft)' }}>{item.date}</div>
            </div>
            <div className="mono" style={{ fontSize: 10, color: 'var(--muted)', letterSpacing: '0.1em', padding: '0 4px' }}>{item.venue.toUpperCase()}</div>
          </div>
        )}
      </div>
      <style>{`
        @keyframes marquee {
          from { transform: translateX(0); }
          to { transform: translateX(-33.333%); }
        }
      `}</style>
    </section>);

};

// Section 3: Photo grid
const ParallaxGrid = () => {
  const [activeMobileIdx, setActiveMobileIdx] = React.useState(null);

  React.useEffect(() => {
    if (window.matchMedia('(hover: hover)').matches) return;
    const update = () => {
      const screenMid = window.innerHeight / 2;
      let bestIdx = null, bestDist = Infinity;
      document.querySelectorAll('[data-mobile-idx]').forEach(el => {
        const rect = el.getBoundingClientRect();
        const elMid = rect.top + rect.height / 2;
        const dist = Math.abs(elMid - screenMid);
        if (dist < bestDist) {
          bestDist = dist;
          bestIdx = parseInt(el.dataset.mobileIdx);
        }
      });
      setActiveMobileIdx(bestIdx);
    };
    window.addEventListener('scroll', update, { passive: true });
    update();
    return () => window.removeEventListener('scroll', update);
  }, []);

  // Rating color scale ported from ratingScoreColor.ts
  const KEY_COLORS = ['#FF4444','#FF5555','#FF8800','#FFB300','#8BC34A','#4CAF50'];
  const parseHex = h => ({ r: parseInt(h.slice(1,3),16), g: parseInt(h.slice(3,5),16), b: parseInt(h.slice(5,7),16) });
  const lerp = (a,b,t) => Math.round(a+(b-a)*t);
  const getRatingColor = (rating) => {
    const c = Math.max(0, Math.min(5, rating));
    if (c <= 0) return KEY_COLORS[0];
    if (c >= 5) return KEY_COLORS[5];
    const k = Math.floor(c), t = c - k;
    const A = parseHex(KEY_COLORS[k]), B = parseHex(KEY_COLORS[k+1]);
    return `#${[lerp(A.r,B.r,t),lerp(A.g,B.g,t),lerp(A.b,B.b,t)].map(x=>x.toString(16).padStart(2,'0')).join('')}`;
  };

  const RatingBadge = ({ score }) => (
    <div style={{
      position: 'absolute', top: 10, right: 10, zIndex: 2,
      width: 44, height: 44, borderRadius: '50%',
      background: getRatingColor(score),
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      color: '#fff', fontFamily: "'Unbounded', sans-serif",
      fontSize: 15, fontWeight: 700, letterSpacing: '-0.02em',
      boxShadow: '0 2px 10px rgba(0,0,0,0.35)',
    }}>
      {score}
    </div>
  );

  const CaptionBox = ({ text }) => (
    <div style={{
      position: 'absolute', bottom: 10, left: 10, right: 10, zIndex: 2,
      background: 'rgba(255,255,255,0.95)',
      borderRadius: 10, padding: '8px 11px',
      color: '#0A0A0F', fontSize: 12, fontWeight: 500, lineHeight: 1.45,
      boxShadow: '0 2px 12px rgba(0,0,0,0.25)',
    }}>
      "{text}"
    </div>
  );

  const Photo = ({ src, alt, ratio, badge, caption, review, score, user, title, mobileIdx }) => (
    <div
      style={{ position: 'relative' }}
      className={review ? 'photo-hoverable' : ''}
      {...(mobileIdx != null ? { 'data-mobile-idx': mobileIdx } : {})}
    >
      {src
        ? <img src={src} alt={alt} loading='lazy' decoding='async' style={{ aspectRatio: ratio, display: 'block', width: '100%' }} />
        : <div className="ph ph-purple" style={{ aspectRatio: ratio }} data-label="photo" />
      }
      {badge != null && <RatingBadge score={badge} />}
      {caption && <CaptionBox text={caption} />}
      {review && (
        <div className={`photo-review-overlay${mobileIdx != null && activeMobileIdx === mobileIdx ? ' mobile-active' : ''}`}>
          {title && <p className="photo-review-title">{title}</p>}
          {score != null && (
            <div className="photo-review-score">
              {score}/5
            </div>
          )}
          <p className="photo-review-text">"{review}"</p>
          {user && <p className="photo-review-user">{user}</p>}
        </div>
      )}
    </div>
  );

  // --- Mobile layout: 2 columns x 3 photos each ---
  const mobileCol1 = [
    { src: 'uploads/justin_bieber.jpg', alt: 'Justin Bieber', ratio: '3/4', mobileIdx: 0, title: 'Justin Bieber @ Coachella 2026',   score: 5,   review: 'Will never forget this set. Interesting set and played a lot of SWAG but some old songs. Wish he played more old songs but his vocals carried. Will be streaming SWAG nonstop now.', user: 'Carol' },
    { src: 'uploads/fred.JPG',          alt: 'Fred',          ratio: '1/1', mobileIdx: 3, title: 'Fred again.. @ Frost Amphitheater', score: 4.3, review: 'He had the whole place dancing. Suddenly appeared right in front of me and blew my mind.',                                                                                  user: 'Megan' },
    { src: 'uploads/oasis.JPG',         alt: 'Oasis',         ratio: '4/5', mobileIdx: 5, title: 'Oasis @ Rose Bowl',                 score: 4.5, review: 'Flew down to LA just for this show. Lifechanging experience.',                                                                                                            user: 'Megan' },
  ];
  const mobileCol2 = [
    { src: 'uploads/odesza.jpeg',        alt: 'Odesza',        ratio: '1/1', mobileIdx: 1, title: 'ODESZA @ Greek Theatre',           score: 4.7, review: 'Brought out an entire ochestra and drones for this show!! Theyre always putting on a show.',                                                                               user: 'Justin' },
    { src: 'uploads/disco_portola.JPG',  alt: 'Disco',         ratio: '1/1', mobileIdx: 2, title: 'Portola Festival',                 score: 4.2, review: 'Unique sets from most artists. Vibes were great but logistics needs work. Zero signal, sound was horrendous in the warehouse first day, goodluck getting a ride home.',   user: 'Phil' },
    { src: 'uploads/grateful_dead.jpeg', alt: 'Grateful Dead', ratio: '4/5', mobileIdx: 4, title: 'Dead & Co. @ Golden Gate Park', score: 4.5, review: 'Wow. First time at a Dead show and it was amazing. The crowd was so into it. The energy was electric. Would recommend even if you arent familiar with the music',        user: 'Jeff' },
  ];

  // --- Desktop layout: 3 columns x 2 photos each ---
  const desktopCol1 = [
    { src: 'uploads/justin_bieber.jpg', alt: 'Justin Bieber', ratio: '3/4', title: 'Justin Bieber @ Coachella 2026',      score: 5,   review: 'Will never forget this set. Interesting set and played a lot of SWAG but some old songs. Wish he played more old songs but his vocals carried. Will be streaming SWAG nonstop now.', user: 'Carol' },
    { src: 'uploads/disco_portola.JPG', alt: 'Disco',         ratio: '1/1', title: 'Portola Festival',                      score: 4.2, review: 'Unique sets from most artists. Vibes were great but logistics needs work. Zero signal, sound was horrendous in the warehouse first day, goodluck getting a ride home.',          user: 'Phil' },
  ];
  const desktopCol2 = [
    { src: 'uploads/odesza.jpeg',        alt: 'Odesza',        ratio: '1/1', title: 'ODESZA @ Greek Theatre',               score: 4.7, review: 'Brought out an entire ochestra and drones for this show!! Theyre always putting on a show.',                                                                                      user: 'Justin' },
    { src: 'uploads/grateful_dead.jpeg', alt: 'Grateful Dead', ratio: '4/5', title: 'Grateful Dead @ Golden Gate Park',     score: 4.5, review: 'Wow. First time at a Dead show and it was amazing. The crowd was so into it. The energy was electric. Would recommend even if you arent familiar with the music',               user: 'Jeff' },
  ];
  const desktopCol3 = [
    { src: 'uploads/fred.JPG',  alt: 'Fred',  ratio: '1/1', title: 'Fred again.. @ Frost Amphitheater',  score: 4.3, review: 'He had the whole place dancing. Suddenly appeared right in front of me and blew my mind.', user: 'Megan' },
    { src: 'uploads/oasis.JPG', alt: 'Oasis', ratio: '4/5', title: 'Oasis @ Rose Bowl',                  score: 4.5, review: 'Flew down to LA just for this show. Lifechanging experience.',                            user: 'Megan' },
  ];

  return (
    <section style={{ padding: 'clamp(32px, 6vw, 100px) var(--pad) 80px' }}>
      <div className="reviews-heading">
        <h2 className="section-title">
          Reviews from real fans
        </h2>
        <p style={{ margin: '8px auto 0', fontSize: 'clamp(12px, 2vw, 18px)', color: 'var(--text-secondary, #888)', maxWidth: 640, lineHeight: 1.5, textAlign: 'center' }}>
          No bots or sponsored posts. Only ratings from people who go.<br className="reviews-caption-break" /> Be in the know for your upcoming shows.
        </p>
      </div>

      {/* Mobile: 2 cols x 3 photos */}
      <div className="reviews-col-grid reviews-mobile">
        <div className="reviews-col">
          {mobileCol1.map((p, i) => <Photo key={i} {...p} />)}
        </div>
        <div className="reviews-col" style={{ marginTop: 32 }}>
          {mobileCol2.map((p, i) => <Photo key={i} {...p} />)}
        </div>
      </div>

      {/* Desktop: 3 cols x 2 photos */}
      <div className="reviews-col-grid reviews-desktop">
        <div className="reviews-col">
          {desktopCol1.map((p, i) => <Photo key={i} {...p} />)}
        </div>
        <div className="reviews-col" style={{ marginTop: 28 }}>
          {desktopCol2.map((p, i) => <Photo key={i} {...p} />)}
        </div>
        <div className="reviews-col" style={{ marginTop: 8 }}>
          {desktopCol3.map((p, i) => <Photo key={i} {...p} />)}
        </div>
      </div>
      <style>{`
        .hero-caption-break { display: block; }
        .reviews-caption-break { display: none; }
        @media (min-width: 768px) {
          .hero-caption-break { display: none; }
          .reviews-caption-break { display: block; }
        }
        .photo-review-overlay {
          position: absolute;
          inset: 0;
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          padding: 20px;
          gap: 10px;
          background: rgba(0,0,0,0);
          opacity: 0;
          transition: opacity 0.25s ease, background 0.25s ease;
          pointer-events: none;
        }
        .photo-review-title {
          color: #fff;
          font-family: 'Unbounded', sans-serif;
          font-size: 18px;
          font-weight: 600;
          letter-spacing: -0.01em;
          margin: 0;
          text-align: center;
        }
        .photo-review-score {
          font-family: 'Unbounded', sans-serif;
          font-size: 18px;
          font-weight: 700;
          color: #fff;
          letter-spacing: -0.02em;
        }
        .photo-review-text {
          color: #fff;
          font-size: 15px;
          line-height: 1.55;
          text-align: center;
          font-style: italic;
          margin: 0;
        }
        .photo-review-user {
          color: #fff;
          font-size: 15px;
          font-style: italic;
          margin: 0;
          text-align: center;
        }
        @media not all and (hover: hover) {
          .photo-review-title { font-size: 10px; }
          .photo-review-score { font-size: 10px; }
          .photo-review-text  { font-size: 9px; line-height: 1.45; }
          .photo-review-user  { font-size: 9px; font-style: italic; }
          .photo-review-overlay { gap: 6px; padding: 12px; }
        }
        @media (hover: hover) {
          .photo-hoverable:hover .photo-review-overlay {
            opacity: 1;
            background: rgba(0,0,0,0.62);
            pointer-events: auto;
          }
          .photo-review-text { color: rgba(255,255,255,0.75); }
          .photo-review-user { color: rgba(255,255,255,0.75); }
        }
        @media not all and (hover: hover) {
          .photo-review-overlay.mobile-active {
            opacity: 1;
            background: rgba(0,0,0,0.62);
          }
        }
      `}</style>
    </section>);

};
// Section 4: Feature slides
const PinnedFade = () => {
  const slides = [
  { tag: 'CONNECT', title: 'Music is better,\ntogether', sub: 'Stay in tune and put your friends on.', label: 'social feed screen', color: '#278658', img: 'friends_carousel.jpg' },
  { tag: 'RATE', title: "What's your take?", sub: "No such thing as a bad take, or is there.. let's find out", label: 'rating UI screen' },
  { tag: 'RECON', title: 'Be in the know', sub: 'Reviews from people who go', label: 'recon screen' },
  { tag: 'REMEMBER', title: 'All your memories\nin one place', sub: 'No more aimlessly scrolling through your photos and notes app', label: 'archive screen' }];

  return (
    <section style={{ padding: '80px var(--pad)' }}>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 80 }}>
        {slides.map((slide, i) =>
        <div key={i} className={`slide-row${i % 2 === 1 ? ' slide-row-reverse' : ''}`}>
            <div className="slide-text">
              <p className="mono" style={{
              fontSize: 11, letterSpacing: '0.2em', color: 'var(--brand-soft)', margin: '0 0 12px'
            }}>{slide.tag}</p>
              <h3 className="display" style={{
              fontSize: 'var(--fs-feature)', lineHeight: 0.95, margin: '0 0 16px', whiteSpace: 'pre-line',
              fontWeight: 600
            }}>{slide.color ? (() => {const lines = slide.title.split('\n');return <><span style={{ color: '#f5f5f7' }}>{lines[0]}{'\n'}</span><span style={{ color: 'rgb(63, 172, 96)' }}>{lines.slice(1).join('\n')}</span></>;})() : slide.title}</h3>
              <p style={{ color: 'var(--muted)', fontSize: 16, margin: 0, maxWidth: 440 }}>{slide.sub}</p>
            </div>
            <div className="slide-media">
              {slide.img
                ? <img src={slide.img} alt={slide.label} style={{ borderRadius: 24, width: '100%', height: 'auto', objectFit: 'cover' }} />
                : <div className="ph ph-purple" style={{ aspectRatio: '4/3', borderRadius: 24 }} data-label={slide.label} />
              }
            </div>
          </div>
        )}
      </div>
    </section>);

};
// Section 5: Horizontal swipeable carousel
const Carousel = () => {
  const reviews = [
  { user: 'maya.k', show: 'Charli XCX · O2 Academy', stars: 5, txt: 'Brat summer is real and it lives in Brixton. Sweat dripped from the ceiling.', tag: 'Pop' },
  { user: 'denislav', show: 'Fred again.. · Berghain', stars: 5, txt: 'Six hours felt like six minutes. He played the WhatsApp voice memo. I cried.', tag: 'Electronic' },
  { user: 'p.rivera', show: 'Black Country, New Road', stars: 4, txt: 'New material slaps. Missed the old songs but trust the process.', tag: 'Indie' },
  { user: 'jules', show: 'Sault · Secret venue', stars: 5, txt: 'Anonymous, unannounced, unforgettable. Best £45 I\'ve ever spent.', tag: 'R&B' },
  { user: 'theo.x', show: 'Overmono · Warehouse Project', stars: 5, txt: 'So Em Dub at 2am with strobes. Religious experience for the bass-pilled.', tag: 'Electronic' }];

  return (
    <section style={{ padding: '80px 0 0' }}>
      <div style={{ padding: '0 var(--pad)' }}>
        <h2 className="section-title" style={{ marginBottom: 24 }}>
          Tonight's reviews.
        </h2>
      </div>
      <div className="no-scrollbar" style={{
        display: 'flex',
        gap: 14,
        overflowX: 'auto',
        scrollSnapType: 'x mandatory',
        padding: '24px var(--pad) 12px',
        WebkitOverflowScrolling: 'touch'
      }}>
        {reviews.map((r, i) =>
        <article key={i} style={{
          flex: '0 0 280px',
          scrollSnapAlign: 'start',
          background: i === 0 ? 'linear-gradient(160deg, #6444FF 0%, #3A1FB8 100%)' : 'var(--surface)',
          border: '1px solid ' + (i === 0 ? 'transparent' : 'var(--line)'),
          borderRadius: 32,
          padding: 20,
          display: 'flex', flexDirection: 'column',
          minHeight: 320
        }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
              <span className="mono" style={{
              fontSize: 10, letterSpacing: '0.12em',
              padding: '4px 10px', borderRadius: 999,
              background: 'rgba(255,255,255,0.12)',
              color: i === 0 ? '#fff' : 'var(--muted)'
            }}>#{r.tag.toUpperCase()}</span>
              <div style={{ display: 'flex', gap: 1 }}>
                {[1, 2, 3, 4, 5].map((s) =>
              <span key={s} style={{
                color: s <= r.stars ? i === 0 ? '#fff' : 'var(--brand-soft)' : 'var(--dim)',
                fontSize: 13
              }}>★</span>
              )}
              </div>
            </div>
            <h3 className="display" style={{
            fontSize: 22, lineHeight: 1.1, margin: '0 0 12px',
            color: '#fff', fontWeight: 600
          }}>{r.show}</h3>
            <p style={{
            fontSize: 14, lineHeight: 1.45, color: i === 0 ? 'rgba(255,255,255,0.85)' : 'var(--muted)',
            margin: '0 0 auto', flex: 1
          }}>"{r.txt}"</p>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 20, paddingTop: 16, borderTop: '1px solid ' + (i === 0 ? 'rgba(255,255,255,0.2)' : 'var(--line)') }}>
              <div className="ph" style={{ width: 28, height: 28, borderRadius: 999, padding: 0 }} />
              <span style={{ fontSize: 13, fontWeight: 500 }}>@{r.user}</span>
            </div>
          </article>
        )}
        <div style={{ flex: '0 0 4px' }} />
      </div>
    </section>);

};

// Section 6: Stats strip
const Stats = () => {
  const stats = [
  { num: '2.4M', label: 'Shows rated' },
  { num: '180K', label: 'Active fans' },
  { num: '14K', label: 'Venues mapped' },
  { num: '4.9★', label: 'App store' }];

  return (
    <section style={{ padding: '80px var(--pad) 0' }}>
      <div style={{
        display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 0,
        border: '1px solid var(--line)', borderRadius: 32,
        overflow: 'hidden',
        background: 'var(--surface)'
      }}>
        {stats.map((s, i) =>
        <div key={i} style={{
          padding: '28px 20px',
          borderRight: i % 2 === 0 ? '1px solid var(--line)' : 'none',
          borderBottom: i < 2 ? '1px solid var(--line)' : 'none'
        }}>
            <div className="display" style={{
            fontSize: 36, fontWeight: 700, letterSpacing: '-0.03em',
            color: 'var(--brand-soft)', lineHeight: 1
          }}>{s.num}</div>
            <div className="mono" style={{
            fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase',
            color: 'var(--dim)', marginTop: 8
          }}>{s.label}</div>
          </div>
        )}
      </div>
    </section>);

};

const AboutUs = () =>
<section className="about-section" style={{ padding: '40px var(--pad)', textAlign: 'center', maxWidth: 680, margin: '0 auto' }}>
  <h2 className="section-title" style={{ margin: '0 0 16px' }}>About Us</h2>
  <p style={{ color: 'var(--muted)', fontSize: 'clamp(14px, 1.5vw, 18px)', lineHeight: 1.7, margin: 0 }}>
  Two friends who've been to enough shows to know that the experience doesn't end when the lights come on, it just moves to the notes, photo albums, the group chat. We built Tracklist to give some of our favorite memories a proper home.
  </p>
</section>;

// ── App Store ratings & reviews ──
const Stars = ({ count = 5 }) => (
  <span style={{ display: 'inline-flex', gap: 1, color: '#FFB300', fontSize: 13, letterSpacing: 0 }} aria-label={`${count} out of 5 stars`}>
    {Array.from({ length: 5 }).map((_, i) => (
      <span key={i} style={{ opacity: i < count ? 1 : 0.18 }}>★</span>
    ))}
  </span>
);

const ReviewCard = ({ title, stars, date, author, body }) => (
  <div style={{
    background: 'var(--surface)',
    border: '1px solid var(--line)',
    borderRadius: 18,
    padding: '20px 22px',
    display: 'flex',
    flexDirection: 'column',
    gap: 10,
    textAlign: 'left',
    minHeight: 180,
  }}>
    <div style={{ display: 'flex', justifyContent: 'space-between', gap: 12, alignItems: 'flex-start' }}>
      <div style={{ flex: 1 }}>
        <h3 style={{
          margin: 0,
          fontFamily: "'Unbounded', sans-serif",
          fontSize: 15,
          fontWeight: 600,
          letterSpacing: '-0.01em',
          color: 'var(--text)',
          lineHeight: 1.3,
        }}>{title}</h3>
        <div style={{ marginTop: 6 }}><Stars count={stars} /></div>
      </div>
      <div style={{ textAlign: 'right', flexShrink: 0 }}>
        <div className="mono" style={{ fontSize: 11, color: 'var(--muted)' }}>{date}</div>
        <div className="mono" style={{ fontSize: 11, color: 'var(--dim)', marginTop: 2 }}>{author}</div>
      </div>
    </div>
    <p style={{
      margin: 0,
      color: 'var(--muted)',
      fontSize: 14,
      lineHeight: 1.55,
    }}>{body}</p>
  </div>
);

const Testimonials = () => (
  <section style={{ padding: '48px var(--pad)', maxWidth: 880, margin: '0 auto' }}>
    <div style={{ textAlign: 'center', marginBottom: 28 }}>
      <h2 className="section-title" style={{ margin: '0 0 24px' }}>Reviews</h2>
      <div style={{ display: 'inline-flex', alignItems: 'center', gap: 14 }}>
        <span style={{
          fontFamily: "'Unbounded', sans-serif",
          fontWeight: 600,
          fontSize: 'clamp(40px, 6vw, 64px)',
          letterSpacing: '-0.02em',
          color: '#fff',
          lineHeight: 1,
        }}>5.0</span>
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: 6 }}>
          <Stars count={5} />
          <span style={{ fontSize: 12, color: 'var(--muted)' }}>11 Ratings on the App Store</span>
        </div>
      </div>
    </div>
    <div style={{
      display: 'grid',
      gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))',
      gap: 14,
    }}>
      <ReviewCard
        title="Love the new Coachella feature!"
        stars={5}
        date="Apr 29"
        author="Triii"
        body="Looking forward to more updates, and looking to make it so that some of my past events can be added to the database in the future"
      />
      <ReviewCard
        title="Awesome app to review music events"
        stars={5}
        date="6d ago"
        author="BadBoiBwy"
        body="Reviewing is fun and I like that we can add pictures and videos! When adding videos though, is there a way to show a buffer circle while they load? Thanks!"
      />
    </div>
  </section>
);

// ── Scrapbook shape utilities (ported from scrapbook/src/Scrapbook.tsx) ──

function _mulberry32(a) {
  return function() {
    a |= 0; a = (a + 0x6d2b79f5) | 0;
    let t = Math.imul(a ^ (a >>> 15), 1 | a);
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}
function _jaggedEdge(x1, y1, x2, y2, segs, jitter, rand) {
  const dx = x2-x1, dy = y2-y1, len = Math.hypot(dx,dy)||1;
  const nx = -dy/len, ny = dx/len, pts = [];
  for (let i = 1; i < segs; i++) {
    const t = i/segs + ((rand()-0.5)*0.5)/segs;
    const big = rand() < 0.12 ? 2.2 : 1;
    const off = (rand()-0.5)*2*jitter*big;
    pts.push([x1+dx*t+nx*off, y1+dy*t+ny*off]);
  }
  return pts;
}
function _toPath(pts) {
  return pts.map((p,i) => `${i===0?'M':'L'} ${p[0].toFixed(2)} ${p[1].toFixed(2)}`).join(' ') + ' Z';
}
function _tornRect(w, h, j, seed, segs=22) {
  const r = _mulberry32(seed);
  return _toPath([[0,0], ..._jaggedEdge(0,0,w,0,segs,j.top,r), [w,0],
    ..._jaggedEdge(w,0,w,h,segs,j.right,r), [w,h],
    ..._jaggedEdge(w,h,0,h,segs,j.bottom,r), [0,h],
    ..._jaggedEdge(0,h,0,0,segs,j.left,r)]);
}
function _tornQuad(corners, jitter, seed, segs=20) {
  const r = _mulberry32(seed), all = [];
  for (let i = 0; i < corners.length; i++) {
    const a = corners[i], b = corners[(i+1)%corners.length];
    all.push(a); all.push(..._jaggedEdge(a[0],a[1],b[0],b[1],segs,jitter,r));
  }
  return _toPath(all);
}
function _tornBlob(cx, cy, baseR, segs, jitter, seed, lobes) {
  const r = _mulberry32(seed), pts = [];
  for (let i = 0; i < segs; i++) {
    const ang = (i/segs)*Math.PI*2;
    let rad = baseR;
    if (lobes) rad += Math.sin(ang*lobes.count+(lobes.phase||0))*lobes.depth;
    rad += (r()-0.5)*2*jitter;
    pts.push([cx+Math.cos(ang)*rad, cy+Math.sin(ang)*rad]);
  }
  return _toPath(pts);
}

const TORN_SHAPES = {
  rectSoft:   { vbW:400, vbH:300, path: _tornRect(400,300,{top:5,right:5,bottom:5,left:5},101) },
  rectRough:  { vbW:400, vbH:300, path: _tornRect(400,300,{top:14,right:14,bottom:14,left:14},102,26) },
  stripWide:  { vbW:600, vbH:200, path: _tornRect(600,200,{top:9,right:9,bottom:9,left:9},103,28) },
  stripTall:  { vbW:200, vbH:600, path: _tornRect(200,600,{top:9,right:9,bottom:9,left:9},104,28) },
  square:     { vbW:400, vbH:400, path: _tornRect(400,400,{top:8,right:8,bottom:8,left:8},105,24) },
  tornBottom: { vbW:400, vbH:320, path: _tornRect(400,320,{top:2,right:3,bottom:18,left:3},106,26) },
  tornTop:    { vbW:400, vbH:320, path: _tornRect(400,320,{top:18,right:3,bottom:2,left:3},107,26) },
  slanted:    { vbW:400, vbH:320, path: _tornQuad([[10,18],[395,0],[380,305],[0,285]],8,108,22) },
  flower:     { vbW:400, vbH:400, path: _tornBlob(200,200,150,96,4,109,{count:5,depth:36,phase:-Math.PI/2}) },
  circle:     { vbW:400, vbH:400, path: _tornBlob(200,200,175,80,7,110) },
  blob:       { vbW:420, vbH:360, path: _tornBlob(210,180,155,84,6,111,{count:3,depth:22,phase:0.6}) },
  diamond:    { vbW:400, vbH:400, path: _tornQuad([[200,10],[390,200],[200,390],[10,200]],7,112,20) },
};

const TornFrame = ({ src, shapeName, rotation = 0 }) => {
  const shape = TORN_SHAPES[shapeName];
  const PAD = 24;
  const vbW = shape.vbW + PAD * 2;
  const vbH = shape.vbH + PAD * 2;
  // CSS mask for the <img> — stays cached, no flash on scroll
  const maskSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${-PAD} ${-PAD} ${vbW} ${vbH}"><path d="${shape.path}" fill="white"/></svg>`;
  const maskUrl = `url("data:image/svg+xml,${encodeURIComponent(maskSvg)}")`;
  const maskStyle = {
    WebkitMaskImage: maskUrl, maskImage: maskUrl,
    WebkitMaskSize: '100% 100%', maskSize: '100% 100%',
    WebkitMaskRepeat: 'no-repeat', maskRepeat: 'no-repeat',
  };
  return (
    <div style={{
      position: 'relative',
      aspectRatio: `${vbW}/${vbH}`,
      transform: rotation ? `rotate(${rotation}deg)` : undefined,
      filter: 'drop-shadow(0 8px 16px rgba(0,0,0,0.28)) drop-shadow(0 2px 4px rgba(0,0,0,0.18))',
    }}>
      {/* SVG draws only the white paper border — no <image> so no flash */}
      <svg viewBox={`${-PAD} ${-PAD} ${vbW} ${vbH}`}
        style={{ position:'absolute', inset:0, width:'100%', height:'100%', display:'block' }}>
        <path d={shape.path} fill="#fdfcf7" stroke="#fdfcf7" strokeWidth={14} strokeLinejoin="round"/>
      </svg>
      {/* Regular <img> with CSS mask — cached properly by browser */}
      {src
        ? <img src={src} loading="eager" decoding="async"
            style={{ position:'absolute', inset:0, width:'100%', height:'100%', objectFit:'cover', ...maskStyle }} />
        : <div style={{ position:'absolute', inset:0, background:'#1B1B24', ...maskStyle }} />
      }
    </div>
  );
};

// ── Scrapbook section ─────────────────────────────────────────────────────
// Each photo is independently positioned. Adjust top/left/width/rotation/shape per photo.
// Available shapes: rectSoft, rectRough, stripWide, stripTall, square,
//                   tornBottom, tornTop, slanted, flower, circle, blob, diamond

const Scrapbook = () => {
  // Available shapes: rectSoft, tornTop, tornBottom, slanted, flower, blob, circle, square
  // Each photo: adjust top/left/width/rotation/shape independently

  const mobilePhotos = [
    { src: 'uploads/friends4.JPG',       shape: 'square',   width: '44%', rotation: -5, top: 0, left:  5, z: 5 },
    { src: 'uploads/friends7.jpg',  shape: 'rectRough',  width: '52%', rotation:  4, top:  2, left: 40, z: 4 },
    { src: 'uploads/friends8.JPG',    shape: 'rectSoft', width: '48%', rotation: 3, top:  29, left:  2, z: 6 },
    { src: 'uploads/friends6.JPG',       shape: 'rectSoft', width: '46%', rotation:  -2, top: 31, left: 44, z: 2 },
    { src: 'uploads/carol_portola.JPG',       shape: 'rectSoft', width: '46%', rotation: -2, top: 56, left:  4, z: 6 },
    { src: 'uploads/amy_portola.JPG',       shape: 'tornTop',  width: '50%', rotation:  4, top: 55, left: 43, z: 1 },
  ];
    const desktopPhotos = [
    { src: 'uploads/amy_portola.JPG',      shape: 'rectSoft',   width: '34%', rotation: -4, top:  6, left: 4, z: 6 },
    { src: 'uploads/carol_portola.JPG',      shape: 'slanted',    width: '38%', rotation:  6, top:  0, left: 31, z: 7 },
    { src: 'uploads/friends4.JPG',      shape: 'square',     width: '36%', rotation: -5, top:  4, left: 60, z: 1 },
    { src: 'uploads/friends6.JPG',      shape: 'rectSoft',     width: '34%', rotation:  2, top: 46, left: 6, z: 4 },
    { src: 'uploads/friends7.jpg', shape: 'rectSoft',   width: '36%', rotation: -2, top: 42, left: 32, z: 8},
    { src: 'uploads/friends8.JPG', shape: 'tornTop',    width: '32%', rotation: 1.5, top: 48, left: 63, z: 5 },
  ];
  const renderPhotos = (photos) => photos.map((p, i) =>
    <div key={i} style={{ position:'absolute', top:`${p.top}%`, left:`${p.left}%`, width:p.width, zIndex:p.z, willChange:'transform' }}>
      <TornFrame src={p.src} shapeName={p.shape} rotation={p.rotation} />
    </div>
  );

  return (
    <section className="scrapbook-section">
      <div className="scrapbook-mobile-wrap">{renderPhotos(mobilePhotos)}</div>
      <div className="scrapbook-desktop-wrap">{renderPhotos(desktopPhotos)}</div>
    </section>
  );
};
Object.assign(window, { Hero, Marquee, ParallaxGrid, PinnedFade, Carousel, Stats, AboutUs, Scrapbook, Testimonials });