/* global React, Icon, WORK, JOURNAL, TEAM, CLIENT_LOGOS, Hero, ClientStrip, WorkIndex, WorkGrid, SectionHead, ServicesAccordion, ProcessBand, StudioSplit, Testimonial, Principles, CtaBanner, MegaFooter */
const { useState, useEffect, useRef } = React;

// ===================================================================
// Home Page
// ===================================================================
function HomePage({ onGoto, heroVariant, workSlug }) {
  // `filter` holds either a type label ('All', 'Commercial', ...) or a
  // client-pinned filter encoded as 'client:<ClientName>' — the latter is
  // only set by clicking a logo in the ClientStrip and disappears when the
  // user picks any standard chip. State is component-local, so navigating
  // away and back resets it.
  const [filter, setFilter] = useState('All');
  const filters = ['All', 'Commercial', 'Brand Videos', 'Social Content', 'Live Events'];
  const clientFilter = filter.startsWith('client:') ? filter.slice(7) : null;
  const filtered = filter === 'All'
    ? WORK
    : clientFilter
      ? WORK.filter((w) => w.client === clientFilter)
      : WORK.filter((w) => w.type === filter);

  // Logo click → pin filter to that client and bring the work grid into
  // view. We scroll to the W—00 section header (not the filter row) so the
  // filter chiplets — including the just-pinned logo — land below the fold
  // of the heading rather than at the very top of the viewport. The
  // section's intrinsic padding-top (96px) already clears the fixed nav.
  const onSelectClient = (client) => {
    setFilter(`client:${client}`);
    const headEl = document.querySelector('.section-head');
    if (headEl) headEl.scrollIntoView({ block: 'start', behavior: 'smooth' });
  };

  return (
    <main className="page active" data-screen-label="01 Home">
      <Hero variant={heroVariant} onGoto={onGoto} />
      <ClientStrip onSelectClient={onSelectClient} />

      <div className="container">
        <SectionHead
          idx="W—00"
          label="Selected work"
          title="Brand stories, <em>cinematically</em><br/>told." />

        <div className="filters">
          {filters.map((f) =>
          <button key={f} className={`filter-chip ${filter === f ? 'active' : ''}`} onClick={() => setFilter(f)} data-hover="Filter">{f}</button>
          )}
          {clientFilter && (
            <button
              className="filter-chip filter-chip-client active"
              onClick={() => setFilter(`client:${clientFilter}`)}
              data-hover="Filter"
              aria-label={`Filter by ${clientFilter}`}>
              {clientFilter}
            </button>
          )}
        </div>
        <WorkGrid items={filtered} workSlug={workSlug} />
      </div>

      <StudioSplit onGoto={onGoto} />
      <Testimonial />
      <CtaBanner onGoto={onGoto} />
      <MegaFooter onGoto={onGoto} />
    </main>);

}

// ===================================================================
// (Work page removed — work content lives on the Home page)
// ===================================================================

// ===================================================================
// Services Page
// ===================================================================
function ServicesPage({ onGoto }) {
  return (
    <main className="page active" data-screen-label="03 Services">
      <section style={{ padding: '160px 0 0', position: 'relative', overflow: 'hidden' }}>
        <div style={{ position: 'absolute', width: 900, height: 900, borderRadius: '50%', filter: 'blur(120px)', background: 'radial-gradient(circle, var(--vf-blue-800) 0%, transparent 70%)', opacity: 0.4, right: -200, top: -300, pointerEvents: 'none' }} />
        <div className="container" style={{ position: 'relative' }}>
          <div className="eyebrow"><span className="idx">VF—02</span> What we make</div>
          <h1 style={{ fontSize: 'clamp(64px, 9vw, 144px)', fontWeight: 700, letterSpacing: '-0.04em', lineHeight: 0.95, marginTop: 24, textWrap: 'balance', maxWidth: 1100 }}>
            Four <em style={{ fontStyle: 'italic', color: 'var(--vf-blue-400)', fontWeight: 500 }}>ways</em> we'd love to make work with you.
          </h1>
          <p style={{ fontSize: 19, color: 'rgba(255,255,255,0.75)', marginTop: 24, maxWidth: 620, lineHeight: 1.5 }}>
            Most engagements start with a 30-minute call and a one-page response — we won't quote until we understand the brief.
          </p>
        </div>
      </section>

      <div className="container" style={{ marginTop: 80 }}>
        <ServicesAccordion />
      </div>

      <ProcessBand />
      <MegaFooter onGoto={onGoto} />
    </main>);

}

// ===================================================================
// About Page
// ===================================================================
function AboutPage({ onGoto }) {
  return (
    <main className="page active about-light" data-screen-label="04 About">
      <section className="about-hero">
        <div className="blob" />
        <div className="container">
          <div className="about-hero-grid">
            <div>
              <div className="eyebrow"><span className="idx">VF—03</span> About the studio</div>
              <h1>A small team, <em>obsessive</em> about the craft.</h1>
            </div>
            <div className="right">
              <p>Valley Films is a boutique production company in Acton, West London. We make creative corporate and commercial video for brands and agencies — from product films and brand documentaries to music videos and live events.</p>
              <p>The studio is built on a deliberate combination — the sophistication of high-budget commercial production with the flexibility and economics of a compact crew. Fewer people on set, more attention on the work.</p>
              <p>"Detail driven" isn't a tagline; it's the rhythm of every shoot day. Lighting that earns its frame. Audio that disappears. A grade that supports the story rather than performs over it.</p>
            </div>
          </div>
        </div>
      </section>

      <div className="container">
        <div className="about-img-strip">
          <div className="img img-1" style={{ backgroundImage: 'url(assets/bts-camera-portrait.jpg)' }} />
          <div className="img img-2" style={{ backgroundImage: 'url(assets/bts-studio-set.jpg)' }} />
          <div className="img img-3" style={{ backgroundImage: 'url(assets/bts-bookshelf.jpg)' }} />
        </div>
      </div>

      <Principles />

      <TeamSection />

      <MegaFooter onGoto={onGoto} />
    </main>);

}

// ===================================================================
// Team section — hover for bio peek, click for expanded view
// ===================================================================
function TeamSection() {
  const [hovered, setHovered] = useState(null);
  const [openIdx, setOpenIdx] = useState(null);
  const closeTimer = useRef(null);

  // ESC closes modal; lock scroll while open; trap focus inside modal
  useEffect(() => {
    if (openIdx === null) return;
    const FOCUSABLE = 'a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"]), input, textarea, select';
    const onKey = (e) => {
      if (e.key === 'Escape') { setOpenIdx(null); return; }
      if (e.key !== 'Tab') return;
      const modal = document.querySelector('.team-modal');
      if (!modal) return;
      const items = [...modal.querySelectorAll(FOCUSABLE)].filter(el => !el.hidden && el.offsetParent !== null);
      if (!items.length) return;
      const first = items[0], last = items[items.length - 1];
      if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
      else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
    };
    window.addEventListener('keydown', onKey);
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    // Move focus into modal
    const focusInModal = setTimeout(() => {
      const closeBtn = document.querySelector('.team-modal .team-modal-close');
      closeBtn && closeBtn.focus();
    }, 0);
    return () => {
      clearTimeout(focusInModal);
      window.removeEventListener('keydown', onKey);
      document.body.style.overflow = prev;
    };
  }, [openIdx]);

  const onEnter = (i) => {
    if (closeTimer.current) clearTimeout(closeTimer.current);
    setHovered(i);
  };
  const onLeave = () => {
    if (closeTimer.current) clearTimeout(closeTimer.current);
    closeTimer.current = setTimeout(() => setHovered(null), 80);
  };

  return (
    <React.Fragment>
      <section className="team-section">
        <div className="container">
          <div className="team-layout">
            <aside className="team-rail">
              <div className="rail-eyebrow"><span className="idx">T—00</span> The team</div>
              <h2 className="rail-title">Three people. Same project, <em>start</em> to master.</h2>
              <p className="rail-lede">Director, DOP, producer. Usually three or four hands from brief to master. The people who shape the brief are the ones who finish the film.</p>
              <dl className="rail-stats">
                <div><dt>Founded</dt><dd>2018, Christchurch NZ</dd></div>
                <div><dt>Headcount</dt><dd>3 staff, 10+ freelancers</dd></div>
              </dl>
            </aside>

            <div className="team-stack">
              {TEAM.map((t, i) => {
                const isHover = hovered === i;
                const facts = t.facts || [];
                return (
                  <article
                    key={t.name}
                    className={`tm-card${isHover ? ' is-hovered' : ''}`}
                    onMouseEnter={() => onEnter(i)}
                    onMouseLeave={onLeave}
                    onFocus={() => onEnter(i)}
                    onBlur={onLeave}
                    onClick={() => setOpenIdx(i)}
                    tabIndex={0}
                    role="button"
                    aria-label={`Open profile for ${t.name}`}
                    onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setOpenIdx(i); } }}
                  >
                    <div className="tm-photo">
                      <div className="tm-photo-img" role="img" aria-label={`${t.name}, ${t.role}`} style={{ backgroundImage: `url(${t.img})` }} />
                      <img className="tm-photo-srfb" src={t.img} alt="" aria-hidden="true" loading="lazy" />
                      <div className="tm-photo-shade" />
                      <span className="tm-idx">T—{String(i + 1).padStart(2, '0')}</span>
                      <span className="tm-open">
                        <svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" strokeWidth="2.4"><path d="M7 17 17 7M9 7h8v8" strokeLinecap="round" strokeLinejoin="round"/></svg>
                        Full profile
                      </span>
                    </div>

                    <div className="tm-body">
                      <header className="tm-head">
                        <h3 className="tm-name">{t.name}</h3>
                        <div className="tm-role">{t.role}</div>
                      </header>

                      <div className="tm-reveal" aria-hidden={!isHover}>
                        <div className="tm-reveal-row tm-spec">
                          <span className="lbl">Focus</span>
                          <span className="val">{t.specialty}</span>
                        </div>
                        <div className="tm-reveal-row tm-sig">
                          <span className="lbl">Signature</span>
                          <span className="val">{t.signature}</span>
                        </div>
                        <dl className="tm-facts">
                          {facts.slice(0, 4).map((f, k) => (
                            <div key={k} style={{ '--d': `${k * 40}ms` }}>
                              <dt>{f.k}</dt>
                              <dd>{f.v}</dd>
                            </div>
                          ))}
                        </dl>
                      </div>

                      <footer className="tm-foot">
                        <span className="tm-loc">{t.years}</span>
                        <span className="tm-arrow" aria-hidden="true">
                          <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2"><path d="M5 12h14M13 5l7 7-7 7" strokeLinecap="round" strokeLinejoin="round"/></svg>
                        </span>
                      </footer>
                    </div>
                  </article>
                );
              })}
            </div>
          </div>
        </div>
      </section>

      {/* Expanded modal */}
      {openIdx !== null && (
        <div className="team-modal-scrim" onClick={() => setOpenIdx(null)}>
          <div
            className="team-modal"
            role="dialog"
            aria-modal="true"
            aria-label={TEAM[openIdx].name}
            onClick={(e) => e.stopPropagation()}
          >
            <button className="team-modal-close" onClick={() => setOpenIdx(null)} aria-label="Close">
              <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2"><path d="M6 6l12 12M18 6 6 18" strokeLinecap="round"/></svg>
            </button>

            <div className="team-modal-photo" role="img" aria-label={TEAM[openIdx].name} style={{ backgroundImage: `url(${TEAM[openIdx].img})` }}>
              <div className="team-modal-photo-meta">
                <span className="idx">T—{String(openIdx + 1).padStart(2, '0')}</span>
                <span>{TEAM[openIdx].years} in craft</span>
              </div>
            </div>

            <div className="team-modal-body">
              <div className="eyebrow"><span className="idx">T—{String(openIdx + 1).padStart(2, '0')}</span> {TEAM[openIdx].role}</div>
              <h2>{TEAM[openIdx].name}</h2>

              <div className="modal-bio">
                {TEAM[openIdx].bio.map((p, k) => <p key={k}>{p}</p>)}
              </div>

              <div className="modal-credits">
                <div className="credits-label">Selected credits</div>
                <ul>
                  {TEAM[openIdx].credits.map((c) => <li key={c}>{c}</li>)}
                </ul>
              </div>

              <div className="modal-foot">
                <a className="modal-mail" href={`mailto:${TEAM[openIdx].contact}`}>{TEAM[openIdx].contact}</a>
                <div className="modal-nav">
                  <button onClick={() => setOpenIdx((openIdx - 1 + TEAM.length) % TEAM.length)} aria-label="Previous">
                    <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2"><path d="M19 12H5M12 5l-7 7 7 7" strokeLinecap="round" strokeLinejoin="round"/></svg>
                    Prev
                  </button>
                  <span className="counter">{openIdx + 1} / {TEAM.length}</span>
                  <button onClick={() => setOpenIdx((openIdx + 1) % TEAM.length)} aria-label="Next">
                    Next
                    <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2"><path d="M5 12h14M13 5l7 7-7 7" strokeLinecap="round" strokeLinejoin="round"/></svg>
                  </button>
                </div>
              </div>
            </div>
          </div>
        </div>
      )}
    </React.Fragment>
  );
}

// ===================================================================
// Journal Page
// ===================================================================
function JournalPage({ onGoto }) {
  return (
    <main className="page active" data-screen-label="05 Journal">
      <section style={{ padding: '160px 0 0', position: 'relative', overflow: 'hidden' }}>
        <div className="container">
          <div className="eyebrow"><span className="idx">VF—05</span> Journal & field notes</div>
          <h1 style={{ fontSize: 'clamp(56px, 7vw, 120px)', fontWeight: 700, letterSpacing: '-0.035em', lineHeight: 0.95, marginTop: 24, maxWidth: 1100, textWrap: 'balance' }}>
            Notes from <em style={{ fontStyle: 'italic', color: 'var(--vf-blue-400)', fontWeight: 500 }}>set</em>, the cutting room, and our process.
          </h1>
        </div>
      </section>

      <div className="container" style={{ marginTop: 80 }}>
        <div className="journal-grid">
          {JOURNAL.map((j) =>
          <div key={j.id} className="journal-card" data-hover="Read">
              <div className="cover">
                <div className="cover-inner" style={{ backgroundImage: `url(${j.img})` }} />
              </div>
              <div className="meta">
                <span className="cat">{j.cat}</span>
                <span>·</span>
                <span>{j.date}</span>
                <span>·</span>
                <span>{j.read}</span>
              </div>
              <h3>{j.title}</h3>
            </div>
          )}
        </div>
      </div>

      <CtaBanner onGoto={onGoto} />
      <MegaFooter onGoto={onGoto} />
    </main>);

}

// ===================================================================
// UK business-hours status — drives the green/red dot on the contact form.
//
// Open Mon–Fri 09:00–17:00 Europe/London, excluding England & Wales bank
// holidays. Bank holidays are computed (not hardcoded) so the list stays
// correct without yearly maintenance: Easter via the Anonymous Gregorian
// Computus, May/August bank holidays via first/last Monday of the month,
// and New Year's / Christmas / Boxing with the standard weekend-substitute
// rules.
// ===================================================================
function _easterSunday(year) {
  const a = year % 19;
  const b = Math.floor(year / 100);
  const c = year % 100;
  const d = Math.floor(b / 4);
  const e = b % 4;
  const f = Math.floor((b + 8) / 25);
  const g = Math.floor((b - f + 1) / 3);
  const h = (19 * a + b - d - g + 15) % 30;
  const i = Math.floor(c / 4);
  const k = c % 4;
  const L = (32 + 2 * e + 2 * i - h - k) % 7;
  const m = Math.floor((a + 11 * h + 22 * L) / 451);
  const month = Math.floor((h + L - 7 * m + 114) / 31);
  const day = ((h + L - 7 * m + 114) % 31) + 1;
  return new Date(Date.UTC(year, month - 1, day));
}
function _firstMondayOfMonth(year, month) {
  for (let day = 1; day <= 7; day++) {
    const d = new Date(Date.UTC(year, month, day));
    if (d.getUTCDay() === 1) return d;
  }
}
function _lastMondayOfMonth(year, month) {
  const lastDay = new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
  for (let day = lastDay; day >= lastDay - 6; day--) {
    const d = new Date(Date.UTC(year, month, day));
    if (d.getUTCDay() === 1) return d;
  }
}
function _ymd(d) {
  return `${d.getUTCFullYear()}-${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`;
}
function _ukBankHolidays(year) {
  const dates = new Set();
  const nyd = new Date(Date.UTC(year, 0, 1));
  if (nyd.getUTCDay() === 6) dates.add(`${year}-01-03`);
  else if (nyd.getUTCDay() === 0) dates.add(`${year}-01-02`);
  else dates.add(_ymd(nyd));
  const easter = _easterSunday(year);
  dates.add(_ymd(new Date(easter.getTime() - 2 * 86400000)));
  dates.add(_ymd(new Date(easter.getTime() + 86400000)));
  dates.add(_ymd(_firstMondayOfMonth(year, 4)));
  dates.add(_ymd(_lastMondayOfMonth(year, 4)));
  dates.add(_ymd(_lastMondayOfMonth(year, 7)));
  const xmasDay = new Date(Date.UTC(year, 11, 25)).getUTCDay();
  if (xmasDay === 6) {
    dates.add(`${year}-12-27`);
    dates.add(`${year}-12-28`);
  } else if (xmasDay === 0) {
    dates.add(`${year}-12-26`);
    dates.add(`${year}-12-27`);
  } else if (xmasDay === 5) {
    dates.add(`${year}-12-25`);
    dates.add(`${year}-12-28`);
  } else {
    dates.add(`${year}-12-25`);
    dates.add(`${year}-12-26`);
  }
  return dates;
}
function _ukParts(date) {
  const fmt = new Intl.DateTimeFormat('en-GB', {
    timeZone: 'Europe/London',
    year: 'numeric', month: '2-digit', day: '2-digit',
    hour: '2-digit', minute: '2-digit', hour12: false,
    weekday: 'long',
  });
  const parts = Object.fromEntries(fmt.formatToParts(date).map((p) => [p.type, p.value]));
  const hour = parts.hour === '24' ? 0 : Number(parts.hour);
  return {
    year: Number(parts.year),
    month: Number(parts.month),
    day: Number(parts.day),
    hour,
    weekday: parts.weekday,
  };
}
function _ukBusinessStatus(now) {
  const p = _ukParts(now);
  const todayYmd = `${p.year}-${String(p.month).padStart(2, '0')}-${String(p.day).padStart(2, '0')}`;
  const isWeekend = p.weekday === 'Saturday' || p.weekday === 'Sunday';
  const isHoliday = _ukBankHolidays(p.year).has(todayYmd);
  const inHours = p.hour >= 9 && p.hour < 17;
  if (!isWeekend && !isHoliday && inHours) {
    return { open: true, label: "We're open, will respond very shortly." };
  }
  let cursor = new Date(Date.UTC(p.year, p.month - 1, p.day));
  for (let i = 0; i < 14; i++) {
    cursor = new Date(cursor.getTime() + 86400000);
    const cp = _ukParts(cursor);
    const cymd = `${cp.year}-${String(cp.month).padStart(2, '0')}-${String(cp.day).padStart(2, '0')}`;
    if (cp.weekday === 'Saturday' || cp.weekday === 'Sunday') continue;
    if (_ukBankHolidays(cp.year).has(cymd)) continue;
    const tomorrowMs = Date.UTC(p.year, p.month - 1, p.day) + 86400000;
    const cursorMs = Date.UTC(cp.year, cp.month - 1, cp.day);
    if (!isWeekend && cursorMs === tomorrowMs) {
      return { open: false, label: "We're closed for the day, we'll get back to you tomorrow." };
    }
    return { open: false, label: `We're closed, we'll get back to you on ${cp.weekday}.` };
  }
  return { open: false, label: "We're closed, we'll get back to you on the next working day." };
}

function ContactStatus() {
  const [now, setNow] = useState(() => new Date());
  useEffect(() => {
    const id = setInterval(() => setNow(new Date()), 60_000);
    return () => clearInterval(id);
  }, []);
  const status = _ukBusinessStatus(now);
  return (
    <p
      className={`desc desc-meta contact-status ${status.open ? 'is-open' : 'is-closed'}`}
      aria-live="polite">
      <span className="desc-dot" />
      {status.label}
    </p>
  );
}

// ===================================================================
// Contact Page (light theme)
// ===================================================================
function ContactPage({ onGoto }) {
  const [sent, setSent] = useState(false);
  const [sending, setSending] = useState(false);
  const [error, setError] = useState('');
  const [form, setForm] = useState({ name: '', company: '', email: '', type: 'Commercial', brief: '', honeypot: '' });
  const set = (k) => (e) => setForm({ ...form, [k]: e.target.value });

  // Continuous form-completion progress (0 → 1).
  // Weighted so the brief textarea drives the final third — bars fill out as
  // identity → contact → brief, mirroring the visual order.
  const progress = (() => {
    const has = (s) => (s || '').trim().length > 0;
    const emailOk = /\S+@\S+\.\S+/.test(form.email || '');
    const briefLen = (form.brief || '').trim().length;
    const briefScore = Math.min(1, briefLen / 80); // ~80 chars feels "filled"
    const parts = [
    has(form.name) ? 1 : 0,
    has(form.company) ? 1 : 0,
    emailOk ? 1 : has(form.email) ? 0.4 : 0,
    1, // project type always has a default
    briefScore];

    return parts.reduce((a, b) => a + b, 0) / parts.length;
  })();

  return (
    <main className="page active" data-screen-label="06 Contact">
      <section className="contact">
        <div className="container">
          <div>
            <div className="lt-eyebrow">Get in touch · VF—04</div>
            <h1>Ready to make an <em>impact?</em></h1>
            <p className="lead">Tell us about your project. We'll come back to you as soon as we can with thoughts, references and an honest sense of fit.</p>
            <div className="meta-block">
              <div className="meta-row">
                <div className="ico"><Icon name="pin" /></div>
                <div><div className="lbl">Studio</div><a className="val val-link" href="https://www.google.com/maps/search/?api=1&query=Access+House+207-211+The+Vale+Acton+London+W3+7QS" target="_blank" rel="noopener noreferrer">Access House, 207–211 The Vale,<br />Acton, London W3 7QS</a></div>
              </div>
              <div className="meta-row">
                <div className="ico"><Icon name="mail" /></div>
                <div><div className="lbl">Email</div><a className="val val-link" href="mailto:info@valley.film">info@valley.film</a></div>
              </div>
              <div className="meta-row">
                <div className="ico"><Icon name="phone" /></div>
                <div><div className="lbl">WhatsApp</div><a className="val val-link" href="https://wa.me/message/UI5I3PDWH5Q3N1" target="_blank" rel="noopener noreferrer">+44 7771 039043</a></div>
              </div>
              <div className="meta-row">
                <div className="ico"><Icon name="instagram" /></div>
                <div><div className="lbl">Instagram</div><a className="val val-link" href="https://instagram.com/rentals.valley" target="_blank" rel="noopener noreferrer">@rentals.valley</a></div>
              </div>
            </div>
          </div>

          <div className="form-card">
            {sent ?
            <div className="contact-sent">
                <div className="check"><Icon name="check" /></div>
                <h3>Thanks — that's with us.</h3>
                <p>We'll come back to you within two working days, in working hours UK. Reply to the email confirmation if anything urgent comes up.</p>
                <button className="btn-pri" style={{ marginTop: 24 }} onClick={() => setSent(false)} data-hover="New">Send another</button>
              </div> :

            <React.Fragment>
                <h3>Project enquiry</h3>
                <p className="desc">A few lines is plenty — we'll take it from there.</p>
                <ContactStatus />
                <div className="step-indicator" aria-hidden="true">
                  {[0, 1, 2].map((i) => {
                  // continuous progress: each bar fills as the user completes ~1/3 of the form
                  const segStart = i / 3;
                  const segEnd = (i + 1) / 3;
                  const fill = Math.max(0, Math.min(1, (progress - segStart) / (segEnd - segStart)));
                  return (
                    <div key={i} className={`dot ${fill > 0 ? 'filling' : ''}`}>
                        <span className="fill" style={{ transform: `scaleX(${fill})` }} />
                      </div>);

                })}
                </div>

                <div className="field-row">
                  <div className="field"><label>Your name</label><input value={form.name} onChange={set('name')} placeholder="Jordan Reeves" /></div>
                  <div className="field"><label>Company</label><input value={form.company} onChange={set('company')} placeholder="Company or brand" /></div>
                </div>
                <div className="field-row">
                  <div className="field"><label>Email</label><input type="email" value={form.email} onChange={set('email')} placeholder="jordan@brand.com" /></div>
                  <div className="field"><label>Project type</label>
                    <select value={form.type} onChange={set('type')}>
                      <option>Commercial</option>
                      <option>Brand Videos</option>
                      <option>Social Content</option>
                      <option>Live Events</option>
                      <option>Other</option>
                    </select>
                  </div>
                </div>

                <div className="field-row">
                  <div className="field full">
                    <label>Tell us about the project</label>
                    <textarea rows="4" value={form.brief} onChange={set('brief')} placeholder="A few lines about the brief, the audience, and any references that resonate." />
                  </div>
                </div>

                {/* Honeypot — hidden field. Real users leave it blank, bots fill it. */}
                <div aria-hidden="true" style={{ position: 'absolute', left: '-9999px', height: 0, overflow: 'hidden' }}>
                  <label>Don't fill this in <input type="text" tabIndex={-1} autoComplete="off" value={form.honeypot} onChange={set('honeypot')} /></label>
                </div>

                {error && <div className="form-error" role="alert">{error}</div>}

                <button className="submit" disabled={sending} onClick={async (e) => {
                  e.preventDefault();
                  setError('');
                  if (!form.name.trim() || !form.email.trim() || !form.brief.trim()) {
                    setError('Please fill in your name, email, and a few lines about the project.');
                    return;
                  }
                  if (!/^\S+@\S+\.\S+$/.test(form.email)) {
                    setError('That email doesn\'t look right — please double-check.');
                    return;
                  }
                  setSending(true);
                  try {
                    const resp = await fetch('/api/contact', {
                      method: 'POST',
                      headers: { 'Content-Type': 'application/json' },
                      body: JSON.stringify(form),
                    });
                    if (!resp.ok) throw new Error((await resp.json().catch(() => ({}))).error || 'Send failed');
                    setSent(true);
                  } catch (err) {
                    setError('Couldn\'t send right now — please email info@valley.film directly.');
                  } finally {
                    setSending(false);
                  }
                }} data-hover="Send">
                  {sending ? 'Sending…' : <>Send enquiry <Icon name="arrow-right" /></>}
                </button>
              </React.Fragment>
            }
          </div>
        </div>
      </section>
    </main>);

}

// ===================================================================
// Privacy Page (light theme) — template, edit copy as needed.
// ===================================================================
function PrivacyPage({ onGoto }) {
  return (
    <main className="page active privacy-light" data-screen-label="07 Privacy">
      <section className="privacy-page">
        <div className="container">
          <div className="lt-eyebrow">Legal · VF—06</div>
          <h1>Privacy notice</h1>
          <p className="lead">Valley Creative LTD ("Valley", "we", "us" or "our") is the data controller in respect of personal data processed through this website and in the course of providing production, rental and post-production services. This notice sets out how we collect, use, retain, share and protect that data, and explains the rights available to you under the UK General Data Protection Regulation ("UK GDPR") and the Data Protection Act 2018.</p>

          <p className="last-updated"><strong>Last updated:</strong> May 2026</p>

          <h2>1. Personal data we collect</h2>
          <p>We collect only the personal data necessary for the purposes for which it is processed. The categories of data collected are: (i) enquiry form data, comprising your name, company name, email address, project type and the contents of any brief, message or correspondence you elect to send via the form or by email; (ii) where you open an account with Valley Rentals, additional data comprising billing and payment details, copies of identity and address verification documents, and trade or financial references provided in support of the account application; and (iii) operational records arising in the ordinary course of providing our services, including correspondence, call notes, scheduling information and project documentation. We do not knowingly collect special category data within the meaning of Article 9 UK GDPR, and we do not collect personal data from children under the age of 16.</p>

          <h2>2. Legal basis for processing</h2>
          <p>We rely on one or more of the following lawful bases under Article 6(1) UK GDPR depending on the processing activity in question: performance of a contract or steps taken at your request prior to entering into a contract (Article 6(1)(b)); compliance with a legal obligation, including in respect of accounting, tax and anti-money-laundering record-keeping (Article 6(1)(c)); and our legitimate interests in operating, maintaining and developing our business, replying to enquiries received, and pursuing or defending legal claims, where such interests are not overridden by your interests, rights or freedoms (Article 6(1)(f)). Where we rely on your consent (Article 6(1)(a)), for example in respect of optional marketing communications which we do not send by default, you may withdraw that consent at any time by contacting us.</p>

          <h2>3. Purposes of processing</h2>
          <p>Personal data is processed solely for the following purposes: responding to enquiries received via the website, contact form or email; entering into and performing contracts for production services, equipment rental or post-production work; verifying the identity, creditworthiness and trade standing of prospective rental clients; communicating with clients, contractors and counterparties in the course of project delivery; complying with our legal, regulatory and tax obligations; and maintaining the security and integrity of our systems, records and premises. We do not engage in profiling, automated decision-making within the meaning of Article 22 UK GDPR, or behavioural advertising of any kind.</p>

          <h2>4. Retention</h2>
          <p>Personal data is retained for no longer than is necessary in light of the purpose for which it is processed and any applicable legal or regulatory minimum retention period. Enquiry-form data is retained for the duration of the enquiry and for a period of up to twelve (12) months thereafter, after which it is deleted unless a contractual relationship has been established. Rental account records, including identity, address verification and financial reference data, are retained for the duration of the account and for a period of six (6) years following its closure, in accordance with the record-keeping requirements of HM Revenue and Customs and the Limitation Act 1980. Operational project records are retained for the duration of the engagement and for such further period as is reasonably necessary in connection with the defence of legal claims or the discharge of professional obligations.</p>

          <h2>5. Recipients and sub-processors</h2>
          <p>Personal data may be disclosed to the following categories of recipient: our employees, contractors and freelance crew strictly on a need-to-know basis in connection with project delivery; our professional advisers, including accountants, auditors and legal counsel, where required for the discharge of professional obligations; and the third-party sub-processors set out below, each of which we have appointed by way of a written data processing agreement satisfying the requirements of Article 28 UK GDPR. The sub-processors currently engaged are: Vercel Inc. (website hosting, United States with EU presence); Resend Inc. (transactional email delivery for the enquiry form, United States); Booqable B.V. (rental cart and inventory management on the Rentals page, Netherlands); and Google LLC, by way of Google Workspace (email, calendar and document storage). Each sub-processor publishes its own privacy policy, to which we encourage you to refer.</p>

          <h2>6. International transfers</h2>
          <p>Where personal data is transferred to recipients outside the United Kingdom, we ensure that an appropriate transfer mechanism under Articles 44 to 49 UK GDPR is in place. Transfers to recipients in the United States are conducted on the basis of the UK International Data Transfer Addendum to the European Commission's Standard Contractual Clauses, or pursuant to the UK Extension to the EU-US Data Privacy Framework where the recipient is a certified participant. Transfers to recipients in the European Economic Area, including the Netherlands, rely on the United Kingdom's adequacy decision in respect of the EEA. Further information about the safeguards in place for any specific transfer is available on request.</p>

          <h2>7. Security</h2>
          <p>We maintain technical and organisational security measures appropriate to the nature, scope and purposes of our processing and to the risks presented to data subjects, including access controls, encryption in transit, segregation of operational and administrative systems, secure deletion of records on expiry of the relevant retention period, and contractual confidentiality obligations on all personnel and sub-processors. Notwithstanding these measures, no system of electronic or physical storage is impervious to compromise, and we cannot guarantee absolute security.</p>

          <h2>8. Cookies</h2>
          <p>This website does not use cookies for analytics, advertising, tracking or any other non-essential purpose, and does not deploy any third-party tracking technologies on the pages served from this domain. The Booqable rental widget embedded on the Rentals page may set strictly necessary functional cookies for the purpose of preserving the contents of your shopping cart between page loads; those cookies are managed by Booqable B.V. as data controller in respect of cart functionality and are governed by Booqable's own privacy policy.</p>

          <h2>9. Your rights</h2>
          <p>Under the UK GDPR you have the right to: request access to the personal data we hold about you (Article 15); request the rectification of inaccurate or incomplete data (Article 16); request the erasure of your data in the circumstances set out in Article 17; request restriction of processing (Article 18); receive your data in a structured, commonly used and machine-readable format and have it transmitted to another controller (Article 20); object to processing carried out on the basis of our legitimate interests (Article 21); and, where processing is based on consent, withdraw that consent at any time without affecting the lawfulness of processing carried out before withdrawal. Requests should be sent in writing to <a href="mailto:info@valley.film">info@valley.film</a> and will be acknowledged within seventy-two (72) hours and substantively responded to within one (1) month of receipt, subject to extension in accordance with Article 12(3) UK GDPR where the request is complex or where multiple requests have been received.</p>

          <h2>10. Complaints</h2>
          <p>If you believe that our processing of your personal data does not comply with applicable data protection law, you have the right to lodge a complaint with the Information Commissioner's Office, the supervisory authority for the United Kingdom, which can be contacted at <a href="https://ico.org.uk" target="_blank" rel="noopener noreferrer">ico.org.uk</a> or on 0303 123 1113. We would, however, appreciate the opportunity to address any concerns directly in the first instance, and ask that you contact us before approaching the regulator where this is reasonably practicable.</p>

          <h2>11. Updates to this notice</h2>
          <p>We may revise this notice from time to time to reflect changes in our processing activities, our sub-processor arrangements or applicable law. The version in force at any given time is the version published on this page, identified by the "Last updated" date set out at the head of this notice. Material changes affecting the lawful basis for processing or the categories of recipients will be drawn to the attention of affected data subjects by reasonable means.</p>

          <h2>12. Contact</h2>
          <p>The data controller for the purposes of this notice is Valley Creative LTD, of Access House, 207-211 The Vale, Acton, London W3 7QS, United Kingdom. All correspondence in respect of this notice, including the exercise of data subject rights, should be directed to <a href="mailto:info@valley.film">info@valley.film</a>, marked for the attention of the data protection contact.</p>
        </div>
      </section>
      <MegaFooter onGoto={onGoto} />
    </main>);
}

Object.assign(window, { HomePage, ServicesPage, AboutPage, JournalPage, ContactPage, PrivacyPage, ContactStatus });