/* ── Page sections ─────────────────────────────────────────────────────── */

/* ── Nav ─────────────────────────────────────────────────────────── */
function Nav() {
  const [scrolled, setScrolled] = React.useState(false);
  React.useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 12);
    window.addEventListener('scroll', onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener('scroll', onScroll);
  }, []);
  return (
    <nav className={'nav' + (scrolled ? ' scrolled' : '')}>
      <div className="wrap nav-inner">
        <div className="nav-mid">
          <ReeveWordmark size={30} />
        </div>
        <div className="nav-links">
          <a href="#model">Model</a>
          <a href="#product">Product</a>
          <a href="#vs">Why Reeve</a>
          <a href="#brand">For agents</a>
          <a href="#proof">Proof</a>
        </div>
        <div className="nav-cta">
          <a
            href="https://calendar.app.google/be3ib85HS3rDzJtr8"
            target="_blank"
            rel="noopener noreferrer"
            className="btn btn-primary"
          >
            Book a walkthrough
            <span className="arrow">→</span>
          </a>
        </div>
      </div>
    </nav>
  );
}

/* ── Hero ─────────────────────────────────────────────────────────── */
function Hero({ headline, sub }) {
  // Live work-order counter — increments by 1 at random intervals
  // between 3 seconds and 3 minutes. Persists across reloads via
  // localStorage; on load, extrapolates ticks that would have
  // happened while the page was closed using the average tick rate.
  const ORDER_STORAGE_KEY = 'reeve_work_orders';
  const AVG_TICK_MS = (3000 + 180000) / 2; // ≈ 91 500 ms
  const ORDER_BASE = 46496;
  const [orderCount, setOrderCount] = React.useState(() => {
    try {
      const raw = localStorage.getItem(ORDER_STORAGE_KEY);
      if (raw) {
        const saved = JSON.parse(raw);
        if (typeof saved.count === 'number' && typeof saved.ts === 'number') {
          const elapsed = Date.now() - saved.ts;
          const extra = Math.max(0, Math.floor(elapsed / AVG_TICK_MS));
          return saved.count + extra;
        }
      }
    } catch (e) {
      /* localStorage unavailable — fall back to base */
    }
    return ORDER_BASE;
  });
  // Persist on every change.
  React.useEffect(() => {
    try {
      localStorage.setItem(
        ORDER_STORAGE_KEY,
        JSON.stringify({ count: orderCount, ts: Date.now() })
      );
    } catch (e) { /* ignore */ }
  }, [orderCount]);
  // Live random ticks while the page is open.
  React.useEffect(() => {
    let timeoutId;
    const tick = () => {
      const delay = 3000 + Math.random() * (180000 - 3000);
      timeoutId = setTimeout(() => {
        setOrderCount((prev) => prev + 1);
        tick();
      }, delay);
    };
    tick();
    return () => clearTimeout(timeoutId);
  }, []);
  const formattedCount = orderCount.toLocaleString('en-GB');

  return (
    <>
      <section className="hero">
        <div className="wrap">
          <div className="hero-grid">
            <div className="hero-left">
              <h1 className="h-display fade-up d2" dangerouslySetInnerHTML={{ __html: headline }} />
              <p className="lede fade-up d3">{sub}</p>
              <div className="hero-ctas fade-up d4">
                <a
                  href="https://calendar.app.google/be3ib85HS3rDzJtr8"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="btn btn-primary"
                >
                  Book a walkthrough <span className="arrow">→</span>
                </a>
                <a href="#model" className="btn btn-ghost">See how Reeve works</a>
              </div>

              <div className="hero-stat fade-up d4">
                <div className="hero-stat-pair">
                  <div className="hero-stat-cell">
                    <div className="hero-stat-big">2.2<sub>d</sub></div>
                    <div className="hero-stat-cell-label">Reeve average</div>
                    <div className="hero-stat-cell-sub">Time to resolution</div>
                  </div>
                  <div className="hero-stat-vs">vs</div>
                  <div className="hero-stat-cell hero-stat-cell-muted">
                    <div className="hero-stat-big">19<sub>d</sub></div>
                    <div className="hero-stat-cell-label">Industry average</div>
                    <div className="hero-stat-cell-sub">For the sector</div>
                  </div>
                </div>
                <div className="hero-stat-foot">
                  Measured across <strong>{formattedCount} work orders</strong>.
                </div>
              </div>
            </div>

            <div className="hero-right">
              <HeroVisual />
            </div>
          </div>
        </div>
      </section>
      <DispatchLog />
    </>
  );
}

/* ── Dispatch log ─ scrolling status ticker, sits under the hero ── */
function DispatchLog() {
  const items = [
    { time: '08:14', ev: 'P1 lift fault',         loc: 'Lyle St SE1',        s: 'dispatched · 6 min' },
    { time: '08:08', ev: 'HVAC filter clean',     loc: 'Tower 9 EC2',        s: 'on site' },
    { time: '07:52', ev: 'Leak',                  loc: 'Greycote SW1',       s: 'resolved', ok: true },
    { time: '07:41', ev: 'CCTV system repair',    loc: 'Lambert WC1',        s: 'triage' },
    { time: '07:20', ev: 'Fire panel adjustment', loc: 'Westhall E1',        s: 'resolved', ok: true },
    { time: '07:02', ev: 'Deep clean required',   loc: 'Thirty-Three EC1',   s: 'dispatched · 12 min' },
    { time: '06:48', ev: 'Pest control service',  loc: 'Hyperion W1',        s: 'resolved', ok: true },
    { time: '06:31', ev: 'Shower descale',        loc: 'Curtain Road EC2',   s: 'on site' },
  ];
  // double for marquee seamless loop
  const loop = [...items, ...items];
  return (
    <div className="dispatch-log">
      <div className="wrap">
        <div className="dispatch-track">
          {loop.map((it, i) => (
            <span className="item" key={i}>
              <span className="time">{it.time}</span>
              <span className="ev">{it.ev}</span>
              <span>{it.loc}</span>
              <span className="sep">→</span>
              <span className={it.ok ? 'ok' : ''}>{it.s}</span>
            </span>
          ))}
        </div>
      </div>
    </div>
  );
}

/* ── Certifications strip ─ sits directly under the dispatch ticker ── */
function Certifications() {
  return (
    <section className="certs">
      <div className="wrap certs-row">
        <img
          src="assets/img/iso27001.png"
          alt="ISO 27001 certified"
          className="cert-img"
        />
        <svg
          width="72"
          height="72"
          viewBox="0 0 100 100"
          xmlns="http://www.w3.org/2000/svg"
          className="cert-bcorp"
          aria-label="Certified B Corporation"
        >
          <text x="50" y="14" textAnchor="middle" fontFamily="Inter Tight, ui-sans-serif, system-ui" fontSize="9" fontWeight="600" letterSpacing="0.5" fill="currentColor">
            CERTIFIED
          </text>
          <circle cx="50" cy="52" r="20" fill="none" stroke="currentColor" strokeWidth="2.6" />
          <text x="50" y="60" textAnchor="middle" fontFamily="Inter Tight, ui-sans-serif, system-ui" fontSize="26" fontWeight="700" fill="currentColor">
            B
          </text>
          <line x1="32" y1="80" x2="68" y2="80" stroke="currentColor" strokeWidth="1.4" />
          <text x="50" y="92" textAnchor="middle" fontFamily="Inter Tight, ui-sans-serif, system-ui" fontSize="9" fontWeight="600" letterSpacing="0.3" fill="currentColor">
            CORPORATION
          </text>
        </svg>
        <img
          src="assets/img/accreditations/iwfm.png"
          alt="IWFM corporate member"
          className="cert-img cert-img-sm"
        />
        <img
          src="assets/img/accreditations/variety-props-2025.svg"
          alt="Variety Property Partner 2025"
          className="cert-img"
        />
      </div>
    </section>
  );
}

/* ── Trust strip ─────────────────────────────────────────────────────── */
function Trust() {
  // Real Kitt client logos — used here as illustrative occupier brands
  // that already sit in Kitt-operated buildings.
  const clients = [
    { src: 'assets/img/logos/clients/kitt_client_miro.svg',       alt: 'Miro' },
    { src: 'assets/img/logos/clients/kitt_client_oatly.svg',      alt: 'Oatly' },
    { src: 'assets/img/logos/clients/kitt_client_kuoni.svg',      alt: 'Kuoni' },
    { src: 'assets/img/logos/clients/kitt_client_massmutual.svg', alt: 'MassMutual' },
    { src: 'assets/img/logos/clients/kitt_client_gumgum.svg',     alt: 'GumGum' },
    { src: 'assets/img/logos/clients/kitt_client_signifyd.svg',   alt: 'Signifyd' },
    { src: 'assets/img/logos/clients/kitt_client_flo.svg',        alt: 'Flo' },
    { src: 'assets/img/logos/clients/kitt_client_believ.svg',     alt: 'Believ' },
  ];
  return (
    <section className="trust">
      <div className="wrap trust-row">
        <span className="trust-label">Operating behind the scenes for occupiers like</span>
        <div className="trust-logos">
          {clients.map((c, i) => (
            <img key={i} className="trust-logo" src={c.src} alt={c.alt} />
          ))}
        </div>
      </div>
    </section>
  );
}

/* ── Problem ─────────────────────────────────────────────────────── */
function Problem() {
  const pains = [
    {
      n: '01',
      t: 'Too many routes, no single standard.',
      d: 'Different suppliers, different formats, different evidence. Every job is its own conversation.'
    },
    {
      n: '02',
      t: 'Suppliers are visible, not controlled.',
      d: 'You can see the directory. You can\'t see SLA breaches, recurring faults or what each supplier actually costs.'
    },
    {
      n: '03',
      t: 'Reporting and resolution arrive too late.',
      d: 'Static monthly reports describe last month. The building\'s already paid the price.'
    },
  ];
  return (
    <section className="section-pad" id="problem">
      <div className="wrap problem-grid">
        <div>
          <span className="eyebrow">The problem</span>
          <h2 className="h-section" style={{ marginTop: 20 }}>
            Ticketing systems log work. They don't run buildings.
          </h2>
        </div>
        <div>
          <p className="lede" style={{ marginBottom: 8 }}>
            Most property teams can already record a job. The hard part is everything after:
            triage, chasing suppliers, access, evidence, approvals, repeat faults, client updates —
            and knowing whether the building is actually getting better, faster.
          </p>
          <div className="pains">
            {pains.map(p => (
              <div className="pain" key={p.n}>
                <span className="pain-num">{p.n}</span>
                <div>
                  <div className="pain-title">{p.t}</div>
                  <div className="pain-desc">{p.d}</div>
                </div>
              </div>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}

/* ── Routes ─────────────────────────────────────────────────────── */
function Routes() {
  return (
    <section className="routes-block" id="model">
      <div className="wrap">
        <div className="section-split section-split-reverse">
          <div>
            <h2 className="h-section">
              One managed layer for every route to resolution.
            </h2>
          </div>
          <p className="section-split-lede">
            For each job, your property team picks the right solution; your suppliers, our team or our vetted specialists. Reeve controls the workflow, evidence and reporting across all three, so your asset gets a consistent service.
          </p>
        </div>

        <div className="route-grid route-grid-anchored">
          {/* LEFT: core route — full height */}
          <article className="route premium route-core">
            <span className="route-tag"><span className="dot" /> Core route</span>
            <h3 className="route-title">Use our team.</h3>
            <p className="route-desc">Use Reeve's team of operatives, ready for dispatch across a range of trades. Our operatives are white labelled to your brand and experience. The fastest, most reliable mode of delivery.</p>
            <ul className="route-list">
              <li>Reeve-employed operatives, embedded into your brand</li>
              <li>Live 'en-route' tracking</li>
              <li>Personalised training plans per operative on a range of skills and trades</li>
              <li>No call-out fee model, ensuring speedy and economic delivery</li>
            </ul>

            {/* Footer: overlapping operative avatars with hover tooltips */}
            <div className="route-operatives">
              {[
                { name: 'Jimmy P.',   skill: 'L2 Electrician',  tenure: '3 years, 4 months', img: 'assets/img/operatives/jimmy.jpg' },
                { name: 'Roy K.',     skill: 'Lift Engineer',   tenure: '2 years, 1 month',  img: 'assets/img/operatives/roy.jpg' },
                { name: 'Gerry W.',   skill: 'HVAC Specialist', tenure: '4 years, 7 months', img: 'assets/img/operatives/gerry.jpg' },
                { name: 'Karolis B.', skill: 'Delivery driver', tenure: '1 year, 2 months',  img: 'assets/img/operatives/karolis.jpg' },
                { name: 'Trish',      skill: 'Triaging agent',  ai: true,                    img: 'assets/img/operatives/trish.svg' },
              ].map((op, i) => (
                <span
                  key={op.name}
                  className={'op-avatar' + (op.ai ? ' op-avatar-ai' : '')}
                  style={{ zIndex: 10 - i }}
                  tabIndex="0"
                  aria-label={
                    op.ai
                      ? `${op.name}, ${op.skill}, in-built AI agent on Reeve platform`
                      : `${op.name}, ${op.skill}, with Reeve for ${op.tenure}`
                  }
                >
                  <span className="op-photo">
                    <img src={op.img} alt="" />
                  </span>
                  <span className="op-tooltip" role="tooltip">
                    <span className="op-tooltip-name">
                      {op.name}
                      {op.ai && (
                        <span className="op-tooltip-ai" aria-label="AI agent">
                          <svg width="10" height="10" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
                            <path d="M10 3.2c.1-.27.49-.27.6 0l1.3 3.45a3 3 0 0 0 1.75 1.75l3.45 1.3c.27.1.27.49 0 .6l-3.45 1.3a3 3 0 0 0-1.75 1.75l-1.3 3.45a.32.32 0 0 1-.6 0l-1.3-3.45a3 3 0 0 0-1.75-1.75l-3.45-1.3a.32.32 0 0 1 0-.6l3.45-1.3a3 3 0 0 0 1.75-1.75l1.3-3.45Z" />
                          </svg>
                          AI
                        </span>
                      )}
                    </span>
                    <span className="op-tooltip-skill">{op.skill}</span>
                    <span className="op-tooltip-tenure">
                      {op.ai ? 'In-built AI agent on Reeve platform' : `With Reeve for ${op.tenure}`}
                    </span>
                  </span>
                </span>
              ))}
            </div>
          </article>

          {/* RIGHT: two outline add-ons stacked */}
          <div className="route-addons">
            <article className="route route-outline">
              <span className="route-tag-add" aria-label="Add on">+</span>
              <h3 className="route-title">Use your suppliers.</h3>
              <p className="route-desc">Onboard the contractors you trust onto the Reeve platform. Manage, track and report through the same tooling.</p>
            </article>

            <article className="route route-outline">
              <span className="route-tag-add" aria-label="Add on">+</span>
              <h3 className="route-title">Use vetted specialists.</h3>
              <p className="route-desc">For specialist work, Reeve manages a network of third-parties, end to end. Same workflow, same reporting, same experience.</p>
            </article>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ── Services in scope ─ exact port of the home-page ServiceExplorer ── */
const SERVICES_DATA = [
  {
    id: 'cleaning',
    title: 'Cleaning & Housekeeping',
    cat: 'Soft FM',
    img: 'assets/img/cleaning.png',
    lede: 'Nightly, lunchtime and housekeeping services, delivered by a range of in-house cleaning operatives. Customisable task lists, nightly audits, and specialist services, such as sanitary, waste collection and deep cleaning.',
  },
  {
    id: 'compliance',
    title: 'Compliance, Health & Safety',
    cat: 'Regulatory',
    img: 'assets/img/compliance.jpg',
    lede: "Statutory compliance including Fire Risk Assessment, Water Risk Assessment, L8 legionella testing, emergency lighting drain-down, fire extinguisher servicing and fire door inspections. We automatically detect and triage remedial works, subject to your team's approval.",
  },
  {
    id: 'reactive',
    title: 'Reactive Maintenance',
    cat: 'Hard FM',
    img: 'assets/img/maintenance.jpg',
    lede: 'In-house electrical, plumbing, carpentry and handyman specialists. Bookable for one-off jobs, as well as more permanent day rates, our maintenance team embed into your property team as your own.',
  },
  {
    id: 'hvac',
    title: 'HVAC Maintenance',
    cat: 'Hard FM',
    img: 'assets/img/hvac.jpg',
    lede: 'Annual servicing, inspections, filter swaps and monthly checks, for all heating, ventilation and cooling systems.',
  },
  {
    id: 'internet',
    title: 'Connectivity',
    cat: 'Tech',
    img: 'assets/img/tech.png',
    lede: 'Full fibre, microwave and 5G solutions, primary and backup lines, managed firewall and Wi-Fi, 24/7 ISP NOC monitoring with auto-ticketed fault triage.',
  },
  {
    id: 'security',
    title: 'Security & CCTV',
    cat: 'Tech',
    img: 'assets/img/security-delivery.jpg',
    lede: 'Motion-triggered CCTV on access/egress, out-of-hours monitoring, keyholding, guarding dispatch and police liaison on suspicious activation.',
  },
  {
    id: 'plants',
    title: 'Plants & Foliage',
    cat: 'Soft FM',
    img: 'assets/img/plants.jpg',
    lede: 'A range of foliage offerings, including floor standing, potted plants and bespoke/curated foliage design. Comprehensive plant servicing that focuses on maintaining plant health and aesthetics.',
  },
  {
    id: 'fb',
    title: 'Tea, Coffee & Milk',
    cat: 'F&B',
    img: 'assets/img/coffee-beans.jpg',
    lede: 'Artisan beans, three teas, dairy and alternative milk offerings. All delivered directly into your fridge, pantry and coffee machine. We track stock and detect top ups, rapidly restocking your supplies without you moving a finger.',
  },
  {
    id: 'coffee',
    title: 'Coffee Machines',
    cat: 'F&B',
    img: 'assets/img/coffee-machine.jpg',
    lede: "Commercial-grade coffee machines, with full management and servicing included. We're able to dispatch engineers quickly, provide replacement machines and work on bespoke machine cleaning programmes.",
  },
  {
    id: 'snacks',
    title: 'Snacks, Fruit & Pantry',
    cat: 'F&B',
    img: 'assets/img/fb-snacks-basket.jpg',
    lede: 'A 500+ product range delivered next-day and put away into your fridge or pantry. Fresh fruit sourced from local markets, all transported on a fully electric fleet.',
  },
];

function servicesImgPosition(id) {
  if (id === 'fb') return 'center 70%';
  if (id === 'coffee') return 'center 65%';
  return 'center';
}

function ServicesCard({ s }) {
  return (
    <article
      className="services-card"
      style={{
        scrollSnapAlign: 'start',
        display: 'flex',
        flexDirection: 'column',
        background: 'var(--paper)',
        border: '1px solid var(--rule)',
        borderRadius: 16,
        overflow: 'hidden',
        boxShadow: '0 2px 6px rgb(0 0 0 / 0.04)',
      }}
    >
      <div
        style={{
          height: 200,
          backgroundImage: `url(${s.img})`,
          backgroundSize: 'cover',
          backgroundPosition: servicesImgPosition(s.id),
          position: 'relative',
        }}
      >
        <div
          style={{
            position: 'absolute',
            top: 14,
            left: 14,
            background: 'var(--paper)',
            color: 'var(--ink)',
            padding: '5px 11px',
            borderRadius: 999,
            fontSize: 11,
            fontWeight: 600,
            letterSpacing: '0.04em',
            textTransform: 'uppercase',
            boxShadow: '0 2px 6px rgb(0 0 0 / 0.12)',
          }}
        >
          {s.cat}
        </div>
      </div>
      <div style={{ padding: 24, display: 'flex', flexDirection: 'column', flex: 1 }}>
        <h3
          style={{
            fontFamily: 'var(--display)',
            fontSize: 22,
            fontWeight: 600,
            letterSpacing: '-0.02em',
            lineHeight: 1.15,
            marginBottom: 12,
            color: 'var(--ink)',
          }}
        >
          {s.title}
        </h3>
        <p style={{ fontSize: 14, color: 'var(--ink-2)', lineHeight: 1.55, margin: 0 }}>{s.lede}</p>
      </div>
    </article>
  );
}

function Services() {
  const scrollerRef = React.useRef(null);
  const [canPrev, setCanPrev] = React.useState(false);
  const [canNext, setCanNext] = React.useState(true);

  const updateButtons = () => {
    const el = scrollerRef.current;
    if (!el) return;
    setCanPrev(el.scrollLeft > 4);
    setCanNext(el.scrollLeft + el.clientWidth < el.scrollWidth - 4);
  };

  React.useEffect(() => {
    updateButtons();
    const el = scrollerRef.current;
    if (!el) return;
    el.addEventListener('scroll', updateButtons, { passive: true });
    window.addEventListener('resize', updateButtons);
    return () => {
      el.removeEventListener('scroll', updateButtons);
      window.removeEventListener('resize', updateButtons);
    };
  }, []);

  const scrollBy = (dir) => {
    const el = scrollerRef.current;
    if (!el) return;
    const step = Math.round(el.clientWidth * 0.85);
    el.scrollBy({ left: dir * step, behavior: 'smooth' });
  };

  return (
    <section
      data-sect
      id="services"
      style={{ background: 'var(--paper-2)', borderTop: '1px solid var(--rule)', padding: 'clamp(72px, 9vw, 112px) 0' }}
    >
      <div className="wrap">
        <div
          style={{
            display: 'flex',
            flexWrap: 'wrap',
            alignItems: 'end',
            justifyContent: 'space-between',
            gap: 24,
            marginBottom: 24,
          }}
        >
          <div>
            <h2
              className="h-section"
              style={{ maxWidth: 760 }}
            >
              Every service your asset needs, ready and waiting.
            </h2>
          </div>
          <div style={{ display: 'flex', gap: 8 }}>
            <button
              type="button"
              aria-label="Previous services"
              onClick={() => scrollBy(-1)}
              disabled={!canPrev}
              style={{
                width: 44,
                height: 44,
                borderRadius: '50%',
                border: '1px solid var(--rule)',
                background: 'var(--paper)',
                color: canPrev ? 'var(--ink)' : 'var(--ink-3)',
                cursor: canPrev ? 'pointer' : 'default',
                opacity: canPrev ? 1 : 0.5,
                fontSize: 18,
                fontFamily: 'var(--display)',
              }}
            >
              ←
            </button>
            <button
              type="button"
              aria-label="Next services"
              onClick={() => scrollBy(1)}
              disabled={!canNext}
              style={{
                width: 44,
                height: 44,
                borderRadius: '50%',
                border: '1px solid var(--rule)',
                background: 'var(--paper)',
                color: canNext ? 'var(--ink)' : 'var(--ink-3)',
                cursor: canNext ? 'pointer' : 'default',
                opacity: canNext ? 1 : 0.5,
                fontSize: 18,
                fontFamily: 'var(--display)',
              }}
            >
              →
            </button>
          </div>
        </div>

        <div style={{ position: 'relative', marginTop: 16 }}>
          <style>{`
            .gantry-services-scroller { scrollbar-width: none; -ms-overflow-style: none; }
            .gantry-services-scroller::-webkit-scrollbar { display: none; }
          `}</style>
          <div
            ref={scrollerRef}
            className="gantry-services-scroller"
            style={{
              display: 'flex',
              gap: 20,
              overflowX: 'auto',
              scrollSnapType: 'x mandatory',
              padding: '8px 4px 32px',
              WebkitOverflowScrolling: 'touch',
            }}
          >
            {SERVICES_DATA.map((s) => (
              <ServicesCard key={s.id} s={s} />
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}

/* ── Modules ─ carousel format, cards LEFT, heading RIGHT ─────────── */
function Modules() {
  const scrollerRef = React.useRef(null);
  const [canPrev, setCanPrev] = React.useState(false);
  const [canNext, setCanNext] = React.useState(true);
  const [isPaused, setIsPaused] = React.useState(false);

  const updateButtons = () => {
    const el = scrollerRef.current;
    if (!el) return;
    setCanPrev(el.scrollLeft > 4);
    setCanNext(el.scrollLeft + el.clientWidth < el.scrollWidth - 4);
  };

  React.useEffect(() => {
    updateButtons();
    const el = scrollerRef.current;
    if (!el) return;
    el.addEventListener('scroll', updateButtons, { passive: true });
    window.addEventListener('resize', updateButtons);
    return () => {
      el.removeEventListener('scroll', updateButtons);
      window.removeEventListener('resize', updateButtons);
    };
  }, []);

  // Autoplay — advance one card every 7s, loop back to start at end.
  // Pauses on hover. Respects the dev tweak panel motion-off flag.
  React.useEffect(() => {
    if (isPaused) return;
    if (document.documentElement.dataset.motion === 'off') return;

    const id = setInterval(() => {
      const el = scrollerRef.current;
      if (!el) return;
      const atEnd = el.scrollLeft + el.clientWidth >= el.scrollWidth - 4;
      if (atEnd) {
        el.scrollTo({ left: 0, behavior: 'smooth' });
      } else {
        // One card (320px) + gap (16px) ≈ 336px per tick
        el.scrollBy({ left: 336, behavior: 'smooth' });
      }
    }, 7000);
    return () => clearInterval(id);
  }, [isPaused]);

  const scrollBy = (dir) => {
    const el = scrollerRef.current;
    if (!el) return;
    const step = Math.round(el.clientWidth * 0.85);
    el.scrollBy({ left: dir * step, behavior: 'smooth' });
  };

  return (
    <section className="section-pad" id="product">
      <div className="wrap">
        <div className="modules-carousel-layout">
          {/* LEFT: carousel */}
          <div
            className="modules-carousel-wrap"
            onMouseEnter={() => setIsPaused(true)}
            onMouseLeave={() => setIsPaused(false)}
          >
            <div ref={scrollerRef} className="modules-carousel">
              {/* 1 — Live tracking */}
              <article className="m-card">
                <div className="m-card-visual m-vis-tracking">
                  <div className="m-tracking-phone">
                    <div className="m-tracking-head">
                      <span className="m-tracking-mark" />
                      <div>
                        <div className="m-tracking-brand">Marlow &amp; Finch</div>
                        <div className="m-tracking-sub">123 Lyle Street</div>
                      </div>
                      <span className="m-tracking-live"><span className="live-dot" />Live</span>
                    </div>
                    <div className="m-tracking-map">
                      <svg viewBox="0 0 200 100" preserveAspectRatio="xMidYMid slice">
                        <defs>
                          {/* Route hugs the streets: east along bottom road,
                              north up a side street, east along mid road,
                              then north up to the destination on top road.
                              Q-rounded corners at each junction. */}
                          <path
                            id="m-route-path"
                            d="M 20 89 L 86 88 Q 90 88 93 84 L 95 58 Q 96 54 100 53 L 152 51 Q 156 51 157 47 L 158 25"
                          />
                        </defs>

                        {/* Building blocks — gentle texture between streets */}
                        <g fill="oklch(94% 0.008 80)" opacity="0.7">
                          <rect x="42" y="27" width="44" height="22" rx="1" />
                          <rect x="102" y="27" width="48" height="22" rx="1" />
                          <rect x="40" y="60" width="50" height="22" rx="1" />
                          <rect x="106" y="58" width="46" height="22" rx="1" />
                          <rect x="165" y="32" width="38" height="16" rx="1" />
                          <rect x="-5" y="60" width="32" height="22" rx="1" />
                          <rect x="-5" y="27" width="32" height="22" rx="1" />
                        </g>

                        {/* Small park / square */}
                        <rect
                          x="165"
                          y="58"
                          width="40"
                          height="22"
                          rx="2"
                          fill="oklch(92% 0.04 145)"
                          opacity="0.75"
                        />

                        {/* Streets — irregular London-ish layout */}
                        <g stroke="oklch(86% 0.005 80)" strokeWidth="4" fill="none" strokeLinecap="round" strokeLinejoin="round">
                          {/* horizontal arteries with subtle curves */}
                          <path d="M -5 22 Q 60 18 110 25 Q 160 32 210 28" />
                          <path d="M -5 54 Q 80 58 150 51 L 210 49" />
                          <path d="M -5 89 Q 70 92 150 85 L 210 80" />
                          {/* vertical roads — slight tilt, not parallel */}
                          <path d="M 32 -5 L 28 110" />
                          <path d="M 95 -5 L 98 110" />
                          <path d="M 158 -5 L 155 110" />
                          {/* diagonal cross street (Charing Cross Rd-style) */}
                          <path d="M 178 -5 L 128 56" strokeWidth="3" opacity="0.6" />
                          {/* small mews / side street */}
                          <path d="M 60 22 L 64 54" strokeWidth="2.5" opacity="0.55" />
                        </g>

                        {/* Faint base route */}
                        <use
                          href="#m-route-path"
                          stroke="color-mix(in oklch, var(--accent) 28%, transparent)"
                          strokeWidth="3"
                          fill="none"
                          strokeLinecap="round"
                          strokeLinejoin="round"
                        />

                        {/* Animated bright progress line — draws in as the
                            operative travels */}
                        <use
                          href="#m-route-path"
                          stroke="var(--accent)"
                          strokeWidth="3"
                          fill="none"
                          strokeLinecap="round"
                          strokeLinejoin="round"
                          pathLength="100"
                          strokeDasharray="100"
                          strokeDashoffset="100"
                        >
                          <animate
                            attributeName="stroke-dashoffset"
                            from="100"
                            to="0"
                            dur="7s"
                            repeatCount="indefinite"
                          />
                        </use>

                        {/* Origin marker — operative's starting point */}
                        <g transform="translate(20 89)">
                          <circle r="2.6" fill="var(--accent)" opacity="0.4" />
                        </g>

                        {/* Destination pin (the building) */}
                        <g transform="translate(158 25)">
                          <circle r="5" fill="oklch(0.32 0.06 250)" />
                          <circle r="1.5" fill="var(--paper)" />
                        </g>

                        {/* Moving operative — pulses & travels */}
                        <g>
                          <circle r="3" fill="var(--accent)" opacity="0.45">
                            <animate attributeName="r" values="3;11;3" dur="1.8s" repeatCount="indefinite" />
                            <animate attributeName="opacity" values="0.55;0;0.55" dur="1.8s" repeatCount="indefinite" />
                          </circle>
                          <circle r="3.5" fill="var(--accent)" stroke="var(--paper)" strokeWidth="1.4" />
                          <animateMotion dur="7s" repeatCount="indefinite" rotate="auto">
                            <mpath href="#m-route-path" />
                          </animateMotion>
                        </g>
                      </svg>
                    </div>
                    <div className="m-tracking-eta">
                      <div>
                        <div className="m-tracking-eta-label">Technician en route</div>
                        <div className="m-tracking-tech">Tariq M. · Van 04</div>
                      </div>
                      <div className="m-tracking-eta-num">6<small>min</small></div>
                    </div>
                  </div>
                </div>
                <div className="m-card-body">
                  <span className="m-card-eyebrow">Live tracking</span>
                  <h3 className="m-card-title">Operative en route, with an ETA the occupier can see.</h3>
                  <p className="m-card-desc">
                    Real-time dispatch, operative identity and certifications, photo evidence
                    attached on arrival.
                  </p>
                </div>
              </article>

              {/* 2 — Workflow */}
              <article className="m-card">
                <div className="m-card-visual m-vis-tint">
                  <div className="m-audit">
                    <div className="m-audit-row"><span className="m-audit-time">08:14</span><span className="audit-state s-open">Logged</span><span className="m-audit-meta">P1 · Lyle St SE1</span></div>
                    <div className="m-audit-row"><span className="m-audit-time">08:17</span><span className="audit-state s-disp">Dispatched</span><span className="m-audit-meta">R03 · ETA 6 min</span></div>
                    <div className="m-audit-row"><span className="m-audit-time">08:24</span><span className="audit-state s-site">On site</span><span className="m-audit-meta">Photo · ID badge</span></div>
                    <div className="m-audit-row"><span className="m-audit-time">09:06</span><span className="audit-state s-ok">Resolved</span><span className="m-audit-meta">Report · 4 photos</span></div>
                  </div>
                </div>
                <div className="m-card-body">
                  <span className="m-card-eyebrow">Workflow</span>
                  <h3 className="m-card-title">Service requests with full audit trail.</h3>
                  <p className="m-card-desc">Triage, dispatch, on-site, resolved, complete visibility and evidence at every step.</p>
                </div>
              </article>

              {/* 3 — Automated quoting engine */}
              <article className="m-card">
                <div className="m-card-visual m-vis-tint">
                  <div className="m-quote">
                    <div className="m-quote-head">
                      <span className="m-quote-title">Quote · Boardroom light fitting</span>
                      <span className="m-quote-time">3 quotes</span>
                    </div>
                    <div className="m-quote-rows">
                      <div className="m-quote-row m-quote-row-best">
                        <span className="m-quote-name">Reeve</span>
                        <span className="m-quote-meta">L2 Electrician · 4h</span>
                        <span className="m-quote-price">£180</span>
                        <span className="m-quote-tag">Recommended</span>
                      </div>
                      <div className="m-quote-row">
                        <span className="m-quote-name">ThermaServ Ltd</span>
                        <span className="m-quote-meta">L1 Electrician · 1 day</span>
                        <span className="m-quote-price">£210</span>
                      </div>
                      <div className="m-quote-row">
                        <span className="m-quote-name">FrontGuard Maint</span>
                        <span className="m-quote-meta">Maintenance · 2 days</span>
                        <span className="m-quote-price">£245</span>
                      </div>
                      <div className="m-quote-row m-quote-row-pending">
                        <span className="m-quote-name">LightFix Co</span>
                        <span className="m-quote-meta">
                          Electrician ·
                          <span className="live-dot m-quote-dot" /> Pending…
                        </span>
                        <span className="m-quote-price">—</span>
                      </div>
                    </div>
                  </div>
                </div>
                <div className="m-card-body">
                  <span className="m-card-eyebrow">Quoting</span>
                  <h3 className="m-card-title">Automated quoting engine.</h3>
                  <p className="m-card-desc">Automatically get quotes from your suppliers and the Reeve network.</p>
                </div>
              </article>

              {/* 4 — Evidence (report mockup) */}
              <article className="m-card">
                <div className="m-card-visual m-vis-report">
                  <div className="m-report">
                    <div className="m-report-head">
                      <span className="m-report-title">Light out on 6th floor</span>
                      <span className="m-report-status">Closed</span>
                    </div>
                    <div className="m-report-body">
                      <div className="m-report-section">
                        <span className="m-report-label">Completed</span>
                        <div className="m-report-task">
                          <span className="m-report-check" aria-hidden="true">
                            <svg width="12" height="12" viewBox="0 0 14 14" fill="none">
                              <path d="M3 7.4 5.7 10 11 4.4" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
                            </svg>
                          </span>
                          <span>Investigate flickering light on 6th floor behind main tea point.</span>
                        </div>
                      </div>
                      <div className="m-report-bottom">
                        <img
                          src="assets/img/maintenance.jpg"
                          alt="Replaced light fitting"
                          className="m-report-photo"
                        />
                        <div className="m-report-section">
                          <span className="m-report-label">Visitor notes</span>
                          <p className="m-report-note">
                            G9 lamp had blown. New lamp purchased; fitting reinstalled.
                          </p>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
                <div className="m-card-body">
                  <span className="m-card-eyebrow">Evidence</span>
                  <h3 className="m-card-title">Photo &amp; report on every job.</h3>
                  <p className="m-card-desc">Technicians attach photos and findings on arrival and at close, with AI-generated customer-friendly visit reports.</p>
                </div>
              </article>

              {/* 5 — Performance intelligence (moved up) */}
              <article className="m-card">
                <div className="m-card-visual m-vis-summary">
                  <div className="m-summary">
                    <header className="m-summary-head">
                      <span className="m-summary-avatar">A</span>
                      <span className="m-summary-name">Ada</span>
                      <span className="m-summary-ai">
                        <svg width="9" height="9" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
                          <path d="M10 3.2c.1-.27.49-.27.6 0l1.3 3.45a3 3 0 0 0 1.75 1.75l3.45 1.3c.27.1.27.49 0 .6l-3.45 1.3a3 3 0 0 0-1.75 1.75l-1.3 3.45a.32.32 0 0 1-.6 0l-1.3-3.45a3 3 0 0 0-1.75-1.75l-3.45-1.3a.32.32 0 0 1 0-.6l3.45-1.3a3 3 0 0 0 1.75-1.75l1.3-3.45Z" />
                        </svg>
                        AI
                      </span>
                      <span className="m-summary-time">2h ago</span>
                    </header>
                    <div className="m-summary-title">Building summary</div>
                    <div className="m-summary-subtitle">Marlow &amp; Finch — week 24</div>
                    <div className="m-summary-rows">
                      <div className="m-summary-row">
                        <span>Avg. resolution</span>
                        <span className="m-summary-pill m-summary-pill-green">2.2d</span>
                      </div>
                      <div className="m-summary-row">
                        <span>SLA hit rate</span>
                        <span className="m-summary-pill m-summary-pill-amber">96%</span>
                      </div>
                      <div className="m-summary-row">
                        <span>Recurring faults</span>
                        <span className="m-summary-pill m-summary-pill-blue">−42%</span>
                      </div>
                    </div>
                    <div className="m-summary-footer">
                      Top operating site this week. Above portfolio average across all routes.
                    </div>
                  </div>
                </div>
                <div className="m-card-body">
                  <span className="m-card-eyebrow">Performance intelligence</span>
                  <h3 className="m-card-title">A live, per-building operating picture.</h3>
                  <p className="m-card-desc">Resolution time, recurring faults, supplier performance, occupier sentiment, by building, by client, by service line.</p>
                </div>
              </article>

              {/* 6 — CAFM-grade */}
              <article className="m-card">
                <div className="m-card-visual m-vis-tint">
                  <div className="m-cafm">
                    <div className="m-cafm-tile"><span className="m-cafm-tile-num">142</span><span className="m-cafm-tile-l">Assets registered</span></div>
                    <div className="m-cafm-tile"><span className="m-cafm-tile-num">38</span><span className="m-cafm-tile-l">PPMs scheduled</span></div>
                    <div className="m-cafm-tile"><span className="m-cafm-tile-num">100%</span><span className="m-cafm-tile-l">Statutory cover</span></div>
                    <div className="m-cafm-tile"><span className="m-cafm-tile-num">0</span><span className="m-cafm-tile-l">Audit findings</span></div>
                  </div>
                </div>
                <div className="m-card-body">
                  <span className="m-card-eyebrow">Compliance</span>
                  <h3 className="m-card-title">PPMs, assets &amp; statutory cover.</h3>
                  <p className="m-card-desc">Asset register, planned maintenance schedules, statutory compliance; everything you need to keep your estate compliant.</p>
                </div>
              </article>

              {/* 7 — Visitor management & access */}
              <article className="m-card">
                <div className="m-card-visual m-vis-guest">
                  <div className="m-guest">
                    <div className="m-guest-head">
                      <span className="m-guest-back" aria-hidden="true">
                        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                          <path d="M15 18l-6-6 6-6" />
                        </svg>
                      </span>
                      <span className="m-guest-title">Register a guest</span>
                    </div>
                    <div className="m-guest-body">
                      <div className="m-guest-field">
                        <label>Guest name</label>
                        <div className="m-guest-input">Maya Chen</div>
                      </div>
                      <div className="m-guest-field">
                        <label>Date</label>
                        <div className="m-guest-input m-guest-input-select">
                          <span>Thu 18 Jun · 9:30</span>
                          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                            <path d="M6 9l6 6 6-6" />
                          </svg>
                        </div>
                      </div>
                      <div className="m-guest-coffee">
                        <span className="m-guest-coffee-icon" aria-hidden="true">
                          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
                            <path d="M4 8h12v6a4 4 0 0 1-4 4H8a4 4 0 0 1-4-4V8z" />
                            <path d="M16 10h2a2 2 0 0 1 0 4h-2" />
                            <path d="M8 3v2M11 3v2M14 3v2" />
                          </svg>
                        </span>
                        <span className="m-guest-coffee-label">Coffee on arrival</span>
                        <span className="m-guest-toggle m-guest-toggle-on" aria-hidden="true">
                          <span className="m-guest-toggle-handle" />
                        </span>
                      </div>
                      <button type="button" className="m-guest-submit">
                        Continue <span className="arrow">→</span>
                      </button>
                    </div>
                  </div>
                </div>
                <div className="m-card-body">
                  <span className="m-card-eyebrow">Estate ops</span>
                  <h3 className="m-card-title">Visitor management &amp; access.</h3>
                  <p className="m-card-desc">Visitor pre-registration, door access provisioning and end-user management, allowing your occupiers direct access to the platform.</p>
                </div>
              </article>
            </div>
          </div>

          {/* RIGHT: heading + lede + nav */}
          <div className="modules-text">
            <h2 className="h-section">The operating layer behind better buildings.</h2>
            <p className="lede">
              A single pane of glass over your facilities management, plus the actual operatives that deliver the service. Instant quotes. Engineers tracked from request to resolution. Your tenants stop chasing.
            </p>
            <div className="modules-nav">
              <button
                type="button"
                aria-label="Previous module"
                onClick={() => scrollBy(-1)}
                disabled={!canPrev}
                className="modules-nav-btn"
              >←</button>
              <button
                type="button"
                aria-label="Next module"
                onClick={() => scrollBy(1)}
                disabled={!canNext}
                className="modules-nav-btn"
              >→</button>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ── Desktop workstation mockup ─ lights-out flow with supplier step ─
   Phased animation, same arc as the phone GIF on the home page but on a
   desktop layout, with a new "supplier selected · cost" step inserted
   between AI triage and dispatch. ─ */
function DesktopWorkstation() {
  const [phase, setPhase] = React.useState(0);
  const [typed, setTyped] = React.useState('');
  const FULL_TEXT = 'Lights gone out in the board meeting room';

  React.useEffect(() => {
    const timers = [];
    if (phase === 0) {
      timers.push(setTimeout(() => setPhase(1), 900));
    } else if (phase === 1) {
      let i = 0;
      const tick = () => {
        i++;
        setTyped(FULL_TEXT.slice(0, i));
        if (i < FULL_TEXT.length) {
          timers.push(setTimeout(tick, 32 + Math.random() * 24));
        } else {
          timers.push(setTimeout(() => setPhase(2), 700));
        }
      };
      tick();
    } else if (phase === 2) {
      timers.push(setTimeout(() => setPhase(3), 1400));
    } else if (phase === 3) {
      timers.push(setTimeout(() => setPhase(4), 1300));
    } else if (phase === 4) {
      timers.push(setTimeout(() => setPhase(5), 1500));
    } else if (phase === 5) {
      timers.push(setTimeout(() => {
        setTyped('');
        setPhase(0);
      }, 5500));
    }
    return () => timers.forEach(clearTimeout);
  }, [phase]);

  const suppliers = [
    { name: 'Reeve',            rating: '98%', cost: '£180', selected: true },
    { name: 'LightFix Co',      rating: '95%', cost: '£210', selected: false, uploaded: true },
    { name: 'FrontGuard Maint', rating: '86%', cost: '£230', selected: false },
  ];

  return (
    <div className="desk-mockup">
      {/* Browser chrome */}
      <div className="desk-chrome">
        <div className="desk-chrome-dots">
          <span /><span /><span />
        </div>
        <div className="desk-chrome-title">reeve · ops · marlow &amp; finch</div>
      </div>

      <div className="desk-body">
        {/* Ticket header bar */}
        <div className="desk-ticket-head">
          <div>
            <div className="desk-mono">Ticket 04812</div>
            <div className="desk-ticket-title">New issue — boardroom</div>
          </div>
          <span
            className={
              'desk-status-pill ' + (
                phase < 2 ? 'desk-status-new' :
                phase < 5 ? 'desk-status-triaged' :
                'desk-status-dispatched'
              )
            }
          >
            {phase < 2 ? 'New' : phase < 5 ? 'Triaged' : 'Dispatched'}
          </span>
        </div>

        {/* Issue input */}
        <div className="desk-field">
          <div className="desk-label">Describe the issue</div>
          <div className="desk-input">
            <span className="desk-input-text">
              {phase >= 1 ? (phase === 1 ? typed : FULL_TEXT) : ''}
              {(phase === 0 || phase === 1) && <span className="desk-cursor" />}
            </span>
            {phase === 0 && !typed && (
              <span className="desk-input-placeholder">Type a new issue…</span>
            )}
          </div>
        </div>

        {/* AI triage — always rendered so the desktop stays at final size */}
        <div className={'desk-field desk-phase' + (phase >= 2 ? ' desk-phase-on' : '')}>
          <div className="desk-triage">
              <div className="desk-triage-head">
                <span className="m-summary-ai">
                  <svg width="9" height="9" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
                    <path d="M10 3.2c.1-.27.49-.27.6 0l1.3 3.45a3 3 0 0 0 1.75 1.75l3.45 1.3c.27.1.27.49 0 .6l-3.45 1.3a3 3 0 0 0-1.75 1.75l-1.3 3.45a.32.32 0 0 1-.6 0l-1.3-3.45a3 3 0 0 0-1.75-1.75l-3.45-1.3a.32.32 0 0 1 0-.6l3.45-1.3a3 3 0 0 0 1.75-1.75l1.3-3.45Z" />
                  </svg>
                  AI triage
                </span>
                <span className="desk-mono">~110 min est.</span>
              </div>
              <div className="desk-triage-chips">
                <span className="desk-chip"><span className="desk-chip-dot" /> Electrical</span>
                <span className="desk-chip"><span className="desk-chip-dot" /> P2 priority</span>
                <span className="desk-chip"><span className="desk-chip-dot" /> Boardroom · Floor 4</span>
              </div>
            </div>
        </div>

        {/* Supplier comparison */}
        <div className={'desk-field desk-phase' + (phase >= 3 ? ' desk-phase-on' : '')}>
            <div className="desk-label">Supplier · select &amp; quote</div>
            <div className="desk-suppliers">
              <div className="desk-supplier desk-supplier-head">
                <span>Supplier</span>
                <span>Reliability</span>
                <span>Quote</span>
                <span />
              </div>
              {suppliers.map((s) => {
                const isSelected = phase >= 4 && s.selected;
                return (
                  <div
                    key={s.name}
                    className={'desk-supplier' + (isSelected ? ' desk-supplier-selected' : '')}
                  >
                    <div className="desk-supplier-name">
                      {s.name}
                      {s.uploaded && (
                        <span className="m-quote-uploaded" aria-label="User uploaded supplier">
                          <svg width="8" height="8" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                            <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
                            <polyline points="17 8 12 3 7 8" />
                            <line x1="12" y1="3" x2="12" y2="15" />
                          </svg>
                          Uploaded supplier
                        </span>
                      )}
                    </div>
                    <div className="desk-supplier-rating">{s.rating}</div>
                    <div className="desk-supplier-cost">{s.cost}</div>
                    <div className="desk-supplier-action">
                      {isSelected ? (
                        <span className="desk-supplier-selected-pill">✓ Selected</span>
                      ) : 'Use'}
                    </div>
                  </div>
                );
              })}
            </div>
        </div>

        {/* Dispatch confirmation */}
        <div className={'desk-dispatch desk-phase' + (phase >= 5 ? ' desk-phase-on' : '')}>
            <div className="desk-dispatch-av">
              <div className="desk-dispatch-av-pulse">
                <span className="live-dot" />
              </div>
            </div>
            <div className="desk-dispatch-info">
              <div className="desk-dispatch-title">Roy on the way · ETA 14:31</div>
              <div className="desk-dispatch-sub">Reeve · L2 Electrician · 8 min away</div>
            </div>
            <div className="desk-dispatch-num">14:31</div>
        </div>
      </div>
    </div>
  );
}

/* ── Comparison ─────────────────────────────────────────────────────── */
function Compare() {
  const Check = () => (
    <svg className="mark" width="14" height="14" viewBox="0 0 14 14">
      <path d="M3 7.2 5.8 10 11 4.2" stroke="var(--accent)" strokeWidth="1.6"
            fill="none" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
  const Dot = () => (
    <svg className="mark" width="14" height="14" viewBox="0 0 14 14">
      <circle cx="7" cy="7" r="1.5" fill="var(--ink-4)" />
    </svg>
  );
  return (
    <section className="section-pad" id="vs">
      <div className="wrap">
        <div className="section-split section-split-reverse">
          <div>
            <h2 className="h-section">
              Everything you expect from CAFM, plus the team to make it happen, faster.
            </h2>
          </div>
          <p className="section-split-lede">
            Cut what you spend on FM coordination, third-party callouts, and software. Most of what you currently pay for the chain disappears.
          </p>
        </div>

        <div className="compare-with-demo">
         <div className="compare-tiles">
          <div className="compare-col legacy">
            <h3>Legacy CAFM &amp; logbooks</h3>
            <ul className="compare-list">
              <li><Dot /><span>Logs jobs</span></li>
              <li><Dot /><span>Software only</span></li>
              <li><Dot /><span>Supplier directory</span></li>
              <li><Dot /><span>Static monthly reports</span></li>
              <li><Dot /><span>Your team still chases</span></li>
              <li><Dot /><span>Tool-adoption risk</span></li>
            </ul>
          </div>
          <div className="compare-col reeve">
            <h3 style={{ color: 'var(--bg)' }}>
              <ReeveWordmark size={22} dark still />
            </h3>
            <ul className="compare-list">
              <li><Check /><span>Owns the route to resolution</span></li>
              <li><Check /><span>Software <em>plus</em> managed FM delivery</span></li>
              <li><Check /><span>Supplier onboarding, SLAs &amp; performance</span></li>
              <li><Check /><span>Live building insights &amp; recurring-fault actions</span></li>
              <li><Check /><span>Reeve chases, escalates, evidences</span></li>
              <li><Check /><span>Service-led adoption, behind your brand</span></li>
            </ul>
          </div>
         </div>

         <div className="compare-demo">
          <DesktopWorkstation />
         </div>
        </div>
      </div>
    </section>
  );
}

/* ── Brand preservation ─────────────────────────────────────────────────── */

/* Brand colour swatches for the whitelabel preview panel. Same palette
   used previously inside the Modules carousel — restored here so the
   Brand section gets a live, interactive whitelabelling visual. */
const BRAND_COLORS = [
  { name: 'Navy',   value: 'oklch(28% 0.06 250)' },
  { name: 'Bronze', value: 'oklch(60% 0.13 50)'  },
  { name: 'Forest', value: 'oklch(48% 0.09 160)' },
  { name: 'Brick',  value: 'oklch(48% 0.10 30)'  },
];

/* Service-requests preview panel — mirrors a tenant-facing dashboard.
   Icon backgrounds + buttons retint to the active brand colour via the
   --sr-accent custom property. The "Delivered by …" label is bound to
   the active brand (Reeve before the upload animation completes,
   Marlow & Finch after) and shows a small brand chip in the active
   colour next to the name. */
function ServiceRequestsPanel({ color, brand, mark }) {
  const REQUESTS = [
    { title: 'Fix the window blinds' },
    { title: 'Shower is broken' },
    { title: 'Install a projector stand' },
    { title: 'Hang up picture frames' },
    { title: 'Quarterly electrical safety check' },
  ];

  // Reusable alert-circle icon (circle + ! mark)
  const AlertIcon = ({ size = 16 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <circle cx="12" cy="12" r="9" />
      <line x1="12" y1="7.5" x2="12" y2="13" />
      <circle cx="12" cy="16.5" r="0.6" fill="currentColor" stroke="none" />
    </svg>
  );

  return (
    <div className="sr-panel" style={{ '--sr-accent': color }}>
      <div className="sr-header">
        <span className="sr-icon sr-icon-lg">
          <AlertIcon size={18} />
        </span>
        <div className="sr-header-text">
          <span className="sr-header-title">Recent service requests</span>
          <span className="sr-header-sub">Latest across your network</span>
        </div>
        <a
          href="#"
          className="sr-view-all"
          onClick={(e) => e.preventDefault()}
        >
          View all <span aria-hidden="true">→</span>
        </a>
      </div>
      <div className="sr-rows">
        {REQUESTS.map((r) => (
          <div className="sr-row" key={r.title}>
            <span className="sr-icon">
              <AlertIcon size={16} />
            </span>
            <div className="sr-text">
              <span className="sr-title">{r.title}</span>
              <span className="sr-sub">
                <span>Delivered by</span>
                <span className="sr-brand-mark">{mark}</span>
                <span>{brand}</span>
              </span>
            </div>
            <button type="button" className="sr-btn">Open</button>
          </div>
        ))}
      </div>
    </div>
  );
}

/* Brand showcase ─ orchestrated whitelabel demo. Plays out on mount:
   (1) type the customer's name slowly, (2) upload their logo with a
   progress bar, (3) switch the active brand colour. After the demo
   finishes the user can still click swatches to retint everything.
   Reeve is the implicit "before" state (activeIdx === -1 + uploaded
   === false) so the service-requests panel reads "Delivered by Reeve"
   until M&F's logo lands. */
function BrandShowcase() {
  const TARGET_NAME = 'Marlow & Finch';
  const [brandName, setBrandName] = React.useState('');
  const [activeIdx, setActiveIdx] = React.useState(-1);   // -1 = Reeve default
  const [uploaded, setUploaded] = React.useState(false);
  const [uploading, setUploading] = React.useState(false);
  // userOverride: true once the visitor has typed their own brand name.
  // Kills the canned auto-animation so they own the demo from there on.
  const [userOverride, setUserOverride] = React.useState(false);
  // customLogo: { dataUrl, name, size } — populated when the visitor
  // uploads a real image via the Replace button. Replaces the M&F text
  // thumb on the panel and the initials chip in service requests.
  const [customLogo, setCustomLogo] = React.useState(null);
  const fileInputRef = React.useRef(null);
  // Animation kicks off only once the section scrolls into view —
  // showcase ref + has-started flag drive that gating.
  const showcaseRef = React.useRef(null);
  const [hasStarted, setHasStarted] = React.useState(false);

  // Helpers — derive a chip's initials and a sensible "uploaded"
  // filename from whatever brand name we're displaying.
  const computeInitials = (name) =>
    name.split(/\s+/).filter(Boolean).map((w) => w[0].toUpperCase()).join('');
  const slugify = (name) =>
    name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');

  // Watch the showcase with IntersectionObserver. As soon as ~15% is
  // on screen, flip hasStarted (and disconnect — we only need to fire
  // once). Fallback: if IO is unavailable for any reason, start now.
  React.useEffect(() => {
    if (hasStarted) return;
    const el = showcaseRef.current;
    if (!el) return;
    if (typeof IntersectionObserver === 'undefined') {
      setHasStarted(true);
      return;
    }
    const io = new IntersectionObserver(
      (entries) => {
        for (const entry of entries) {
          if (entry.isIntersecting) {
            setHasStarted(true);
            io.disconnect();
            break;
          }
        }
      },
      { threshold: 0.15 }
    );
    io.observe(el);
    return () => io.disconnect();
  }, [hasStarted]);

  // Pre-upload: use Reeve's green. Post-upload: whichever swatch is active.
  const activeColor = activeIdx === -1
    ? 'var(--accent)'
    : BRAND_COLORS[activeIdx].value;
  const displayBrand    = uploaded ? brandName            : 'Reeve';
  const displayInitials = uploaded ? computeInitials(brandName) : 'R';
  // "Show file" — only once the upload has started or finished do we
  // expose filename / size in the meta area. Before then the panel is
  // in an explicit empty state (no logo uploaded yet).
  const showFile        = uploading || uploaded;
  const displayLogoFile = customLogo
    ? customLogo.name
    : uploaded
      ? slugify(brandName) + '.svg'
      : (uploading ? 'marlow-finch.svg' : '');
  const displayLogoSize = customLogo
    ? customLogo.size
    : (showFile ? '240 × 60' : '');
  // Inline mark in the service-requests subtitle:
  // - Visitor uploaded a real logo → small image thumb
  // - Brand identity established   → initials chip in active brand colour
  // - Reeve initial state          → real wordmark from brand.jsx
  const inlineMark = customLogo
    ? (
      <span className="sr-brand-mark-img" aria-hidden="true">
        <img src={customLogo.dataUrl} alt="" />
      </span>
    )
    : uploaded
      ? <span className="sr-brand-chip" aria-hidden="true">{displayInitials}</span>
      : <ReeveWordmark size={11} still />;

  // User typed something — kill the auto-animation, claim ownership of
  // the brand identity, default to a starting swatch if we're still
  // sitting on the Reeve green.
  const handleNameChange = (e) => {
    const v = e.target.value;
    setBrandName(v);
    if (!userOverride) setUserOverride(true);
    setUploading(false);
    if (v.length > 0) {
      setUploaded(true);
      if (activeIdx === -1) setActiveIdx(0);
    } else {
      setUploaded(false);
      setActiveIdx(-1);
      setCustomLogo(null);
    }
  };

  // Visitor picked a logo file via the hidden file input. Read as data
  // URL + measure the natural dimensions for the meta line.
  const handleLogoUpload = (e) => {
    const file = e.target.files && e.target.files[0];
    if (!file) return;
    if (!file.type.startsWith('image/')) return;
    const reader = new FileReader();
    reader.onload = (ev) => {
      const dataUrl = ev.target && ev.target.result;
      if (typeof dataUrl !== 'string') return;
      const probe = new Image();
      probe.onload = () => {
        const w = probe.naturalWidth;
        const h = probe.naturalHeight;
        const size = (w && h) ? `${w} × ${h}` : '—';
        setCustomLogo({ dataUrl, name: file.name, size });
        if (!userOverride) setUserOverride(true);
        setUploading(false);
        setUploaded(true);
        if (activeIdx === -1) setActiveIdx(0);
      };
      probe.onerror = () => {
        setCustomLogo({ dataUrl, name: file.name, size: '—' });
        if (!userOverride) setUserOverride(true);
        setUploading(false);
        setUploaded(true);
        if (activeIdx === -1) setActiveIdx(0);
      };
      probe.src = dataUrl;
    };
    reader.readAsDataURL(file);
    // Allow re-selecting the same file later
    e.target.value = '';
  };

  const triggerLogoUpload = () => {
    fileInputRef.current && fileInputRef.current.click();
  };

  React.useEffect(() => {
    // Wait until the section is in view before kicking off.
    if (!hasStarted) return;
    // Visitor has taken control of the input — stand down.
    if (userOverride) return;

    // Honour motion-off — jump to the final state immediately.
    if (typeof document !== 'undefined' &&
        document.documentElement.dataset.motion === 'off') {
      setBrandName(TARGET_NAME);
      setUploaded(true);
      setActiveIdx(2);
      return;
    }

    const timers = [];

    // Phase 4: colour change demo — Navy → Forest after a beat.
    const colourChange = () => setActiveIdx(2);

    // Phase 3: upload completes — flip to M&F brand identity.
    const finishUpload = () => {
      setUploaded(true);
      setUploading(false);
      setActiveIdx(0);
      timers.push(setTimeout(colourChange, 1300));
    };

    // Phase 2: upload starts after typing.
    const startUpload = () => {
      setUploading(true);
      timers.push(setTimeout(finishUpload, 1500));
    };

    // Phase 1: type the name char-by-char (~250ms per char on average).
    const startTyping = () => {
      let i = 0;
      const typeChar = () => {
        i += 1;
        setBrandName(TARGET_NAME.slice(0, i));
        if (i < TARGET_NAME.length) {
          timers.push(setTimeout(typeChar, 200 + Math.random() * 110));
        } else {
          timers.push(setTimeout(startUpload, 600));
        }
      };
      typeChar();
    };

    timers.push(setTimeout(startTyping, 900));
    return () => timers.forEach(clearTimeout);
  }, [hasStarted, userOverride]);

  return (
    <div className="brand-showcase" ref={showcaseRef}>
      <div className="m-brand-panel brand-preview-panel">
        {/* Name field — auto-types Marlow & Finch on first view, but the
            input is fully editable so the visitor can type their own
            brand name (which kills the canned animation). */}
        <div className="m-brand-row">
          <span className="m-brand-row-label">Name</span>
          <input
            type="text"
            className="brand-name-input"
            value={brandName}
            onChange={handleNameChange}
            placeholder="Your brand name"
            aria-label="Brand name"
            spellCheck="false"
            autoComplete="off"
          />
        </div>

        {/* Logo row — empty placeholder → upload progress → M&F filled.
            Custom image upload via the hidden file input wired up below
            the Replace pill replaces the text thumb with a real image. */}
        <div className="m-brand-row">
          <span className="m-brand-row-label">Logo</span>
          <div className={'m-brand-logo' + (uploading ? ' m-brand-logo-uploading' : '')}>
            {customLogo ? (
              <div className="m-brand-logo-thumb m-brand-logo-thumb-img">
                <img src={customLogo.dataUrl} alt="Uploaded brand logo" />
              </div>
            ) : uploaded ? (
              <div
                className="m-brand-logo-thumb"
                style={{ background: activeColor, transition: 'background 280ms ease' }}
              >
                M&amp;F
              </div>
            ) : (
              <div className="m-brand-logo-thumb m-brand-logo-thumb-empty" aria-hidden="true">
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
                  <polyline points="17 8 12 3 7 8" />
                  <line x1="12" y1="3" x2="12" y2="15" />
                </svg>
              </div>
            )}
            <div className="m-brand-logo-meta">
              {(showFile || customLogo) ? (
                <>
                  <span className="m-brand-logo-name">{displayLogoFile}</span>
                  <span className="m-brand-logo-size">{displayLogoSize}</span>
                </>
              ) : (
                <span className="m-brand-logo-empty">No logo uploaded</span>
              )}
            </div>
            <button
              type="button"
              className="m-brand-replace"
              onClick={triggerLogoUpload}
            >
              {uploading ? 'Uploading' : (uploaded || customLogo) ? 'Replace' : 'Upload'}
            </button>
            <input
              ref={fileInputRef}
              type="file"
              accept="image/*"
              onChange={handleLogoUpload}
              style={{ display: 'none' }}
              aria-label="Upload brand logo"
            />
            {uploading && (
              <div className="m-brand-upload-bar" aria-hidden="true">
                <div className="m-brand-upload-fill" />
              </div>
            )}
          </div>
        </div>

        {/* Brand colour swatches */}
        <div className="m-brand-row">
          <span className="m-brand-row-label">Brand</span>
          <div className="m-brand-swatches">
            {BRAND_COLORS.map((c, i) => (
              <button
                key={c.name}
                type="button"
                className={'m-swatch' + (i === activeIdx ? ' m-swatch-active' : '')}
                style={{ background: c.value }}
                aria-label={c.name}
                aria-pressed={i === activeIdx}
                onClick={() => setActiveIdx(i)}
              />
            ))}
            <button type="button" className="m-swatch m-swatch-add" aria-label="Add colour">+</button>
          </div>
        </div>

        {/* Tone slider */}
        <div className="m-brand-row">
          <span className="m-brand-row-label">Tone</span>
          <div className="m-tone">
            <div className="m-tone-track">
              <div
                className="m-tone-fill"
                style={{ background: activeColor, transition: 'background 280ms ease' }}
              />
              <div
                className="m-tone-thumb"
                style={{ borderColor: activeColor, transition: 'border-color 280ms ease' }}
              />
            </div>
            <div className="m-tone-labels">
              <span>Formal</span>
              <span
                className="m-tone-current"
                style={{ color: activeColor, transition: 'color 280ms ease' }}
              >
                Warm
              </span>
              <span>Friendly</span>
            </div>
          </div>
        </div>
      </div>

      <ServiceRequestsPanel
        color={activeColor}
        brand={displayBrand}
        mark={inlineMark}
      />
    </div>
  );
}

function Brand() {
  return (
    <section className="section-pad" id="brand">
      <div className="wrap">
        <div className="section-split">
          <div>
            <h2 className="h-section">
              Deliver an elevated level of service, under your brand.
            </h2>
          </div>
          <p className="section-split-lede">
            A platform and service fully white-labelled to your brand. Provide real time
            visibility, reporting and performance to your clients.
          </p>
        </div>
        <BrandShowcase />
      </div>
    </section>
  );
}

/* ── Proof / Rollout ─────────────────────────────────────────────────── */
function Proof() {
  return (
    <section className="section-pad" id="proof" style={{ background: 'var(--paper-2)', borderTop: '1px solid var(--rule)', borderBottom: '1px solid var(--rule)' }}>
      <div className="wrap">
        <div className="section-split">
          <div>
            <h2 className="h-section">
              Start with selected buildings. Scale what works.
            </h2>
          </div>
          <p className="section-split-lede">
            Set up your Reeve experience to however suits you, whether that's using
            our embedded team or your own suppliers and operatives. Whitelabel the
            experience to your identity. Retain the same tracking, workflows and analytics.
          </p>
        </div>

        <div className="rollout-steps rollout-steps-horizontal">
          <div className="step">
            <span className="step-n">01</span>
            <div>
              <div className="step-t">Select buildings &amp; services</div>
              <div className="step-d">Pick the buildings that you want Reeve to operate on first. Define the services you wish to kick off with.</div>
            </div>
          </div>
          <div className="step">
            <span className="step-n">02</span>
            <div>
              <div className="step-t">Agree routes</div>
              <div className="step-d">Select which services and jobs you wish to run through Reeve operatives or your own uploaded suppliers.</div>
            </div>
          </div>
          <div className="step">
            <span className="step-n">03</span>
            <div>
              <div className="step-t">Configure your brand experience</div>
              <div className="step-d">Our operatives, supply network and platform will begin to whitelabel and get to grips with your identity and experience.</div>
            </div>
          </div>
          <div className="step">
            <span className="step-n">04</span>
            <div>
              <div className="step-t">Operate, evidence, report</div>
              <div className="step-d">Reeve runs the operating layer behind your portfolio. You get full visibility and reporting on performance.</div>
            </div>
          </div>
          <a
            href="https://calendar.app.google/be3ib85HS3rDzJtr8"
            target="_blank"
            rel="noopener noreferrer"
            className="step step-cta"
          >
            <div>
              <div className="step-t">Get started</div>
              <div className="step-d">Book a walkthrough and we'll scope your first buildings together.</div>
            </div>
            <span className="step-cta-arrow" aria-hidden="true">→</span>
          </a>
        </div>
      </div>
    </section>
  );
}

/* ── Closing CTA ─────────────────────────────────────────────────────── */
function ClosingCTA() {
  return (
    <section id="walk">
      <div className="close-cta">
        <svg className="close-cta-bg" viewBox="0 0 1200 400" preserveAspectRatio="none" aria-hidden="true">
          <g stroke="rgba(255,255,255,0.05)" fill="none" strokeWidth="1">
            <path d="M0 200 Q 300 80 600 200 T 1200 200" />
            <path d="M0 240 Q 300 120 600 240 T 1200 240" />
            <path d="M0 280 Q 300 160 600 280 T 1200 280" />
          </g>
        </svg>
        <div className="close-cta-inner">
          <div className="close-cta-stack">
            <h2 className="h-section">
              Run your portfolio 10x faster.
            </h2>
            <p className="close-cta-body">
              Book in a 45 minute session. We'll walk through the platform with your portfolio
              in mind, discussing your assets, existing supply chain and reporting needs.
            </p>
            <a
              href="https://calendar.app.google/be3ib85HS3rDzJtr8"
              target="_blank"
              rel="noopener noreferrer"
              className="btn btn-on-dark btn-primary"
              style={{ width: 'fit-content' }}
            >
              Book a Reeve walkthrough <span className="arrow">→</span>
            </a>
          </div>
        </div>
      </div>
    </section>
  );
}

/* ── Footer ─────────────────────────────────────────────────────── */
function Footer() {
  return (
    <footer className="foot">
      <div className="wrap">
        <div className="accreditations">
          <span className="accreditations-label">Accredited &amp; certified</span>
          <div className="accreditation-row">
            <img src="assets/img/iso27001.png" alt="ISO 27001 certified" />
            <svg
              width="36"
              height="36"
              viewBox="0 0 100 100"
              xmlns="http://www.w3.org/2000/svg"
              className="accreditation-bcorp"
              aria-label="Certified B Corporation"
            >
              <text x="50" y="14" textAnchor="middle" fontFamily="Inter Tight, ui-sans-serif, system-ui" fontSize="9" fontWeight="600" letterSpacing="0.5" fill="currentColor">
                CERTIFIED
              </text>
              <circle cx="50" cy="52" r="20" fill="none" stroke="currentColor" strokeWidth="2.6" />
              <text x="50" y="60" textAnchor="middle" fontFamily="Inter Tight, ui-sans-serif, system-ui" fontSize="26" fontWeight="700" fill="currentColor">
                B
              </text>
              <line x1="32" y1="80" x2="68" y2="80" stroke="currentColor" strokeWidth="1.4" />
              <text x="50" y="92" textAnchor="middle" fontFamily="Inter Tight, ui-sans-serif, system-ui" fontSize="9" fontWeight="600" letterSpacing="0.3" fill="currentColor">
                CORPORATION
              </text>
            </svg>
            <img src="assets/img/accreditations/iwfm.png" alt="IWFM member" />
            <img src="assets/img/accreditations/variety-props-2025.svg" alt="Variety Property Partner 2025" />
          </div>
        </div>
        <div className="foot-grid">
          <div className="foot-col">
            <ReeveWordmark dark still />
            <p style={{ color: 'var(--ink-3)', fontSize: 13.5, marginTop: 12, maxWidth: 280 }}>
              The managed operating layer for commercial property teams. Software plus hands-on
              FM coordination — behind your brand.
            </p>
          </div>
          <div className="foot-col">
            <h4>Product</h4>
            <ul>
              <li><a href="#model">The Reeve model</a></li>
              <li><a href="#product">Modules</a></li>
              <li><a href="#vs">Why Reeve</a></li>
              <li><a href="#proof">Rollout</a></li>
            </ul>
          </div>
          <div className="foot-col">
            <h4>Company</h4>
            <ul>
              <li><a href="#">About</a></li>
              <li><a href="#">Operations</a></li>
              <li><a href="#">Careers</a></li>
              <li><a href="#">Press</a></li>
            </ul>
          </div>
          <div className="foot-col">
            <h4>Talk</h4>
            <ul>
              <li><a href="https://calendar.app.google/be3ib85HS3rDzJtr8" target="_blank" rel="noopener noreferrer">Book a walkthrough</a></li>
              <li><a href="mailto:hello@reeve.fm">hello@reeve.fm</a></li>
              <li><a href="#">London — 23 Curtain Road</a></li>
            </ul>
          </div>
        </div>
        <div className="foot-base">
          <span>© Reeve Operations Ltd. 2026 · Registered in England</span>
          <span style={{ display: 'inline-flex', gap: 18 }}>
            <a href="#">Privacy</a><a href="#">Terms</a><a href="#">Security</a>
          </span>
        </div>
      </div>
    </footer>
  );
}

Object.assign(window, {
  Nav, Hero, DispatchLog, Certifications, Trust, Problem, Routes, Services, Modules, Compare, Brand, Proof, ClosingCTA, Footer
});
