/* global React, ReactDOM */
const { useState, useEffect, useRef } = React;

// ---------------------------------------------------------------------------
// Brand tokens
// ---------------------------------------------------------------------------
// Huisstijl-tokens. "navy" en "teal" zijn historische sleutels (overal in de
// code in gebruik); ze mappen op de *primaire* en *accent*kleur van de actieve
// klant. De waarden hieronder zijn de neutrale standaard (Workflow Automations
// demo-thema) en worden bij het opstarten overschreven door applyCompanyTheme()
// op basis van de klant in data/companies.json. Daarom is dit `let`, geen const.
let brand = {
  navy: "#1F2A44",
  navyDeep: "#141C30",
  navySoft: "#33415F",
  teal: "#3B82F6",
  tealDeep: "#2563EB",
  tealSoft: "#E5EEFD",
  paper: "#FFFFFF",
  panel: "#F4F4F4",
  panelEdge: "#E3E3E3",
  ink: "#1A1A1A",
  inkSoft: "#4A4A4A",
  inkMute: "#6B6B6B",
  line: "#E3E3E3",
  blue: "#7DAFD2",
  blueSoft: "#EAF3FA",
};

// ---------------------------------------------------------------------------
// Per-company theming
// ---------------------------------------------------------------------------
// Color helpers - derive the lichte/donkere varianten from a single primary +
// accent hex, so the scraper only has to emit two colors per company.
function hexToRgb(hex) {
  const h = String(hex || "").replace("#", "").trim();
  const s = h.length === 3 ? h.split("").map((c) => c + c).join("") : h;
  const n = parseInt(s, 16);
  if (Number.isNaN(n) || s.length !== 6) return null;
  return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };
}
function rgbToHex({ r, g, b }) {
  const c = (v) => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, "0");
  return `#${c(r)}${c(g)}${c(b)}`.toUpperCase();
}
function mix(hex, target, amt) {
  const a = hexToRgb(hex);
  const b = hexToRgb(target);
  if (!a || !b) return hex;
  return rgbToHex({
    r: a.r + (b.r - a.r) * amt,
    g: a.g + (b.g - a.g) * amt,
    b: a.b + (b.b - a.b) * amt,
  });
}
const darken = (hex, amt) => mix(hex, "#000000", amt);
const lighten = (hex, amt) => mix(hex, "#FFFFFF", amt);
// Relative luminance → pick black/white text that stays readable on `hex`.
function readableText(hex) {
  const c = hexToRgb(hex);
  if (!c) return "#FFFFFF";
  const lum = (0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) / 255;
  return lum > 0.6 ? "#1A1A1A" : "#FFFFFF";
}

// The active company, populated by bootstrap() before the first render.
// Default = neutral Workflow Automations demo (no real client baked in).
let activeCompany = {
  name: "Demo Makelaardij",
  slug: "",
  logo: "assets/logo.png",
  logoDark: null,
  tagline: null,
  primary: "#1F2A44",
  accent: "#3B82F6",
  font: null,
  offices: [],
  nvm: false,
};

// Company initials for the avatar fallback (e.g. "Hoekstra en van Eck" → "HE").
function companyInitials(name) {
  const words = String(name || "").trim().split(/\s+/).filter(Boolean);
  if (!words.length) return "WA";
  if (words.length === 1) return words[0].slice(0, 2).toUpperCase();
  return (words[0][0] + words[words.length - 1][0]).toUpperCase();
}

// Mutate the existing brand/pdfBrand token objects in place from a company's
// primary + accent. Every component reads brand.* / pdfBrand.* at render time,
// so mutating before the first render rebrands the whole app with no further
// changes. Unknown/missing colors fall back to the current token values.
function applyCompanyTheme(company) {
  if (!company) return;
  activeCompany = {
    ...activeCompany,
    ...company,
    offices: Array.isArray(company.offices) ? company.offices : [],
  };
  const primary = hexToRgb(company.primary) ? company.primary : brand.navy;
  const accent = hexToRgb(company.accent) ? company.accent : brand.teal;
  brand.navy = primary;
  brand.navyDeep = darken(primary, 0.28);
  brand.navySoft = lighten(primary, 0.18);
  brand.teal = accent;
  brand.tealDeep = darken(accent, 0.14);
  brand.tealSoft = lighten(accent, 0.82);
  pdfBrand.navy = primary;
  pdfBrand.navyDeep = darken(primary, 0.28);
  pdfBrand.gold = accent;
  pdfBrand.goldDeep = darken(accent, 0.14);

  applyCompanyFont(company.font);
  applyCompanyChrome();
}

// Set the browser tab title + favicon to the active company, so the demo feels
// like the prospect's own document from the moment the tab opens.
function applyCompanyChrome() {
  if (typeof document === "undefined") return;
  if (activeCompany.name) {
    document.title = `Vooronderzoek · ${activeCompany.name}`;
  }
  const href = activeCompany.logo;
  if (!href) return;
  let icon = document.querySelector("link[rel~='icon']");
  if (!icon) {
    icon = document.createElement("link");
    icon.rel = "icon";
    document.head.appendChild(icon);
  }
  icon.href = href;
}

// Load the company's brand font from Google Fonts and point --font-sans at it,
// so every "var(--font-sans)" in the UI and PDF picks it up. Inter stays as the
// fallback if the font fails to load. The mono accent font is left untouched.
function applyCompanyFont(font) {
  if (!font || typeof document === "undefined") return;
  const family = String(font).trim();
  // Guard against non-loadable names (CSS vars, expressions) slipping through.
  if (!family || /var\(|--|[(){},]/.test(family)) return;
  const id = "brand-font";
  if (!document.getElementById(id)) {
    const link = document.createElement("link");
    link.id = id;
    link.rel = "stylesheet";
    const fam = family.replace(/\s+/g, "+");
    link.href = `https://fonts.googleapis.com/css2?family=${fam}:wght@400;500;600;700;800&display=swap`;
    document.head.appendChild(link);
  }
  document.documentElement.style.setProperty(
    "--font-sans",
    `'${family}', 'Inter', system-ui, -apple-system, sans-serif`
  );
}

// ---------------------------------------------------------------------------
// Property registry - multiple addresses with realistic NL data
// ---------------------------------------------------------------------------
const PROPERTIES = {
  keizersgracht: {
    matchTokens: ["keizersgracht"],
    address: { street: "Keizersgracht 123", postal: "1015 CJ", city: "Amsterdam" },
    rd: [120925, 487535],
    heroPhoto: "assets/hero-keizersgracht.png",
    facade: { palette: ["#cf8b4a", "#e9b87a", "#7a4e2b"], style: "grachtenpand" },
    kadaster: {
      eigenaar: "J.M. van der Berg & A.E. de Vries",
      perceel: "AMS04 D 4827",
      oppervlakte: "142 m²",
      eigendom: "Volledig eigendom",
      bouwjaar: "1887",
      woz: "€ 1.245.000",
      peildatum: "1 januari 2025",
    },
    bestemming: {
      type: "Wonen - Gemengd 1",
      gebruik: "Wonen, kleinschalig kantoor aan huis toegestaan",
      bouwhoogte: "max. 14 m",
      uitbreiding: "Uitbouw tot 3 m mogelijk aan achterzijde",
      monument: "Gemeentelijk monument",
      laatstGewijzigd: "12 maart 2024",
    },
    buurt: {
      naam: "Grachtengordel-West",
      inkomen: "€ 58.400",
      leeftijd: [
        { label: "0–20", v: 14 },
        { label: "20–40", v: 38 },
        { label: "40–65", v: 34 },
        { label: "65+", v: 14 },
      ],
      huishouden: [
        { label: "Alleenstaand", v: 52 },
        { label: "Stel zonder kinderen", v: 28 },
        { label: "Gezin", v: 16 },
        { label: "Overig", v: 4 },
      ],
      bewoners: "4.820",
      dichtheid: "11.240 / km²",
    },
    fundering: {
      type: "Houten paalfundering",
      risico: "Verhoogd",
      risicoScore: 0.62,
      laatsteInspectie: "april 2022",
      advies: "Herinspectie binnen 5 jaar aanbevolen",
      grondwater: "Stabiel - NAP −0,40 m",
    },
    vergelijkbaar: [
      { adres: "Herengracht 412", m2: 138, prijs: "€ 1.295.000", verkocht: "feb 2025" },
      { adres: "Prinsengracht 287", m2: 151, prijs: "€ 1.380.000", verkocht: "nov 2024" },
      { adres: "Keizersgracht 89", m2: 134, prijs: "€ 1.210.000", verkocht: "jan 2025" },
      { adres: "Leliegracht 22", m2: 129, prijs: "€ 1.165.000", verkocht: "dec 2024" },
    ],
    markt: {
      trend: "+ 4,2 %",
      periode: "12 maanden",
      gemiddeld: "€ 8.940 / m²",
      serie: [82, 81, 83, 84, 85, 84, 86, 87, 86, 88, 89, 89, 90, 91],
    },
    aankoop: {
      kansen: [
        "Prime locatie binnen Grachtengordel",
        "Stabiele waardeontwikkeling laatste 10 jaar",
        "Uitbouw aan achterzijde planologisch toegestaan",
      ],
      risicos: [
        "Houten fundering - herinspectie binnen 5 jaar",
        "Monumentstatus beperkt verbouwingsvrijheid",
        "Bovengemiddelde VvE-bijdrage te verwachten",
      ],
    },
    hypotheek: {
      woz: "€ 1.245.000",
      indicatie: "€ 996.000",
      maandlast: "€ 4.180",
      rente: "3,89 %",
      looptijd: "30 jaar - annuïtair",
    },
    onderhoud: [
      { jaar: "2023", werk: "Volledige renovatie keuken & badkamer" },
      { jaar: "2019", werk: "Dakvervanging + isolatie" },
      { jaar: "2015", werk: "CV-ketel vervangen (Remeha Tzerra)" },
      { jaar: "2008", werk: "Casco renovatie & schilderwerk gevel" },
    ],
  },
  vondelstraat: {
    matchTokens: ["vondelstraat", "vondel"],
    address: { street: "Vondelstraat 84", postal: "1054 GR", city: "Amsterdam" },
    rd: [119900, 486630],
    heroPhoto: "assets/hero-vondelstraat.png",
    facade: { palette: ["#9a3b3b", "#c76a6a", "#5a1f1f"], style: "herenhuis" },
    kadaster: {
      eigenaar: "Familie Bakker-Hoogendoorn",
      perceel: "AMS09 K 2218",
      oppervlakte: "186 m²",
      eigendom: "Volledig eigendom",
      bouwjaar: "1903",
      woz: "€ 1.510.000",
      peildatum: "1 januari 2025",
    },
    bestemming: {
      type: "Wonen - 1",
      gebruik: "Wonen, beroep aan huis toegestaan",
      bouwhoogte: "max. 16 m",
      uitbreiding: "Dakopbouw mogelijk binnen welstand­kader",
      monument: "Beschermd stadsgezicht",
      laatstGewijzigd: "8 september 2023",
    },
    buurt: {
      naam: "Vondelbuurt",
      inkomen: "€ 64.200",
      leeftijd: [
        { label: "0–20", v: 19 },
        { label: "20–40", v: 32 },
        { label: "40–65", v: 36 },
        { label: "65+", v: 13 },
      ],
      huishouden: [
        { label: "Alleenstaand", v: 38 },
        { label: "Stel zonder kinderen", v: 26 },
        { label: "Gezin", v: 32 },
        { label: "Overig", v: 4 },
      ],
      bewoners: "6.140",
      dichtheid: "9.820 / km²",
    },
    fundering: {
      type: "Betonnen paalfundering (1962)",
      risico: "Laag",
      risicoScore: 0.22,
      laatsteInspectie: "juni 2024",
      advies: "Geen acties vereist",
      grondwater: "Stabiel - NAP −0,55 m",
    },
    vergelijkbaar: [
      { adres: "Vondelstraat 112", m2: 178, prijs: "€ 1.495.000", verkocht: "mrt 2025" },
      { adres: "P.C. Hooftstraat 64", m2: 192, prijs: "€ 1.625.000", verkocht: "okt 2024" },
      { adres: "Roemer Visscherstraat 18", m2: 165, prijs: "€ 1.420.000", verkocht: "feb 2025" },
      { adres: "Tesselschadestraat 7", m2: 174, prijs: "€ 1.555.000", verkocht: "dec 2024" },
    ],
    markt: {
      trend: "+ 5,1 %",
      periode: "12 maanden",
      gemiddeld: "€ 8.120 / m²",
      serie: [78, 79, 80, 81, 82, 83, 83, 85, 86, 86, 88, 89, 90, 91],
    },
    aankoop: {
      kansen: [
        "Direct aan het Vondelpark",
        "Recente fundering - laag risicoprofiel",
        "Mogelijkheid tot dakopbouw",
      ],
      risicos: [
        "Beschermd stadsgezicht - welstandstoets vereist",
        "Geluidsbelasting voorzijde licht verhoogd",
        "Energielabel D - verduurzaming aanbevolen",
      ],
    },
    hypotheek: {
      woz: "€ 1.510.000",
      indicatie: "€ 1.208.000",
      maandlast: "€ 5.060",
      rente: "3,89 %",
      looptijd: "30 jaar - annuïtair",
    },
    onderhoud: [
      { jaar: "2024", werk: "Verduurzaming - HR++ glas & spouwisolatie" },
      { jaar: "2021", werk: "Tuinrenovatie & nieuwe achtergevel" },
      { jaar: "2017", werk: "Volledige badkamer­vervanging" },
      { jaar: "2010", werk: "Schilderwerk & herstel kozijnen" },
    ],
  },
  "witte-de-with": {
    matchTokens: ["witte de with", "withstraat", "rotterdam"],
    address: { street: "Witte de Withstraat 12", postal: "3012 BP", city: "Rotterdam" },
    rd: [92050, 436680],
    heroPhoto: "assets/hero-witte-de-with.png",
    facade: { palette: ["#3a4a5e", "#6b8aa8", "#1f2a38"], style: "modern" },
    kadaster: {
      eigenaar: "B.V. Stadshof Vastgoed",
      perceel: "RTM02 H 1108",
      oppervlakte: "98 m²",
      eigendom: "Erfpacht - afgekocht 2042",
      bouwjaar: "1958",
      woz: "€ 425.000",
      peildatum: "1 januari 2025",
    },
    bestemming: {
      type: "Centrum - Gemengd",
      gebruik: "Wonen + horeca cat. 1 op begane grond",
      bouwhoogte: "max. 22 m",
      uitbreiding: "Geen uitbreiding mogelijk binnen huidig bouwvlak",
      monument: "Geen monumentstatus",
      laatstGewijzigd: "21 juni 2024",
    },
    buurt: {
      naam: "Cool / Witte de With",
      inkomen: "€ 41.800",
      leeftijd: [
        { label: "0–20", v: 11 },
        { label: "20–40", v: 54 },
        { label: "40–65", v: 26 },
        { label: "65+", v: 9 },
      ],
      huishouden: [
        { label: "Alleenstaand", v: 61 },
        { label: "Stel zonder kinderen", v: 24 },
        { label: "Gezin", v: 11 },
        { label: "Overig", v: 4 },
      ],
      bewoners: "3.260",
      dichtheid: "13.450 / km²",
    },
    fundering: {
      type: "Betonnen strookfundering",
      risico: "Laag",
      risicoScore: 0.18,
      laatsteInspectie: "februari 2023",
      advies: "Geen acties vereist",
      grondwater: "Stabiel - NAP −1,20 m",
    },
    vergelijkbaar: [
      { adres: "Schiedamsedijk 38", m2: 92, prijs: "€ 398.000", verkocht: "jan 2025" },
      { adres: "Witte de Withstraat 44", m2: 104, prijs: "€ 445.000", verkocht: "okt 2024" },
      { adres: "Gedempte Zalmhaven 22", m2: 88, prijs: "€ 372.000", verkocht: "feb 2025" },
      { adres: "Mauritsweg 19", m2: 95, prijs: "€ 410.000", verkocht: "nov 2024" },
    ],
    markt: {
      trend: "+ 6,8 %",
      periode: "12 maanden",
      gemiddeld: "€ 4.350 / m²",
      serie: [72, 73, 74, 76, 77, 78, 79, 80, 82, 84, 85, 87, 88, 89],
    },
    aankoop: {
      kansen: [
        "Sterke prijsontwikkeling laatste 24 maanden",
        "Centrale ligging in cultuurkwartier",
        "Lage funderingsrisico",
      ],
      risicos: [
        "Erfpacht - herziening 2042",
        "Geluidsoverlast horeca beneden",
        "Geen uitbreidings­mogelijkheden",
      ],
    },
    hypotheek: {
      woz: "€ 425.000",
      indicatie: "€ 340.000",
      maandlast: "€ 1.430",
      rente: "3,89 %",
      looptijd: "30 jaar - annuïtair",
    },
    onderhoud: [
      { jaar: "2024", werk: "Nieuwe keuken & vloer" },
      { jaar: "2020", werk: "Dakrenovatie + zonnepanelen (4)" },
      { jaar: "2014", werk: "Volledig stuc- en schilderwerk" },
    ],
  },
  oudegracht: {
    matchTokens: ["oudegracht", "utrecht"],
    heroPhoto: "assets/hero-oudegracht.png",
    address: { street: "Oudegracht 220", postal: "3511 NT", city: "Utrecht" },
    rd: [136500, 456350],
    facade: { palette: ["#7a6a4a", "#b69e74", "#3e3422"], style: "werfkelder" },
    kadaster: {
      eigenaar: "L.W. Verhoeven",
      perceel: "UTR01 B 0532",
      oppervlakte: "118 m²",
      eigendom: "Volledig eigendom + werfkelder",
      bouwjaar: "1742",
      woz: "€ 785.000",
      peildatum: "1 januari 2025",
    },
    bestemming: {
      type: "Centrum - Wonen + werken",
      gebruik: "Wonen + werfkelder commercieel verhuurbaar",
      bouwhoogte: "max. 12 m - gevelbeeld behouden",
      uitbreiding: "Werfkelder­uitbreiding richting gracht beoordeeld per geval",
      monument: "Rijksmonument",
      laatstGewijzigd: "4 november 2024",
    },
    buurt: {
      naam: "Binnenstad - Oudegracht",
      inkomen: "€ 49.600",
      leeftijd: [
        { label: "0–20", v: 12 },
        { label: "20–40", v: 46 },
        { label: "40–65", v: 30 },
        { label: "65+", v: 12 },
      ],
      huishouden: [
        { label: "Alleenstaand", v: 48 },
        { label: "Stel zonder kinderen", v: 30 },
        { label: "Gezin", v: 18 },
        { label: "Overig", v: 4 },
      ],
      bewoners: "2.940",
      dichtheid: "10.180 / km²",
    },
    fundering: {
      type: "Houten paalfundering op staal",
      risico: "Hoog",
      risicoScore: 0.84,
      laatsteInspectie: "september 2021",
      advies: "Funderingsherstel binnen 10 jaar gepland",
      grondwater: "Wisselend - NAP −0,30 m tot −0,90 m",
    },
    vergelijkbaar: [
      { adres: "Oudegracht 178", m2: 122, prijs: "€ 795.000", verkocht: "feb 2025" },
      { adres: "Lichte Gaard 6", m2: 110, prijs: "€ 720.000", verkocht: "okt 2024" },
      { adres: "Kromme Nieuwegracht 41", m2: 134, prijs: "€ 875.000", verkocht: "jan 2025" },
      { adres: "Nieuwegracht 88", m2: 115, prijs: "€ 745.000", verkocht: "dec 2024" },
    ],
    markt: {
      trend: "+ 3,1 %",
      periode: "12 maanden",
      gemiddeld: "€ 6.420 / m²",
      serie: [86, 86, 85, 86, 87, 87, 88, 87, 88, 88, 89, 89, 88, 89],
    },
    aankoop: {
      kansen: [
        "Werfkelder genereert verhuur­potentieel",
        "Iconische locatie in binnenstad Utrecht",
        "Rijksmonument - fiscale voordelen mogelijk",
      ],
      risicos: [
        "Funderingsrisico hoog - herstelfonds aanbevolen",
        "Beperkingen door rijksmonument­status",
        "Wisselend grondwaterpeil",
      ],
    },
    hypotheek: {
      woz: "€ 785.000",
      indicatie: "€ 628.000",
      maandlast: "€ 2.640",
      rente: "3,89 %",
      looptijd: "30 jaar - annuïtair",
    },
    onderhoud: [
      { jaar: "2022", werk: "Restauratie houten kozijnen voorgevel" },
      { jaar: "2018", werk: "Werfkelder vochtbestendig gemaakt" },
      { jaar: "2012", werk: "Volledige binnen­renovatie" },
      { jaar: "2005", werk: "Schoorsteen & dakgoten vervangen" },
    ],
  },
};

// Match a free-form query to a property key.
function matchProperty(query) {
  const q = query.toLowerCase();
  for (const [key, p] of Object.entries(PROPERTIES)) {
    if (p.matchTokens.some((t) => q.includes(t))) return key;
  }
  return "keizersgracht"; // default
}

const RECENT_QUERIES = [
  "Keizersgracht 123, Amsterdam",
  "Vondelstraat 84, Amsterdam",
  "Witte de Withstraat 12, Rotterdam",
  "Oudegracht 220, Utrecht",
];

const TODAY_NL = "6 mei 2026";

// Kantoorgegevens voor de contactstrook op de voorpagina worden per klant
// gevuld vanuit activeCompany.offices (gescrapet uit de website-footer).

// ---------------------------------------------------------------------------
// Logo lockup
// ---------------------------------------------------------------------------
function LogoMark({ size = 84, maxWidthRatio = 4.5 }) {
  // Bound by both height and width so wide wordmark logos (e.g. a very wide,
  // short logo) scale down to fit instead of sprawling across the bar.
  return (
    <img
      src={activeCompany.logo}
      alt={activeCompany.name}
      style={{
        display: "block",
        height: "auto",
        width: "auto",
        maxHeight: size,
        maxWidth: size * maxWidthRatio,
        objectFit: "contain",
      }}
    />
  );
}

function LogoLockup({ inverted = false, compact = false }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
      <LogoMark size={compact ? 31 : 96} />
      <div style={{ display: "flex", flexDirection: "column", lineHeight: 1 }}>
        <span
          style={{
            fontFamily: "var(--font-mono)",
            fontSize: 11,
            letterSpacing: "0.18em",
            textTransform: "uppercase",
            color: inverted ? "rgba(255,255,255,0.6)" : brand.inkMute,
          }}
        >
          Generator
        </span>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Property Image - stylized SVG illustration tinted per property
// ---------------------------------------------------------------------------
function PropertyImage({ property, height = 280, rounded = false }) {
  const [c1, c2, c3] = property.facade.palette;
  const style = property.facade.style;
  const id = property.address.street.replace(/\W/g, "");

  // Real photo when available, otherwise the procedural SVG facade.
  if (property.heroPhoto) {
    return (
      <div
        style={{
          width: "100%",
          height,
          borderRadius: rounded ? 8 : 4,
          overflow: "hidden",
          position: "relative",
          background: "#1c2d52",
        }}
      >
        <img
          src={property.heroPhoto}
          alt=""
          crossOrigin="anonymous"
          style={{
            width: "100%",
            height: "100%",
            objectFit: "cover",
            display: "block",
          }}
        />
      </div>
    );
  }

  // Sky + ground gradient (subtle, doesn't fight brand)
  return (
    <div
      style={{
        width: "100%",
        height,
        borderRadius: rounded ? 8 : 4,
        overflow: "hidden",
        position: "relative",
        background: `linear-gradient(180deg, #2a3f60 0%, #4a6285 60%, #6c5a3e 100%)`,
      }}
    >
      <svg
        viewBox="0 0 800 320"
        width="100%"
        height="100%"
        preserveAspectRatio="xMidYMid slice"
        style={{ display: "block" }}
      >
        <defs>
          <linearGradient id={`sky-${id}`} x1="0" x2="0" y1="0" y2="1">
            <stop offset="0%" stopColor="#2a3f60" />
            <stop offset="100%" stopColor="#7088a8" />
          </linearGradient>
          <linearGradient id={`facadeA-${id}`} x1="0" x2="0" y1="0" y2="1">
            <stop offset="0%" stopColor={c1} />
            <stop offset="100%" stopColor={c3} />
          </linearGradient>
          <linearGradient id={`facadeB-${id}`} x1="0" x2="0" y1="0" y2="1">
            <stop offset="0%" stopColor={c2} />
            <stop offset="100%" stopColor={c1} />
          </linearGradient>
          <pattern id={`bricks-${id}`} width="14" height="6" patternUnits="userSpaceOnUse">
            <rect width="14" height="6" fill="transparent" />
            <line x1="0" y1="6" x2="14" y2="6" stroke="rgba(0,0,0,0.10)" strokeWidth="0.5" />
            <line x1="7" y1="0" x2="7" y2="6" stroke="rgba(0,0,0,0.10)" strokeWidth="0.5" />
          </pattern>
        </defs>

        {/* sky */}
        <rect x="0" y="0" width="800" height="320" fill={`url(#sky-${id})`} />
        {/* clouds */}
        <ellipse cx="180" cy="60" rx="80" ry="10" fill="rgba(255,255,255,0.12)" />
        <ellipse cx="560" cy="40" rx="120" ry="8" fill="rgba(255,255,255,0.10)" />

        {style === "grachtenpand" && <Grachtenpand id={id} />}
        {style === "herenhuis" && <Herenhuis id={id} />}
        {style === "modern" && <Modern id={id} />}
        {style === "werfkelder" && <Werfkelder id={id} />}

        {/* foreground street */}
        <rect x="0" y="290" width="800" height="30" fill="rgba(0,0,0,0.35)" />
      </svg>
    </div>
  );
}

function row(n, w, gap, startX, y, h, fillId) {
  return Array.from({ length: n }, (_, i) => (
    <rect
      key={i}
      x={startX + i * (w + gap)}
      y={y}
      width={w}
      height={h}
      fill={`url(#${fillId})`}
      stroke="rgba(0,0,0,0.18)"
      strokeWidth="0.7"
    />
  ));
}

function windowPane(x, y, w, h, lit = false) {
  return (
    <g key={`${x}-${y}`}>
      <rect x={x} y={y} width={w} height={h} fill={lit ? "#f2d27a" : "#1c2d52"} stroke="rgba(255,255,255,0.5)" strokeWidth="0.6" />
      <line x1={x + w / 2} y1={y} x2={x + w / 2} y2={y + h} stroke="rgba(255,255,255,0.4)" strokeWidth="0.5" />
      <line x1={x} y1={y + h / 2} x2={x + w} y2={y + h / 2} stroke="rgba(255,255,255,0.4)" strokeWidth="0.5" />
    </g>
  );
}

// Amsterdam canal house - gabled, narrow, tall
function Grachtenpand({ id }) {
  return (
    <g>
      {/* neighbor left */}
      <rect x="0" y="120" width="180" height="170" fill={`url(#facadeB-${id})`} opacity="0.7" />
      <rect x="0" y="120" width="180" height="170" fill={`url(#bricks-${id})`} />
      {[0, 1, 2].map((r) =>
        [0, 1, 2].map((c) =>
          windowPane(20 + c * 50, 140 + r * 45, 30, 28, r === 1 && c === 0)
        )
      )}
      {/* main building - narrow gable */}
      <polygon points="200,90 320,60 440,90 440,290 200,290" fill={`url(#facadeA-${id})`} />
      <rect x="200" y="90" width="240" height="200" fill={`url(#bricks-${id})`} />
      {/* gable accent */}
      <polygon points="200,90 320,60 440,90" fill="rgba(255,255,255,0.06)" />
      <circle cx="320" cy="78" r="6" fill="rgba(255,255,255,0.4)" />
      {/* windows grid */}
      {[0, 1, 2, 3].map((r) =>
        [0, 1, 2].map((c) =>
          windowPane(220 + c * 70, 110 + r * 42, 44, 32, r === 1 && c === 1)
        )
      )}
      {/* door */}
      <rect x="300" y="240" width="40" height="50" fill="#3a2818" stroke="rgba(255,255,255,0.4)" />
      <rect x="316" y="252" width="8" height="20" fill="#1a1208" />
      {/* stoep */}
      <rect x="290" y="285" width="60" height="6" fill="#2a2018" />
      {/* neighbor right */}
      <rect x="460" y="135" width="200" height="155" fill={`url(#facadeB-${id})`} opacity="0.6" />
      <rect x="460" y="135" width="200" height="155" fill={`url(#bricks-${id})`} />
      {[0, 1, 2].map((r) =>
        [0, 1, 2, 3].map((c) =>
          windowPane(478 + c * 45, 152 + r * 42, 28, 28)
        )
      )}
      {/* far right */}
      <rect x="680" y="155" width="120" height="135" fill={`url(#facadeA-${id})`} opacity="0.5" />
      {/* canal water */}
      <rect x="0" y="270" width="800" height="20" fill="#1c3852" opacity="0.7" />
      <line x1="0" y1="278" x2="800" y2="278" stroke="rgba(255,255,255,0.15)" strokeWidth="0.5" />
      <line x1="0" y1="284" x2="800" y2="284" stroke="rgba(255,255,255,0.15)" strokeWidth="0.5" />
    </g>
  );
}

// Vondelstraat-style red brick herenhuis
function Herenhuis({ id }) {
  return (
    <g>
      {/* neighbors */}
      <rect x="0" y="110" width="180" height="180" fill={`url(#facadeB-${id})`} opacity="0.7" />
      <rect x="0" y="110" width="180" height="180" fill={`url(#bricks-${id})`} />
      {/* main herenhuis - wider, bay window */}
      <rect x="200" y="80" width="400" height="210" fill={`url(#facadeA-${id})`} />
      <rect x="200" y="80" width="400" height="210" fill={`url(#bricks-${id})`} />
      {/* roof */}
      <polygon points="190,80 400,40 610,80" fill="#2a1a1a" />
      <rect x="370" y="20" width="14" height="30" fill="#3a2a2a" />
      {/* bay window */}
      <rect x="240" y="180" width="120" height="100" fill={`url(#facadeB-${id})`} />
      {windowPane(248, 188, 32, 80, true)}
      {windowPane(284, 188, 32, 80, true)}
      {windowPane(320, 188, 32, 80)}
      {/* upper rows */}
      {[0, 1].map((r) =>
        [0, 1, 2, 3].map((c) =>
          windowPane(220 + c * 95, 100 + r * 42, 60, 32, r === 0 && c === 2)
        )
      )}
      {/* door */}
      <rect x="450" y="200" width="50" height="80" fill="#1f1208" stroke="rgba(255,255,255,0.4)" />
      <rect x="455" y="210" width="40" height="30" fill="#2a1810" />
      <circle cx="491" cy="240" r="2" fill="#c9a878" />
      {/* neighbor right */}
      <rect x="620" y="120" width="180" height="170" fill={`url(#facadeB-${id})`} opacity="0.7" />
      <rect x="620" y="120" width="180" height="170" fill={`url(#bricks-${id})`} />
      {/* trees */}
      <circle cx="120" cy="240" r="32" fill="#2d4a2d" opacity="0.85" />
      <circle cx="700" cy="245" r="28" fill="#2d4a2d" opacity="0.85" />
    </g>
  );
}

// Rotterdam modern apartment
function Modern({ id }) {
  return (
    <g>
      {/* tall tower left */}
      <rect x="40" y="40" width="160" height="250" fill={`url(#facadeB-${id})`} />
      {[...Array(7)].map((_, r) =>
        [...Array(4)].map((__, c) =>
          windowPane(54 + c * 35, 60 + r * 32, 26, 22, (r + c) % 5 === 0)
        )
      )}
      {/* main building - modernist horizontal bands */}
      <rect x="220" y="100" width="380" height="190" fill={`url(#facadeA-${id})`} />
      {/* horizontal window bands */}
      {[0, 1, 2, 3].map((r) => (
        <rect
          key={r}
          x="230"
          y={115 + r * 42}
          width="360"
          height="22"
          fill="#1c2d52"
          stroke="rgba(255,255,255,0.4)"
          strokeWidth="0.6"
        />
      ))}
      {/* mullions */}
      {[0, 1, 2, 3].map((r) =>
        [...Array(8)].map((_, c) => (
          <line
            key={`${r}-${c}`}
            x1={230 + c * 45}
            y1={115 + r * 42}
            x2={230 + c * 45}
            y2={115 + r * 42 + 22}
            stroke="rgba(255,255,255,0.3)"
            strokeWidth="0.5"
          />
        ))
      )}
      {/* lit windows */}
      {windowPane(275, 115, 40, 22, true)}
      {windowPane(455, 199, 40, 22, true)}
      {/* entry */}
      <rect x="380" y="240" width="60" height="50" fill="#0a1530" stroke="rgba(255,255,255,0.5)" />
      {/* right block */}
      <rect x="620" y="140" width="160" height="150" fill={`url(#facadeB-${id})`} opacity="0.85" />
      {[...Array(4)].map((_, r) =>
        [...Array(3)].map((__, c) =>
          windowPane(636 + c * 42, 152 + r * 32, 32, 22, r === 0 && c === 1)
        )
      )}
    </g>
  );
}

// Utrecht werfkelder canal house
function Werfkelder({ id }) {
  return (
    <g>
      {/* neighbors */}
      <rect x="0" y="130" width="180" height="160" fill={`url(#facadeB-${id})`} opacity="0.7" />
      <rect x="0" y="130" width="180" height="160" fill={`url(#bricks-${id})`} />
      {/* main - short and wide, stepped gable */}
      <polygon
        points="200,110 230,90 260,90 260,75 320,75 320,90 350,90 380,110 380,290 200,290"
        fill={`url(#facadeA-${id})`}
      />
      <rect x="200" y="110" width="180" height="180" fill={`url(#bricks-${id})`} />
      {/* windows */}
      {[0, 1].map((r) =>
        [0, 1, 2].map((c) =>
          windowPane(218 + c * 55, 130 + r * 50, 38, 32, r === 0 && c === 1)
        )
      )}
      {/* door */}
      <rect x="270" y="240" width="38" height="50" fill="#2a1c10" stroke="rgba(255,255,255,0.4)" />
      {/* werfkelder - arch below water level */}
      <rect x="200" y="270" width="180" height="20" fill="#1a1208" />
      <path d="M 220 290 Q 240 260 260 290 Z" fill="#0a0500" />
      <path d="M 320 290 Q 340 260 360 290 Z" fill="#0a0500" />
      {/* neighbors right */}
      <rect x="400" y="120" width="180" height="170" fill={`url(#facadeB-${id})`} opacity="0.7" />
      <rect x="400" y="120" width="180" height="170" fill={`url(#bricks-${id})`} />
      <rect x="600" y="140" width="200" height="150" fill={`url(#facadeA-${id})`} opacity="0.6" />
      {/* canal */}
      <rect x="0" y="270" width="800" height="20" fill="#3d3424" opacity="0.6" />
    </g>
  );
}

// ---------------------------------------------------------------------------
// App shell
// ---------------------------------------------------------------------------
function App() {
  const [stage, setStage] = useState("search");
  const [query, setQuery] = useState("Keizersgracht 123, Amsterdam");
  const [activeKey, setActiveKey] = useState("keizersgracht");
  const [progress, setProgress] = useState(0);
  const [statusMsg, setStatusMsg] = useState("");
  const [extras, setExtras] = useState([]); // [{id, kind, sourceFile?}]

  function generate() {
    if (!query.trim()) return;
    setActiveKey(matchProperty(query));
    setStage("loading");
    setProgress(0);
  }

  useEffect(() => {
    if (stage !== "loading") return;
    const steps = [
      { at: 0,  msg: "Adres valideren bij PDOK Locatieserver…" },
      { at: 10, msg: "Kadaster - Eigendomsinformatie (BRK) ophalen…" },
      { at: 22, msg: "PDOK - Kadastrale Kaart (WMS) renderen…" },
      { at: 34, msg: "BAG - adres- en gebouwgegevens laden…" },
      { at: 44, msg: "WOZ-waardeloket - 12-jaars historie ophalen…" },
      { at: 56, msg: "EP-Online (RVO) - definitief energielabel…" },
      { at: 66, msg: "DSO Omgevingsloket - bestemmingsplan raadplegen…" },
      { at: 76, msg: "CBS - kerncijfers buurten en wijken laden…" },
      { at: 86, msg: "FunderMaps / KCAF - funderingsrisico…" },
      { at: 95, msg: "Boekje samenstellen…" },
    ];
    let p = 0;
    const t = setInterval(() => {
      // Non-linear pacing: dwell longer on Kadaster (18–42%) so it doesn't
      // feel like a straight progress bar.
      const inKadaster = p >= 18 && p < 42;
      const step = inKadaster
        ? 0.4 + Math.random() * 0.8
        : 2 + Math.random() * 3;
      p += step;
      if (p >= 100) {
        p = 100;
        clearInterval(t);
        setProgress(100);
        setStatusMsg("Klaar.");
        setTimeout(() => setStage("booklet"), 350);
        return;
      }
      setProgress(p);
      const cur = [...steps].reverse().find((s) => p >= s.at);
      if (cur) setStatusMsg(cur.msg);
    }, 55);
    return () => clearInterval(t);
  }, [stage]);

  function reset() {
    setStage("search");
    setExtras([]);
    setProgress(0);
  }

  const property = PROPERTIES[activeKey];

  return (
    <div style={{ minHeight: "100vh", background: brand.panel, color: brand.ink }}>
      <TopBar onReset={reset} />
      {stage === "search" && (
        <SearchScreen query={query} setQuery={setQuery} onGenerate={generate} />
      )}
      {stage === "loading" && (
        <LoadingScreen query={query} progress={progress} statusMsg={statusMsg} />
      )}
      {stage === "booklet" && (
        <BookletScreen
          property={property}
          extras={extras}
          setExtras={setExtras}
          onReset={reset}
        />
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Top bar
// ---------------------------------------------------------------------------
function TopBar({ onReset }) {
  return (
    <div
      style={{
        height: 60,
        borderBottom: `1px solid ${brand.panelEdge}`,
        background: "#ffffff",
        display: "flex",
        alignItems: "center",
        justifyContent: "space-between",
        padding: "0 28px",
        position: "sticky",
        top: 0,
        zIndex: 50,
      }}
    >
      <div onClick={onReset} style={{ cursor: "pointer", display: "flex", alignItems: "center" }}>
        <LogoLockup compact />
      </div>
      <nav style={{ display: "flex", gap: 28, alignItems: "center" }}>
        {["Dashboard", "Boekjes", "Klanten", "Instellingen"].map((x, i) => (
          <span
            key={x}
            style={{
              fontFamily: "var(--font-sans)",
              fontSize: 13.5,
              color: i === 1 ? brand.navy : brand.inkSoft,
              fontWeight: i === 1 ? 600 : 500,
              cursor: "pointer",
            }}
          >
            {x}
          </span>
        ))}
        <div
          style={{
            width: 32,
            height: 32,
            borderRadius: 999,
            background: `linear-gradient(135deg, ${brand.navy}, ${brand.teal})`,
            color: "white",
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            fontFamily: "var(--font-sans)",
            fontSize: 12,
            fontWeight: 600,
          }}
        >
          {companyInitials(activeCompany.name)}
        </div>
      </nav>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Stage 1 - Search
// ---------------------------------------------------------------------------
function SearchScreen({ query, setQuery, onGenerate }) {
  return (
    <div style={{ maxWidth: 760, margin: "0 auto", padding: "48px 28px 120px" }}>
      <div
        style={{
          fontFamily: "var(--font-mono)",
          fontSize: 11,
          letterSpacing: "0.22em",
          textTransform: "uppercase",
          color: brand.tealDeep,
          marginBottom: 18,
        }}
      >
        Nieuw boekje · stap 1 van 3
      </div>
      <h1
        style={{
          fontFamily: "var(--font-sans)",
          fontSize: 56,
          lineHeight: 1.05,
          letterSpacing: "-0.02em",
          margin: 0,
          color: brand.navy,
          textWrap: "pretty",
        }}
      >
        Genereer een vooronderzoek<br />
        <span style={{ color: brand.inkSoft, fontStyle: "italic" }}>op basis van één adres.</span>
      </h1>
      <p
        style={{
          fontFamily: "var(--font-sans)",
          fontSize: 15.5,
          color: brand.inkSoft,
          maxWidth: 520,
          marginTop: 22,
          lineHeight: 1.55,
        }}
      >
        Wij combineren Kadaster, BAG, CBS, bestemmingsplan en funderingsdata
        tot één gebrand document - klaar om te delen met uw kopers.
      </p>
      <p
        style={{
          fontFamily: "var(--font-sans)",
          fontSize: 13.5,
          color: brand.inkMute,
          maxWidth: 520,
          marginTop: 10,
          lineHeight: 1.5,
        }}
      >
        Dit is een demo - kies hieronder een van de voorbeeldadressen. Eigen
        adressen worden in deze demo nog niet doorzocht.
      </p>

      <div
        style={{
          marginTop: 44,
          background: "#fff",
          border: `1px solid ${brand.panelEdge}`,
          borderRadius: 14,
          padding: 8,
          display: "flex",
          alignItems: "center",
          gap: 8,
          boxShadow: "0 1px 2px rgba(15,30,61,0.04), 0 8px 28px rgba(15,30,61,0.06)",
        }}
      >
        <div style={{ width: 44, display: "flex", justifyContent: "center", color: brand.inkMute }}>
          <SearchIcon />
        </div>
        <input
          value={query}
          readOnly
          onKeyDown={(e) => e.key === "Enter" && onGenerate()}
          placeholder="Kies hieronder een voorbeeldadres"
          title="Demo - selecteer een van de voorbeeldadressen hieronder"
          style={{
            flex: 1,
            border: "none",
            outline: "none",
            fontFamily: "var(--font-sans)",
            fontSize: 16,
            color: brand.ink,
            background: "transparent",
            padding: "14px 0",
            cursor: "default",
          }}
        />
        <button
          onClick={onGenerate}
          style={{
            background: brand.navy,
            color: "white",
            border: "none",
            borderRadius: 10,
            padding: "12px 22px",
            fontFamily: "var(--font-sans)",
            fontSize: 14,
            fontWeight: 600,
            cursor: "pointer",
            display: "flex",
            alignItems: "center",
            gap: 8,
          }}
          onMouseOver={(e) => (e.currentTarget.style.background = brand.navyDeep)}
          onMouseOut={(e) => (e.currentTarget.style.background = brand.navy)}
        >
          Genereer boekje
          <ArrowRight />
        </button>
      </div>

      <div style={{ marginTop: 18, display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" }}>
        <span
          style={{
            fontFamily: "var(--font-mono)",
            fontSize: 11,
            color: brand.inkMute,
            letterSpacing: "0.1em",
            textTransform: "uppercase",
            marginRight: 4,
          }}
        >
          Voorbeeldadressen
        </span>
        {RECENT_QUERIES.map((r) => (
          <button
            key={r}
            onClick={() => setQuery(r)}
            style={{
              border: `1px solid ${brand.panelEdge}`,
              background: "#fff",
              borderRadius: 999,
              padding: "6px 14px",
              fontFamily: "var(--font-sans)",
              fontSize: 12.5,
              color: brand.inkSoft,
              cursor: "pointer",
            }}
          >
            {r}
          </button>
        ))}
      </div>

      <div
        style={{
          marginTop: 72,
          display: "grid",
          gridTemplateColumns: "repeat(4, 1fr)",
          gap: 12,
        }}
      >
        {[
          { k: "Kadaster BRK", v: "Eigenaar & perceel" },
          { k: "PDOK Kadastrale Kaart", v: "Perceelgrenzen (WMS)" },
          { k: "BAG", v: "Bouwjaar & oppervlakte" },
          { k: "WOZ-waardeloket", v: "12-jaars waardereeks" },
          { k: "EP-Online (RVO)", v: "Definitief energielabel" },
          { k: "DSO Omgevingsloket", v: "Bestemmingsplan" },
          { k: "CBS Buurten", v: "Demografie & inkomen" },
          { k: "FunderMaps / KCAF", v: "Funderingsrisico" },
        ].map((s) => (
          <div
            key={s.k}
            style={{
              background: "#fff",
              border: `1px solid ${brand.panelEdge}`,
              borderRadius: 10,
              padding: 14,
            }}
          >
            <div
              style={{
                fontFamily: "var(--font-mono)",
                fontSize: 9.5,
                letterSpacing: "0.16em",
                textTransform: "uppercase",
                color: brand.tealDeep,
              }}
            >
              Bron
            </div>
            <div
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: 15,
                fontWeight: 600,
                color: brand.navy,
                marginTop: 6,
                lineHeight: 1.2,
              }}
            >
              {s.k}
            </div>
            <div
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: 12,
                color: brand.inkSoft,
                marginTop: 4,
                lineHeight: 1.35,
              }}
            >
              {s.v}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Stage 1.5 - Loading
// ---------------------------------------------------------------------------
function LoadingScreen({ query, progress, statusMsg }) {
  return (
    <div style={{ maxWidth: 720, margin: "0 auto", padding: "120px 28px 80px" }}>
      <div
        style={{
          background: "#fff",
          border: `1px solid ${brand.panelEdge}`,
          borderRadius: 16,
          padding: 36,
          boxShadow: "0 8px 32px rgba(15,30,61,0.07)",
        }}
      >
        <div style={{ display: "flex", alignItems: "center", gap: 16, marginBottom: 28 }}>
          <Spinner />
          <div>
            <div
              style={{
                fontFamily: "var(--font-mono)",
                fontSize: 11,
                letterSpacing: "0.18em",
                textTransform: "uppercase",
                color: brand.tealDeep,
              }}
            >
              Bezig met genereren
            </div>
            <div
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: 26,
                color: brand.navy,
                marginTop: 4,
                letterSpacing: "-0.01em",
              }}
            >
              {query}
            </div>
          </div>
        </div>
        <div style={{ height: 6, background: brand.panel, borderRadius: 999, overflow: "hidden" }}>
          <div
            style={{
              width: `${progress}%`,
              height: "100%",
              background: `linear-gradient(90deg, ${brand.navy}, ${brand.teal})`,
              transition: "width .25s ease-out",
            }}
          />
        </div>
        <div
          style={{
            display: "flex",
            justifyContent: "space-between",
            marginTop: 12,
            fontFamily: "var(--font-mono)",
            fontSize: 12,
            color: brand.inkSoft,
          }}
        >
          <span>{statusMsg}</span>
          <span>{Math.floor(progress)}%</span>
        </div>
        <div
          style={{
            marginTop: 32,
            display: "grid",
            gridTemplateColumns: "repeat(4, 1fr)",
            gap: 8,
          }}
        >
          {[
            { label: "PDOK", at: 10 },
            { label: "Kadaster BRK", at: 22 },
            { label: "Kadastrale Kaart", at: 34 },
            { label: "BAG", at: 44 },
            { label: "WOZ-loket", at: 56 },
            { label: "EP-Online", at: 66 },
            { label: "DSO", at: 76 },
            { label: "CBS", at: 86 },
            { label: "FunderMaps", at: 95 },
          ].map((s) => {
            const done = progress >= s.at;
            return (
              <div
                key={s.label}
                style={{
                  border: `1px solid ${done ? brand.teal : brand.panelEdge}`,
                  background: done ? brand.tealSoft : brand.panel,
                  color: done ? brand.tealDeep : brand.inkMute,
                  padding: "8px 10px",
                  borderRadius: 8,
                  fontFamily: "var(--font-mono)",
                  fontSize: 10,
                  letterSpacing: "0.08em",
                  textTransform: "uppercase",
                  display: "flex",
                  alignItems: "center",
                  justifyContent: "space-between",
                  transition: "all .25s",
                }}
              >
                <span>{s.label}</span>
                <span>{done ? "✓" : "…"}</span>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Stage 2 - Booklet
// ---------------------------------------------------------------------------
function BookletScreen({ property, extras, setExtras, onReset }) {
  return (
    <div
      style={{
        maxWidth: 1200,
        margin: "0 auto",
        padding: "32px 28px 120px",
        display: "grid",
        gridTemplateColumns: "1fr 380px",
        gap: 28,
        alignItems: "start",
      }}
    >
      <div>
        <BookletToolbar property={property} onReset={onReset} />
        <div
          id="pdf-export-area"
          style={{
            display: "flex",
            flexDirection: "column",
            alignItems: "center",
            gap: 24,
          }}
        >
          <PdfBooklet property={property} extras={extras} />
        </div>
      </div>
      <div
        style={{
          position: "sticky",
          top: 92,
          maxHeight: "calc(100vh - 112px)",
          overflowY: "auto",
        }}
      >
        <UitbreidenPanel extras={extras} setExtras={setExtras} property={property} />
      </div>
    </div>
  );
}

// Convert every <img src="*.svg"> inside `root` into an equivalent PNG data-URL
// at its on-screen rendered size, so html2canvas (which can't rasterise SVG
// <img>) reproduces them in the PDF. Returns a function that restores the
// original src attributes.
async function rasterizeSvgImages(root) {
  if (!root) return () => {};
  const imgs = Array.from(root.querySelectorAll("img")).filter((img) =>
    /\.svg(\?|$)/i.test(img.getAttribute("src") || "")
  );
  const restores = [];
  await Promise.all(
    imgs.map(async (img) => {
      const orig = img.getAttribute("src");
      try {
        const res = await fetch(orig);
        const svgText = await res.text();
        const dataUri =
          "data:image/svg+xml;base64," +
          btoa(unescape(encodeURIComponent(svgText)));
        const im = new Image();
        im.crossOrigin = "anonymous";
        await new Promise((resolve, reject) => {
          im.onload = resolve;
          im.onerror = reject;
          im.src = dataUri;
        });
        const rect = img.getBoundingClientRect();
        const scale = 3;
        const w = Math.max(1, Math.round((rect.width || im.naturalWidth || 120) * scale));
        const h = Math.max(1, Math.round((rect.height || im.naturalHeight || 40) * scale));
        const canvas = document.createElement("canvas");
        canvas.width = w;
        canvas.height = h;
        canvas.getContext("2d").drawImage(im, 0, 0, w, h);
        restores.push([img, orig]);
        img.setAttribute("src", canvas.toDataURL("image/png"));
      } catch (e) {
        console.warn("Kon SVG-logo niet omzetten voor PDF:", orig, e);
      }
    })
  );
  return () => restores.forEach(([img, src]) => img.setAttribute("src", src));
}

function BookletToolbar({ property, onReset }) {
  const [downloading, setDownloading] = useState(false);

  async function handleDownload() {
    if (downloading) return;
    const pages = Array.from(
      document.querySelectorAll("#pdf-export-area .pdf-a4-page")
    );
    const html2canvas = window.html2canvas;
    const jsPDFCtor = window.jspdf && window.jspdf.jsPDF;
    if (pages.length === 0 || !html2canvas || !jsPDFCtor) {
      alert(
        "PDF-export niet beschikbaar - controleer je internetverbinding (html2pdf.js wordt via CDN geladen)."
      );
      return;
    }
    setDownloading(true);
    document.body.classList.add("pdf-export");
    // html2canvas can't rasterise <img src="*.svg"> reliably, so several brand
    // logos come out blank in the PDF. Pre-convert any SVG logos in the export
    // area to PNG data-URLs (at their rendered size), then restore afterwards.
    const restoreLogos = await rasterizeSvgImages(
      document.getElementById("pdf-export-area")
    );
    try {
      const pdf = new jsPDFCtor({
        unit: "mm",
        format: "a4",
        orientation: "portrait",
        compress: true,
      });
      const pageW = pdf.internal.pageSize.getWidth();   // 210mm
      const pageH = pdf.internal.pageSize.getHeight();  // 297mm

      // A4 in CSS pixels at 96 DPI - keeps source aspect ratio identical to
      // the destination, so addImage doesn't have to stretch.
      const A4_W = (210 / 25.4) * 96;
      const A4_H = (297 / 25.4) * 96;

      for (let i = 0; i < pages.length; i++) {
        const el = pages[i];
        const canvas = await html2canvas(el, {
          scale: 2,
          useCORS: true,
          backgroundColor: "#FFFFFF",
          logging: false,
          width: A4_W,
          height: A4_H,
          windowWidth: A4_W,
          windowHeight: A4_H,
        });
        if (i > 0) pdf.addPage();
        pdf.addImage(
          canvas.toDataURL("image/jpeg", 0.92),
          "JPEG",
          0,
          0,
          pageW,
          pageH,
          undefined,
          "FAST"
        );
      }

      const safeStreet = (property.address.street || "vooronderzoek").replace(/[^\w\-]+/g, "-");
      const safeCity = (property.address.city || "").replace(/[^\w\-]+/g, "-");
      pdf.save(`Vooronderzoek - ${safeStreet}${safeCity ? ", " + safeCity : ""}.pdf`);
    } catch (e) {
      console.error(e);
      alert("Er ging iets mis bij het genereren van de PDF.");
    } finally {
      restoreLogos();
      document.body.classList.remove("pdf-export");
      setDownloading(false);
    }
  }

  return (
    <div
      style={{
        display: "flex",
        alignItems: "center",
        justifyContent: "space-between",
        marginBottom: 20,
      }}
    >
      <div>
        <div
          style={{
            fontFamily: "var(--font-mono)",
            fontSize: 11,
            letterSpacing: "0.2em",
            textTransform: "uppercase",
            color: brand.tealDeep,
          }}
        >
          Boekje · concept
        </div>
        <div
          style={{
            fontFamily: "var(--font-sans)",
            fontSize: 28,
            fontWeight: 700,
            color: brand.navy,
            marginTop: 4,
            letterSpacing: "-0.01em",
          }}
        >
          {property.address.street}, {property.address.city}
        </div>
      </div>
      <div style={{ display: "flex", gap: 8 }}>
        <button
          onClick={onReset}
          style={{
            background: "#fff",
            color: brand.inkSoft,
            border: `1px solid ${brand.panelEdge}`,
            borderRadius: 10,
            padding: "10px 16px",
            fontFamily: "var(--font-sans)",
            fontSize: 13,
            fontWeight: 500,
            cursor: "pointer",
          }}
        >
          ← Nieuw boekje
        </button>
        {/* "Delen" button hidden for now. */}
        <button
          onClick={handleDownload}
          disabled={downloading}
          style={{
            background: brand.navy,
            color: "white",
            border: "none",
            borderRadius: 10,
            padding: "10px 18px",
            fontFamily: "var(--font-sans)",
            fontSize: 13,
            fontWeight: 600,
            cursor: downloading ? "wait" : "pointer",
            opacity: downloading ? 0.7 : 1,
            display: "inline-flex",
            alignItems: "center",
            gap: 8,
          }}
        >
          {downloading ? <Spinner small /> : null}
          {downloading ? "PDF wordt gemaakt…" : "Download PDF"}
        </button>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Booklet pages
// ---------------------------------------------------------------------------
function Booklet({ property, extras }) {
  const baseSections = [
    { key: "cover", el: <CoverPage property={property} /> },
    { key: "kadaster", el: <KadasterPage property={property} /> },
    { key: "bestemming", el: <BestemmingPage property={property} /> },
    { key: "buurt", el: <BuurtPage property={property} /> },
    { key: "fundering", el: <FunderingPage property={property} /> },
  ];

  const extraComponents = {
    vergelijkbaar: <VergelijkbaarPage property={property} />,
    markt: <MarktPage property={property} />,
    aankoop: <AankoopPage property={property} />,
    hypotheek: <HypotheekPage property={property} />,
    onderhoud: <OnderhoudPage property={property} />,
  };

  return (
    <div id="booklet-pdf-root" style={{ display: "flex", flexDirection: "column", gap: 24 }}>
      {baseSections.map((s) => (
        <Page key={s.key}>{s.el}</Page>
      ))}
      {extras.map((ex) => (
        <Page key={ex.id} animateIn>
          {ex.kind === "upload" ? (
            <UploadedDocPage doc={ex} />
          ) : (
            extraComponents[ex.kind]
          )}
        </Page>
      ))}
    </div>
  );
}

function Page({ children, animateIn }) {
  const [shown, setShown] = useState(!animateIn);
  useEffect(() => {
    if (animateIn) {
      const t = setTimeout(() => setShown(true), 30);
      return () => clearTimeout(t);
    }
  }, [animateIn]);
  return (
    <div
      className="pdf-page"
      style={{
        background: brand.paper,
        border: `1px solid ${brand.panelEdge}`,
        borderRadius: 4,
        boxShadow: "0 1px 2px rgba(15,30,61,0.04), 0 16px 40px -16px rgba(15,30,61,0.12)",
        overflow: "hidden",
        width: "100%",
        aspectRatio: "210 / 297",
        opacity: shown ? 1 : 0,
        transform: shown ? "translateY(0)" : "translateY(24px)",
        transition: "opacity .5s ease, transform .5s ease",
      }}
    >
      {children}
    </div>
  );
}

function PageHeader({ kicker, title, n }) {
  return (
    <div
      style={{
        padding: "32px 48px 18px",
        borderBottom: `1px solid ${brand.line}`,
        display: "flex",
        alignItems: "flex-end",
        justifyContent: "space-between",
      }}
    >
      <div>
        <div
          style={{
            fontFamily: "var(--font-mono)",
            fontSize: 10.5,
            letterSpacing: "0.22em",
            textTransform: "uppercase",
            color: brand.tealDeep,
            marginBottom: 6,
          }}
        >
          {kicker}
        </div>
        <h2
          style={{
            fontFamily: "var(--font-sans)",
            fontSize: 36,
            margin: 0,
            color: brand.navy,
            letterSpacing: "-0.015em",
            fontWeight: 400,
          }}
        >
          {title}
        </h2>
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        <LogoMark size={60} />
        <span
          style={{
            fontFamily: "var(--font-mono)",
            fontSize: 11,
            color: brand.inkMute,
            letterSpacing: "0.1em",
          }}
        >
          {n}
        </span>
      </div>
    </div>
  );
}

// --- Cover ---
function CoverPage({ property }) {
  const k = property.kadaster;
  return (
    <div
      style={{
        background: brand.navy,
        color: "white",
        position: "relative",
        minHeight: 540,
        display: "flex",
        flexDirection: "column",
      }}
    >
      <div
        style={{
          padding: "32px 48px",
          display: "flex",
          justifyContent: "space-between",
          alignItems: "flex-start",
        }}
      >
        <LogoLockup inverted />
        <div style={{ textAlign: "right" }}>
          <div
            style={{
              fontFamily: "var(--font-mono)",
              fontSize: 10.5,
              letterSpacing: "0.22em",
              textTransform: "uppercase",
              color: "rgba(255,255,255,0.55)",
            }}
          >
            Datum
          </div>
          <div
            style={{
              fontFamily: "var(--font-sans)",
              fontSize: 14,
              marginTop: 4,
              color: "rgba(255,255,255,0.95)",
            }}
          >
            {TODAY_NL}
          </div>
        </div>
      </div>

      <div style={{ padding: "0 48px", position: "relative" }}>
        <PropertyImage property={property} height={300} rounded />
        <div
          style={{
            position: "absolute",
            left: 64,
            bottom: 14,
            background: "rgba(15,30,61,0.78)",
            backdropFilter: "blur(6px)",
            border: "1px solid rgba(255,255,255,0.18)",
            padding: "8px 14px",
            borderRadius: 999,
            fontFamily: "var(--font-mono)",
            fontSize: 10.5,
            letterSpacing: "0.16em",
            textTransform: "uppercase",
            color: "rgba(255,255,255,0.85)",
          }}
        >
          {property.address.city} · {k.bouwjaar}
        </div>
      </div>

      <div
        style={{
          padding: "40px 48px 56px",
          display: "grid",
          gridTemplateColumns: "1fr auto",
          gap: 32,
          alignItems: "end",
        }}
      >
        <div>
          <div
            style={{
              fontFamily: "var(--font-mono)",
              fontSize: 11,
              letterSpacing: "0.22em",
              textTransform: "uppercase",
              color: brand.teal,
              marginBottom: 14,
            }}
          >
            Vooronderzoek · concept
          </div>
          <div
            style={{
              fontFamily: "var(--font-sans)",
              fontSize: 64,
              lineHeight: 1.0,
              letterSpacing: "-0.02em",
              fontWeight: 700,
              textWrap: "balance",
            }}
          >
            {property.address.street}
          </div>
          <div
            style={{
              fontFamily: "var(--font-sans)",
              fontSize: 30,
              fontStyle: "italic",
              color: "rgba(255,255,255,0.7)",
              marginTop: 6,
              letterSpacing: "-0.01em",
            }}
          >
            {property.address.postal} · {property.address.city}
          </div>
        </div>
        <div
          style={{
            borderLeft: `1px solid rgba(255,255,255,0.18)`,
            paddingLeft: 24,
            display: "flex",
            flexDirection: "column",
            gap: 14,
            minWidth: 180,
          }}
        >
          <CoverStat label="Bouwjaar" value={k.bouwjaar} />
          <CoverStat label="Oppervlakte" value={k.oppervlakte} />
          <CoverStat label="WOZ-waarde" value={k.woz} />
        </div>
      </div>
    </div>
  );
}

function CoverStat({ label, value }) {
  return (
    <div>
      <div
        style={{
          fontFamily: "var(--font-mono)",
          fontSize: 9.5,
          letterSpacing: "0.18em",
          textTransform: "uppercase",
          color: "rgba(255,255,255,0.5)",
        }}
      >
        {label}
      </div>
      <div
        style={{
          fontFamily: "var(--font-sans)",
          fontSize: 22,
          color: "white",
          marginTop: 2,
          letterSpacing: "-0.01em",
        }}
      >
        {value}
      </div>
    </div>
  );
}

// --- FieldGrid ---
function FieldGrid({ rows }) {
  return (
    <div style={{ display: "grid", gridTemplateColumns: "200px 1fr", rowGap: 0 }}>
      {rows.map((r, i) => (
        <React.Fragment key={r.k}>
          <div
            style={{
              padding: "14px 0",
              borderTop: i === 0 ? "none" : `1px solid ${brand.line}`,
              fontFamily: "var(--font-mono)",
              fontSize: 11,
              letterSpacing: "0.1em",
              textTransform: "uppercase",
              color: brand.inkMute,
            }}
          >
            {r.k}
          </div>
          <div
            style={{
              padding: "14px 0",
              borderTop: i === 0 ? "none" : `1px solid ${brand.line}`,
              fontFamily: "var(--font-sans)",
              fontSize: 15,
              color: brand.ink,
            }}
          >
            {r.v}
          </div>
        </React.Fragment>
      ))}
    </div>
  );
}

function KadasterPage({ property }) {
  const k = property.kadaster;
  return (
    <div>
      <PageHeader kicker="Bron · Kadaster + BAG" title="Kadasterinformatie" n="01" />
      <div style={{ padding: "20px 48px 40px" }}>
        <FieldGrid
          rows={[
            { k: "Eigenaar", v: k.eigenaar },
            { k: "Perceelnummer", v: k.perceel },
            { k: "Perceeloppervlakte", v: k.perceelOppervlakte || k.oppervlakte },
            { k: "Eigendomssituatie", v: k.eigendom },
            { k: "Bouwjaar", v: k.bouwjaar },
            { k: "WOZ-waarde", v: `${k.woz}  ·  peildatum ${k.peildatum}` },
          ]}
        />
      </div>
    </div>
  );
}

function BestemmingPage({ property }) {
  const b = property.bestemming;
  return (
    <div>
      <PageHeader kicker="Bron · Ruimtelijkeplannen.nl" title="Bestemmingsplan" n="02" />
      <div style={{ padding: "20px 48px 40px" }}>
        <FieldGrid
          rows={[
            { k: "Bestemming", v: b.type },
            { k: "Toegestaan gebruik", v: b.gebruik },
            { k: "Maximale bouwhoogte", v: b.bouwhoogte },
            { k: "Status", v: b.monument },
            { k: "Laatst gewijzigd", v: b.laatstGewijzigd },
          ]}
        />
        <div
          style={{
            marginTop: 26,
            background: "#ECFDF5",
            border: `1px solid #34D399`,
            borderRadius: 6,
            padding: "16px 20px",
            display: "flex",
            gap: 14,
          }}
        >
          <div style={{ width: 4, alignSelf: "stretch", background: "#047857", borderRadius: 2 }} />
          <div>
            <div
              style={{
                fontFamily: "var(--font-mono)",
                fontSize: 10.5,
                letterSpacing: "0.18em",
                textTransform: "uppercase",
                color: "#047857",
              }}
            >
              Uitbreidingsmogelijkheid
            </div>
            <div
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: 22,
                color: brand.navy,
                marginTop: 4,
                letterSpacing: "-0.005em",
              }}
            >
              {b.uitbreiding}
            </div>
            <div
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: 13.5,
                color: brand.inkSoft,
                marginTop: 6,
                lineHeight: 1.5,
                maxWidth: 540,
              }}
            >
              Onder voorwaarden kruimelregeling - vergunningvrij of via reguliere
              omgevingsvergunning. Toetsing welstand­commissie.
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function BuurtPage({ property }) {
  const u = property.buurt;
  return (
    <div>
      <PageHeader kicker="Bron · CBS Statline" title="Buurt­demografie" n="03" />
      <div style={{ padding: "20px 48px 40px" }}>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 32 }}>
          <div>
            <div
              style={{
                fontFamily: "var(--font-mono)",
                fontSize: 10.5,
                letterSpacing: "0.18em",
                textTransform: "uppercase",
                color: brand.inkMute,
              }}
            >
              Buurt
            </div>
            <div
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: 30,
                fontWeight: 700,
                color: brand.navy,
                marginTop: 4,
                letterSpacing: "-0.01em",
              }}
            >
              {u.naam}
            </div>
            <div style={{ display: "flex", gap: 24, marginTop: 22 }}>
              <BigStat label="Gem. inkomen" value={u.inkomen} />
              <BigStat label="Bewoners" value={u.bewoners} />
              <BigStat label="Dichtheid" value={u.dichtheid} />
            </div>
          </div>
          <div>
            <BarBlock title="Leeftijdsverdeling" data={u.leeftijd} />
            <div style={{ height: 18 }} />
            <BarBlock title="Huishoudens" data={u.huishouden} />
          </div>
        </div>
      </div>
    </div>
  );
}

function BigStat({ label, value }) {
  return (
    <div>
      <div
        style={{
          fontFamily: "var(--font-mono)",
          fontSize: 10.5,
          letterSpacing: "0.16em",
          textTransform: "uppercase",
          color: brand.inkMute,
        }}
      >
        {label}
      </div>
      <div
        style={{
          fontFamily: "var(--font-sans)",
          fontSize: 26,
          color: brand.navy,
          marginTop: 4,
          letterSpacing: "-0.01em",
        }}
      >
        {value}
      </div>
    </div>
  );
}

function BarBlock({ title, data }) {
  return (
    <div>
      <div
        style={{
          fontFamily: "var(--font-mono)",
          fontSize: 10.5,
          letterSpacing: "0.16em",
          textTransform: "uppercase",
          color: brand.inkMute,
          marginBottom: 10,
        }}
      >
        {title}
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
        {data.map((d) => (
          <div
            key={d.label}
            style={{
              display: "grid",
              gridTemplateColumns: "120px 1fr 36px",
              alignItems: "center",
              gap: 10,
            }}
          >
            <span style={{ fontFamily: "var(--font-sans)", fontSize: 12.5, color: brand.inkSoft }}>
              {d.label}
            </span>
            <div style={{ height: 8, background: brand.panel, borderRadius: 999, overflow: "hidden" }}>
              <div
                style={{
                  width: `${d.v}%`,
                  height: "100%",
                  background: `linear-gradient(90deg, ${brand.navy}, ${brand.teal})`,
                }}
              />
            </div>
            <span
              style={{
                fontFamily: "var(--font-mono)",
                fontSize: 11.5,
                color: brand.ink,
                textAlign: "right",
              }}
            >
              {d.v}%
            </span>
          </div>
        ))}
      </div>
    </div>
  );
}

function FunderingPage({ property }) {
  const f = property.fundering;
  return (
    <div>
      <PageHeader kicker="Bron · KCAF + Fundermaps" title="Funderings­rapport" n="04" />
      <div style={{ padding: "20px 48px 40px" }}>
        <div style={{ display: "grid", gridTemplateColumns: "1.2fr 1fr", gap: 36 }}>
          <FieldGrid
            rows={[
              { k: "Funderingstype", v: f.type },
              { k: "Risiconiveau", v: f.risico },
              { k: "Laatste inspectie", v: f.laatsteInspectie },
              { k: "Grondwaterstand", v: f.grondwater },
              { k: "Advies", v: f.advies },
            ]}
          />
          <div>
            <div
              style={{
                fontFamily: "var(--font-mono)",
                fontSize: 10.5,
                letterSpacing: "0.16em",
                textTransform: "uppercase",
                color: brand.inkMute,
                marginBottom: 10,
              }}
            >
              Risico-indicator
            </div>
            <div
              style={{
                position: "relative",
                height: 14,
                background: `linear-gradient(90deg, #5fbf6a 0%, #f0c14a 50%, #d96b5a 100%)`,
                borderRadius: 999,
              }}
            >
              <div
                style={{
                  position: "absolute",
                  top: -4,
                  left: `calc(${f.risicoScore * 100}% - 11px)`,
                  width: 22,
                  height: 22,
                  borderRadius: 999,
                  background: "white",
                  border: `3px solid ${brand.navy}`,
                  boxShadow: "0 2px 6px rgba(0,0,0,0.15)",
                }}
              />
            </div>
            <div
              style={{
                display: "flex",
                justifyContent: "space-between",
                marginTop: 10,
                fontFamily: "var(--font-mono)",
                fontSize: 10.5,
                letterSpacing: "0.12em",
                textTransform: "uppercase",
                color: brand.inkMute,
              }}
            >
              <span>Laag</span>
              <span>Verhoogd</span>
              <span>Hoog</span>
            </div>
            <div
              style={{
                marginTop: 24,
                padding: 16,
                background: brand.panel,
                borderRadius: 6,
                fontFamily: "var(--font-sans)",
                fontSize: 13,
                color: brand.inkSoft,
                lineHeight: 1.5,
              }}
            >
              Risicobeoordeling op basis van funderingstype, bouwjaar en
              grondwater­fluctuaties in directe omgeving. Advies volgens KCAF-richtlijnen.
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// --- Extra pages ---
function VergelijkbaarPage({ property }) {
  return (
    <div>
      <PageHeader kicker="Aanvullend · NVM transactiedata" title="Vergelijkbare woningen" n="05" />
      <div style={{ padding: "20px 48px 40px" }}>
        <table
          style={{
            width: "100%",
            borderCollapse: "collapse",
            fontFamily: "var(--font-sans)",
            fontSize: 14,
          }}
        >
          <thead>
            <tr>
              {["Adres", "Oppervlakte", "Verkoopprijs", "Verkocht"].map((h) => (
                <th
                  key={h}
                  style={{
                    textAlign: "left",
                    padding: "12px 8px",
                    borderBottom: `1px solid ${brand.line}`,
                    fontFamily: "var(--font-mono)",
                    fontSize: 10.5,
                    letterSpacing: "0.14em",
                    textTransform: "uppercase",
                    color: brand.inkMute,
                    fontWeight: 500,
                  }}
                >
                  {h}
                </th>
              ))}
            </tr>
          </thead>
          <tbody>
            {property.vergelijkbaar.map((v) => (
              <tr key={v.adres}>
                <td style={tdStyle}>
                  <span style={{ fontFamily: "var(--font-sans)", fontSize: 18, color: brand.navy }}>
                    {v.adres}
                  </span>
                </td>
                <td style={tdStyle}>{v.m2} m²</td>
                <td style={{ ...tdStyle, fontFamily: "var(--font-mono)" }}>{v.prijs}</td>
                <td style={{ ...tdStyle, color: brand.inkSoft }}>{v.verkocht}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}
const tdStyle = { padding: "16px 8px", borderBottom: `1px solid ${brand.line}` };

function MarktPage({ property }) {
  const m = property.markt;
  const max = Math.max(...m.serie);
  const min = Math.min(...m.serie);
  const points = m.serie
    .map((v, i) => {
      const x = (i / (m.serie.length - 1)) * 600;
      const y = 140 - ((v - min) / (max - min)) * 110 - 10;
      return `${x.toFixed(1)},${y.toFixed(1)}`;
    })
    .join(" ");
  return (
    <div>
      <PageHeader kicker="Aanvullend · Brainbay marktdata" title="Marktanalyse" n="06" />
      <div style={{ padding: "20px 48px 40px" }}>
        <div style={{ display: "flex", gap: 32, marginBottom: 22 }}>
          <BigStat label="Trend 12 mnd" value={m.trend} />
          <BigStat label="Gem. m²-prijs" value={m.gemiddeld} />
          <BigStat label="Periode" value={m.periode} />
        </div>
        <div style={{ background: brand.panel, borderRadius: 6, padding: "20px 16px 12px" }}>
          <svg viewBox="0 0 600 150" width="100%" height="180" style={{ display: "block" }}>
            <defs>
              <linearGradient id="mktGrad" x1="0" x2="0" y1="0" y2="1">
                <stop offset="0%" stopColor={brand.teal} stopOpacity="0.35" />
                <stop offset="100%" stopColor={brand.teal} stopOpacity="0" />
              </linearGradient>
            </defs>
            <polyline
              points={points}
              fill="none"
              stroke={brand.navy}
              strokeWidth="2"
              strokeLinecap="round"
              strokeLinejoin="round"
            />
            <polygon points={`0,150 ${points} 600,150`} fill="url(#mktGrad)" />
            {m.serie.map((v, i) => {
              const x = (i / (m.serie.length - 1)) * 600;
              const y = 140 - ((v - min) / (max - min)) * 110 - 10;
              return (
                <circle
                  key={i}
                  cx={x}
                  cy={y}
                  r={i === m.serie.length - 1 ? 5 : 0}
                  fill={brand.teal}
                  stroke={brand.navy}
                  strokeWidth="2"
                />
              );
            })}
          </svg>
          <div
            style={{
              display: "flex",
              justifyContent: "space-between",
              fontFamily: "var(--font-mono)",
              fontSize: 10.5,
              color: brand.inkMute,
              padding: "0 4px",
              marginTop: 4,
            }}
          >
            <span>mei '25</span>
            <span>nov '25</span>
            <span>mei '26</span>
          </div>
        </div>
      </div>
    </div>
  );
}

function AankoopPage({ property }) {
  const a = property.aankoop;
  return (
    <div>
      <PageHeader kicker="Aanvullend · advies" title="Aankoop­samenvatting" n="07" />
      <div style={{ padding: "20px 48px 40px", display: "grid", gridTemplateColumns: "1fr 1fr", gap: 32 }}>
        <ColumnList title="Kansen" tone="teal" items={a.kansen} />
        <ColumnList title="Aandachtspunten" tone="navy" items={a.risicos} />
      </div>
    </div>
  );
}

function ColumnList({ title, items, tone }) {
  const accent = tone === "teal" ? brand.tealDeep : brand.navy;
  return (
    <div>
      <div
        style={{
          fontFamily: "var(--font-mono)",
          fontSize: 10.5,
          letterSpacing: "0.18em",
          textTransform: "uppercase",
          color: accent,
          marginBottom: 14,
        }}
      >
        {title}
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
        {items.map((it, i) => (
          <div
            key={i}
            style={{
              display: "grid",
              gridTemplateColumns: "32px 1fr",
              gap: 12,
              alignItems: "start",
            }}
          >
            <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: brand.inkMute, paddingTop: 4 }}>
              {String(i + 1).padStart(2, "0")}
            </div>
            <div
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: 19,
                color: brand.navy,
                lineHeight: 1.35,
                letterSpacing: "-0.005em",
              }}
            >
              {it}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

function HypotheekPage({ property }) {
  const h = property.hypotheek;
  return (
    <div>
      <PageHeader kicker="Aanvullend · indicatief" title="Hypotheek­indicatie" n="08" />
      <div style={{ padding: "20px 48px 40px" }}>
        <div
          style={{
            background: brand.navy,
            color: "white",
            borderRadius: 6,
            padding: "28px 32px",
            display: "grid",
            gridTemplateColumns: "1fr 1fr",
            gap: 24,
          }}
        >
          <div>
            <div
              style={{
                fontFamily: "var(--font-mono)",
                fontSize: 10.5,
                letterSpacing: "0.18em",
                textTransform: "uppercase",
                color: brand.teal,
              }}
            >
              Maandlast indicatie
            </div>
            <div
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: 56,
                fontWeight: 700,
                marginTop: 6,
                letterSpacing: "-0.02em",
              }}
            >
              {h.maandlast}
            </div>
            <div
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: 13,
                color: "rgba(255,255,255,0.65)",
                marginTop: 4,
              }}
            >
              bruto, op basis van WOZ-waarde {h.woz}
            </div>
          </div>
          <div
            style={{
              display: "flex",
              flexDirection: "column",
              gap: 14,
              borderLeft: "1px solid rgba(255,255,255,0.18)",
              paddingLeft: 24,
            }}
          >
            <CoverStat label="Hypotheek indicatie" value={h.indicatie} />
            <CoverStat label="Rente (NHG, 10 jr vast)" value={h.rente} />
            <CoverStat label="Looptijd" value={h.looptijd} />
          </div>
        </div>
        <div
          style={{
            marginTop: 16,
            fontFamily: "var(--font-sans)",
            fontSize: 12,
            color: brand.inkMute,
            lineHeight: 1.5,
          }}
        >
          Indicatieve berekening - geen advies. Werkelijke maandlasten zijn
          afhankelijk van inkomen, eigen middelen, hypotheekvorm en geldverstrekker.
        </div>
      </div>
    </div>
  );
}

function OnderhoudPage({ property }) {
  return (
    <div>
      <PageHeader kicker="Aanvullend · door eigenaar verstrekt" title="Onderhouds­historie" n="09" />
      <div style={{ padding: "20px 48px 40px" }}>
        <div style={{ display: "flex", flexDirection: "column", gap: 0 }}>
          {property.onderhoud.map((o, i) => (
            <div
              key={o.jaar}
              style={{
                display: "grid",
                gridTemplateColumns: "100px 1fr",
                gap: 24,
                padding: "18px 0",
                borderTop: i === 0 ? "none" : `1px solid ${brand.line}`,
                alignItems: "baseline",
              }}
            >
              <div
                style={{
                  fontFamily: "var(--font-sans)",
                  fontSize: 28,
                  fontWeight: 700,
                  color: brand.tealDeep,
                  letterSpacing: "-0.01em",
                }}
              >
                {o.jaar}
              </div>
              <div
                style={{
                  fontFamily: "var(--font-sans)",
                  fontSize: 16,
                  color: brand.ink,
                  lineHeight: 1.45,
                }}
              >
                {o.werk}
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// --- Uploaded document page (rebranded) ---
function UploadedDocPage({ doc }) {
  return (
    <div>
      <PageHeader
        kicker={`Geüpload door makelaar · ${doc.fileType}`}
        title={doc.title}
        n="·"
      />
      <div style={{ padding: "20px 48px 40px" }}>
        <div
          style={{
            background: brand.tealSoft,
            border: `1px dashed ${brand.teal}`,
            borderRadius: 6,
            padding: "12px 16px",
            display: "flex",
            alignItems: "center",
            gap: 12,
            marginBottom: 24,
          }}
        >
          <ReBrandIcon />
          <div>
            <div
              style={{
                fontFamily: "var(--font-mono)",
                fontSize: 10.5,
                letterSpacing: "0.16em",
                textTransform: "uppercase",
                color: brand.tealDeep,
              }}
            >
              Automatisch overgenomen
            </div>
            <div
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: 13.5,
                color: brand.inkSoft,
                marginTop: 2,
              }}
            >
              Bron: <strong style={{ color: brand.navy }}>{doc.fileName}</strong> ·
              tekst geëxtraheerd, opgemaakt in huisstijl en samengevat door AI.
            </div>
          </div>
        </div>

        {/* Mock extracted content rendered in brand style */}
        <div
          style={{
            display: "grid",
            gridTemplateColumns: "1fr 1fr",
            gap: 32,
          }}
        >
          <div>
            <SectionLabel>Samenvatting</SectionLabel>
            <p
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: 20,
                color: brand.navy,
                lineHeight: 1.4,
                margin: "8px 0 0",
                letterSpacing: "-0.005em",
              }}
            >
              {doc.summary}
            </p>
            <div style={{ height: 18 }} />
            <SectionLabel>Belangrijkste bevindingen</SectionLabel>
            <ul
              style={{
                margin: "10px 0 0",
                padding: 0,
                listStyle: "none",
                display: "flex",
                flexDirection: "column",
                gap: 10,
              }}
            >
              {doc.bullets.map((b, i) => (
                <li
                  key={i}
                  style={{
                    fontFamily: "var(--font-sans)",
                    fontSize: 14,
                    color: brand.ink,
                    lineHeight: 1.5,
                    paddingLeft: 18,
                    position: "relative",
                  }}
                >
                  <span
                    style={{
                      position: "absolute",
                      left: 0,
                      top: 8,
                      width: 8,
                      height: 2,
                      background: brand.tealDeep,
                    }}
                  />
                  {b}
                </li>
              ))}
            </ul>
          </div>
          <div>
            <SectionLabel>Metagegevens</SectionLabel>
            <div style={{ marginTop: 10 }}>
              <FieldGrid
                rows={[
                  { k: "Documenttype", v: doc.fileType },
                  { k: "Bestandsnaam", v: doc.fileName },
                  { k: "Datum document", v: doc.date },
                  { k: "Pagina's", v: doc.pages },
                ]}
              />
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function SectionLabel({ children }) {
  return (
    <div
      style={{
        fontFamily: "var(--font-mono)",
        fontSize: 10.5,
        letterSpacing: "0.18em",
        textTransform: "uppercase",
        color: brand.tealDeep,
      }}
    >
      {children}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Stage 3 - Uitbreiden: file upload + auto-rebrand
// ---------------------------------------------------------------------------
const TEMPLATE_EXTRAS = [
  { id: "vergelijkbaar", title: "Vergelijkbare woningen", desc: "Recent verkochte panden in de omgeving." },
  { id: "markt", title: "Marktanalyse", desc: "Prijstrend van de buurt over 12 maanden." },
  { id: "aankoop", title: "Aankoopsamenvatting", desc: "Kansen en aandachtspunten voor de koper." },
  { id: "hypotheek", title: "Hypotheekindicatie", desc: "Indicatieve maandlast op basis van WOZ." },
];

// Mock content the "AI" will produce when a file is uploaded.
// Picks a doc type heuristically based on filename, otherwise defaults.
function mockRebrandFromFile(name) {
  const lower = name.toLowerCase();
  if (lower.includes("taxa")) {
    return {
      title: "Taxatierapport - samengevat",
      fileType: "Taxatierapport (PDF)",
      summary:
        "Onafhankelijke taxatie bevestigt marktwaarde binnen verwachte bandbreedte; geen bijzonderheden m.b.t. waardedrukkende factoren.",
      bullets: [
        "Marktwaarde vrij van huur en gebruik: in lijn met vraagprijs",
        "Geen waardedrukkende factoren in directe omgeving",
        "Onderhoudstoestand binnen en buiten beoordeeld als 'goed'",
      ],
      date: "12 maart 2026",
      pages: "24",
    };
  }
  if (lower.includes("energie") || lower.includes("epc") || lower.includes("label")) {
    return {
      title: "Energielabel & verduurzamings­advies",
      fileType: "Energielabel (PDF)",
      summary:
        "Definitief energielabel met aanbevolen verduurzamings­maatregelen en indicatieve terugverdientijd.",
      bullets: [
        "Huidig label: C - registratie geldig tot 2034",
        "Aanbevolen: HR++ glas, dakisolatie, warmtepomp",
        "Indicatieve labelsprong na maatregelen: C → A",
      ],
      date: "8 januari 2026",
      pages: "6",
    };
  }
  if (lower.includes("vve") || lower.includes("splits")) {
    return {
      title: "VvE-stukken - samengevat",
      fileType: "VvE-dossier (ZIP)",
      summary:
        "Actieve VvE met gezonde reserves; recent MJOP en geen lopende geschillen of bijzondere besluiten.",
      bullets: [
        "Maandelijkse bijdrage: € 245 - incl. reservefonds",
        "Reservefonds: € 84.000 (ruim toereikend o.b.v. MJOP)",
        "Laatste ALV: 14 nov 2025 - geen bijzondere besluiten",
      ],
      date: "14 november 2025",
      pages: "32",
    };
  }
  if (lower.includes("bouw") || lower.includes("inspect") || lower.includes("keuring")) {
    return {
      title: "Bouwkundige keuring",
      fileType: "Bouwkundig rapport (PDF)",
      summary:
        "Algemene staat 'voldoende tot goed'. Enkele aandachtspunten op korte en middellange termijn.",
      bullets: [
        "Direct: kitwerk badkamer vernieuwen - € 350",
        "Middellange termijn: voegwerk gevel - € 4.200",
        "Geen acute constructieve gebreken vastgesteld",
      ],
      date: "27 februari 2026",
      pages: "18",
    };
  }
  return {
    title: "Aanvullend document - samengevat",
    fileType: "Document (PDF)",
    summary:
      "Document automatisch verwerkt: tekst geëxtraheerd, samengevat en opgemaakt in de huisstijl van het kantoor.",
    bullets: [
      "Volledige tekst doorzocht en gestructureerd",
      "Belangrijkste cijfers en data overgenomen",
      "Tabellen en lijsten herschreven in branded stijl",
    ],
    date: "6 mei 2026",
    pages: "12",
  };
}

function UitbreidenPanel({ extras, setExtras, property }) {
  const [selected, setSelected] = useState([]);
  const [adding, setAdding] = useState(false);
  const [dragOver, setDragOver] = useState(false);
  const [processing, setProcessing] = useState(null); // {fileName, step}
  const fileInputRef = useRef(null);

  const addedTemplateIds = extras.filter((e) => e.kind !== "upload").map((e) => e.kind);
  // Filenames already added via upload/example, so we can't add the same one twice.
  const addedUploadNames = extras.filter((e) => e.kind === "upload").map((e) => e.fileName);

  function toggleTemplate(id) {
    if (addedTemplateIds.includes(id)) return;
    setSelected((s) => (s.includes(id) ? s.filter((x) => x !== id) : [...s, id]));
  }

  function commitTemplates() {
    if (selected.length === 0) return;
    setAdding(true);
    setTimeout(() => {
      setExtras((e) => [
        ...e,
        ...selected.map((id) => ({ id: `${id}-${Date.now()}`, kind: id })),
      ]);
      setSelected([]);
      setAdding(false);
    }, 500);
  }

  function handleFiles(fileList) {
    if (!fileList || fileList.length === 0) return;
    const file = fileList[0];
    const fileName = file.name || "Document.pdf";
    const isPdf =
      file.type === "application/pdf" || /\.pdf$/i.test(fileName);
    runUploadFlow(fileName, isPdf ? file : null);
  }

  // Render each page of an uploaded PDF to a high-res data URL using pdf.js.
  // Returns an array of { dataUrl, w, h } for direct embedding as page images.
  async function renderPdfPagesAsImages(file) {
    const pdfjsLib = window.pdfjsLib;
    if (!pdfjsLib) return [];
    const buf = await file.arrayBuffer();
    const pdf = await pdfjsLib.getDocument({ data: buf }).promise;
    const pages = [];
    for (let i = 1; i <= pdf.numPages; i++) {
      const page = await pdf.getPage(i);
      const viewport = page.getViewport({ scale: 2 });
      const canvas = document.createElement("canvas");
      canvas.width = viewport.width;
      canvas.height = viewport.height;
      const ctx = canvas.getContext("2d");
      await page.render({ canvasContext: ctx, viewport }).promise;
      pages.push({
        dataUrl: canvas.toDataURL("image/jpeg", 0.9),
        w: viewport.width,
        h: viewport.height,
      });
    }
    return pages;
  }

  // Simulate the upload → extract → rebrand flow with realistic stages.
  // For real PDFs we additionally rasterize each page via pdf.js so the
  // original pages can be appended verbatim to the booklet.
  function runUploadFlow(fileName, pdfFile) {
    const mock = mockRebrandFromFile(fileName);
    setProcessing({ fileName, step: "Bestand uploaden…", pct: 5 });
    const steps = [
      { ms: 350, step: "Bestand uploaden…", pct: 22 },
      { ms: 700, step: "Pagina's renderen…", pct: 48 },
      { ms: 1100, step: "Tekst & tabellen extraheren…", pct: 72 },
      { ms: 1500, step: "Opmaken in huisstijl…", pct: 92 },
    ];
    steps.forEach((s) => {
      setTimeout(() => setProcessing({ fileName, step: s.step, pct: s.pct }), s.ms);
    });

    const renderPromise = pdfFile
      ? renderPdfPagesAsImages(pdfFile).catch(() => [])
      : Promise.resolve([]);

    Promise.all([
      renderPromise,
      new Promise((r) => setTimeout(r, 1900)),
    ]).then(([pdfPages]) => {
      setExtras((e) => [
        ...e,
        {
          id: `upload-${Date.now()}`,
          kind: "upload",
          fileName,
          pdfPages,
          ...mock,
        },
      ]);
      setProcessing(null);
    });
  }

  return (
    <div
      style={{
        background: "#fff",
        border: `1px solid ${brand.panelEdge}`,
        borderRadius: 14,
        padding: 22,
        display: "flex",
        flexDirection: "column",
        gap: 18,
      }}
    >
      <div>
        <div
          style={{
            fontFamily: "var(--font-mono)",
            fontSize: 10.5,
            letterSpacing: "0.22em",
            textTransform: "uppercase",
            color: brand.tealDeep,
          }}
        >
          Stap 3 · uitbreiden
        </div>
        <div
          style={{
            fontFamily: "var(--font-sans)",
            fontSize: 26,
            color: brand.navy,
            marginTop: 4,
            letterSpacing: "-0.01em",
          }}
        >
          Document toevoegen
        </div>
        <p
          style={{
            fontFamily: "var(--font-sans)",
            fontSize: 13,
            color: brand.inkSoft,
            marginTop: 8,
            lineHeight: 1.5,
          }}
        >
          Upload een document - bouwkundige keuring, taxatierapport, VvE-stukken,
          energielabel - en wij nemen het op in het boekje, automatisch
          opgemaakt in uw huisstijl.
        </p>
      </div>

      {/* How it works mini-flow */}
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "1fr 14px 1fr 14px 1fr",
          alignItems: "center",
          gap: 6,
          padding: "12px",
          background: brand.panel,
          borderRadius: 8,
        }}
      >
        <FlowStep n="1" label="Upload PDF" />
        <FlowArrow />
        <FlowStep n="2" label="AI vat samen" />
        <FlowArrow />
        <FlowStep n="3" label="In huisstijl" />
      </div>

      {/* Drop zone */}
      <div
        onDragOver={(e) => {
          e.preventDefault();
          setDragOver(true);
        }}
        onDragLeave={() => setDragOver(false)}
        onDrop={(e) => {
          e.preventDefault();
          setDragOver(false);
          handleFiles(e.dataTransfer.files);
        }}
        onClick={() => !processing && fileInputRef.current?.click()}
        style={{
          border: `1.5px dashed ${dragOver ? brand.tealDeep : brand.panelEdge}`,
          background: dragOver ? brand.tealSoft : brand.paper,
          borderRadius: 10,
          padding: "20px 16px",
          textAlign: "center",
          cursor: processing ? "default" : "pointer",
          transition: "all .15s",
        }}
      >
        <input
          ref={fileInputRef}
          type="file"
          accept=".pdf,.docx,.doc,.zip"
          style={{ display: "none" }}
          onChange={(e) => handleFiles(e.target.files)}
        />
        {processing ? (
          <ProcessingState p={processing} />
        ) : (
          <>
            <UploadIcon />
            <div
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: 14,
                fontWeight: 600,
                color: brand.navy,
                marginTop: 10,
              }}
            >
              Sleep een document hierheen
            </div>
            <div
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: 12.5,
                color: brand.inkSoft,
                marginTop: 4,
              }}
            >
              of <span style={{ color: brand.tealDeep, fontWeight: 600 }}>klik om te bladeren</span>
            </div>
            <div
              style={{
                fontFamily: "var(--font-mono)",
                fontSize: 10,
                letterSpacing: "0.14em",
                textTransform: "uppercase",
                color: brand.inkMute,
                marginTop: 10,
              }}
            >
              PDF · DOCX · ZIP - max. 25 MB
            </div>
          </>
        )}
      </div>

      {/* Try-with examples */}
      {!processing && (
        <div>
          <div
            style={{
              fontFamily: "var(--font-mono)",
              fontSize: 10.5,
              letterSpacing: "0.18em",
              textTransform: "uppercase",
              color: brand.inkMute,
              marginBottom: 8,
            }}
          >
            Of probeer een voorbeeld
          </div>
          <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
            {[
              "taxatierapport.pdf",
              "energielabel.pdf",
              "bouwkundige-keuring.pdf",
              "vve-dossier.zip",
            ].map((f) => {
              const added = addedUploadNames.includes(f);
              return (
                <button
                  key={f}
                  onClick={() => !added && runUploadFlow(f)}
                  disabled={added}
                  title={added ? "Al toegevoegd" : undefined}
                  style={{
                    border: `1px solid ${added ? brand.teal : brand.panelEdge}`,
                    background: added ? brand.tealSoft : "#fff",
                    borderRadius: 999,
                    padding: "5px 11px",
                    fontFamily: "var(--font-mono)",
                    fontSize: 11,
                    color: added ? brand.tealDeep : brand.inkSoft,
                    cursor: added ? "default" : "pointer",
                    opacity: added ? 0.7 : 1,
                    display: "inline-flex",
                    alignItems: "center",
                    gap: 5,
                  }}
                  onMouseOver={(e) => {
                    if (added) return;
                    e.currentTarget.style.borderColor = brand.teal;
                    e.currentTarget.style.color = brand.tealDeep;
                  }}
                  onMouseOut={(e) => {
                    if (added) return;
                    e.currentTarget.style.borderColor = brand.panelEdge;
                    e.currentTarget.style.color = brand.inkSoft;
                  }}
                >
                  {added ? <span style={{ fontWeight: 700 }}>✓</span> : <FileIcon />} {f}
                </button>
              );
            })}
          </div>
        </div>
      )}

      {/* Divider */}
      <div
        style={{
          display: "flex",
          alignItems: "center",
          gap: 10,
          fontFamily: "var(--font-mono)",
          fontSize: 10,
          letterSpacing: "0.2em",
          textTransform: "uppercase",
          color: brand.inkMute,
        }}
      >
        <div style={{ flex: 1, height: 1, background: brand.panelEdge }} />
        Of kies een standaardsectie
        <div style={{ flex: 1, height: 1, background: brand.panelEdge }} />
      </div>

      {/* Template extras */}
      <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
        {TEMPLATE_EXTRAS.map((x) => {
          const added = addedTemplateIds.includes(x.id);
          const isSel = selected.includes(x.id);
          return (
            <button
              key={x.id}
              onClick={() => toggleTemplate(x.id)}
              disabled={added}
              style={{
                textAlign: "left",
                background: added ? brand.tealSoft : isSel ? "#eef7ff" : "#fff",
                border: `1px solid ${added ? brand.teal : isSel ? brand.navy : brand.panelEdge}`,
                borderRadius: 10,
                padding: "10px 12px",
                cursor: added ? "default" : "pointer",
                display: "grid",
                gridTemplateColumns: "20px 1fr",
                gap: 12,
                alignItems: "start",
                transition: "all .15s",
                fontFamily: "inherit",
              }}
            >
              <Checkbox checked={added || isSel} added={added} />
              <div>
                <div
                  style={{
                    fontFamily: "var(--font-sans)",
                    fontSize: 13.5,
                    fontWeight: 600,
                    color: added ? brand.tealDeep : brand.navy,
                  }}
                >
                  {x.title}
                  {added && (
                    <span
                      style={{
                        marginLeft: 8,
                        fontFamily: "var(--font-mono)",
                        fontSize: 9.5,
                        letterSpacing: "0.16em",
                        textTransform: "uppercase",
                        color: brand.tealDeep,
                        fontWeight: 500,
                      }}
                    >
                      · toegevoegd
                    </span>
                  )}
                </div>
                <div
                  style={{
                    fontFamily: "var(--font-sans)",
                    fontSize: 12,
                    color: brand.inkSoft,
                    marginTop: 2,
                    lineHeight: 1.4,
                  }}
                >
                  {x.desc}
                </div>
              </div>
            </button>
          );
        })}
      </div>

      <button
        onClick={commitTemplates}
        disabled={selected.length === 0 || adding}
        style={{
          width: "100%",
          background: selected.length === 0 ? brand.panel : brand.navy,
          color: selected.length === 0 ? brand.inkMute : "white",
          border: "none",
          borderRadius: 10,
          padding: "12px 16px",
          fontFamily: "var(--font-sans)",
          fontSize: 14,
          fontWeight: 600,
          cursor: selected.length === 0 ? "not-allowed" : "pointer",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          gap: 8,
        }}
      >
        {adding ? (
          <>
            <Spinner small /> Toevoegen…
          </>
        ) : (
          <>
            Toevoegen aan boekje
            {selected.length > 0 && (
              <span
                style={{
                  background: brand.teal,
                  color: brand.navy,
                  borderRadius: 999,
                  padding: "2px 8px",
                  fontFamily: "var(--font-mono)",
                  fontSize: 11,
                  fontWeight: 600,
                }}
              >
                {selected.length}
              </span>
            )}
          </>
        )}
      </button>
    </div>
  );
}

function FlowStep({ n, label }) {
  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        gap: 4,
      }}
    >
      <div
        style={{
          width: 22,
          height: 22,
          borderRadius: 999,
          background: brand.navy,
          color: "white",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          fontFamily: "var(--font-mono)",
          fontSize: 10.5,
          fontWeight: 600,
        }}
      >
        {n}
      </div>
      <div
        style={{
          fontFamily: "var(--font-sans)",
          fontSize: 11.5,
          color: brand.ink,
          fontWeight: 500,
          textAlign: "center",
        }}
      >
        {label}
      </div>
    </div>
  );
}
function FlowArrow() {
  return (
    <svg width="14" height="10" viewBox="0 0 14 10" fill="none">
      <path d="M1 5 H12 M9 2 L12 5 L9 8" stroke={brand.inkMute} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function ProcessingState({ p }) {
  return (
    <div style={{ padding: "4px 4px 0" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 10, justifyContent: "center" }}>
        <Spinner />
        <div style={{ fontFamily: "var(--font-sans)", fontSize: 14, fontWeight: 600, color: brand.navy }}>
          {p.fileName}
        </div>
      </div>
      <div
        style={{
          marginTop: 12,
          height: 4,
          background: brand.panel,
          borderRadius: 999,
          overflow: "hidden",
        }}
      >
        <div
          style={{
            width: `${p.pct}%`,
            height: "100%",
            background: `linear-gradient(90deg, ${brand.navy}, ${brand.teal})`,
            transition: "width .3s ease-out",
          }}
        />
      </div>
      <div
        style={{
          marginTop: 8,
          fontFamily: "var(--font-mono)",
          fontSize: 11,
          color: brand.inkSoft,
          letterSpacing: "0.05em",
        }}
      >
        {p.step}
      </div>
    </div>
  );
}

function Checkbox({ checked, added }) {
  return (
    <div
      style={{
        width: 18,
        height: 18,
        borderRadius: 5,
        border: `1.5px solid ${checked ? (added ? brand.tealDeep : brand.navy) : brand.panelEdge}`,
        background: checked ? (added ? brand.tealDeep : brand.navy) : "white",
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        marginTop: 2,
        transition: "all .15s",
      }}
    >
      {checked && (
        <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
          <path d="M2 5.2 L4.2 7.4 L8 3" stroke="white" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
        </svg>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Icons
// ---------------------------------------------------------------------------
function SearchIcon() {
  return (
    <svg width="18" height="18" viewBox="0 0 18 18" fill="none">
      <circle cx="8" cy="8" r="5.5" stroke="currentColor" strokeWidth="1.5" />
      <path d="M12 12 L16 16" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
    </svg>
  );
}
function ArrowRight() {
  return (
    <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
      <path d="M2 7 H12 M8 3 L12 7 L8 11" stroke="white" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}
function UploadIcon() {
  return (
    <svg width="32" height="32" viewBox="0 0 32 32" fill="none">
      <rect x="6" y="20" width="20" height="6" rx="1.5" stroke={brand.navy} strokeWidth="1.5" />
      <path d="M16 18 V5 M11 10 L16 5 L21 10" stroke={brand.navy} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}
function FileIcon() {
  return (
    <svg width="11" height="13" viewBox="0 0 11 13" fill="none">
      <path
        d="M1 1 H7 L10 4 V12 H1 Z"
        stroke="currentColor"
        strokeWidth="1.1"
        fill="none"
        strokeLinejoin="round"
      />
      <path d="M7 1 V4 H10" stroke="currentColor" strokeWidth="1.1" fill="none" strokeLinejoin="round" />
    </svg>
  );
}
function ReBrandIcon() {
  return (
    <svg width="34" height="34" viewBox="0 0 34 34" fill="none">
      <rect x="3" y="5" width="14" height="20" rx="1.5" stroke={brand.tealDeep} strokeWidth="1.4" fill="white" />
      <path d="M11 30 L21 30 M16 26 V30" stroke={brand.tealDeep} strokeWidth="1.4" strokeLinecap="round" />
      <path d="M19 11 L25 11 L28 14 L28 26 L17 26" stroke={brand.tealDeep} strokeWidth="1.4" fill={brand.tealSoft} strokeLinejoin="round" />
      <path d="M25 11 V14 H28" stroke={brand.tealDeep} strokeWidth="1.4" strokeLinejoin="round" />
      <path d="M14 16 L17 19" stroke={brand.tealDeep} strokeWidth="1.4" strokeLinecap="round" />
      <path d="M14 19 L17 16 M16 17 L17 16 L17 18" stroke={brand.navy} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}
function Spinner({ small }) {
  const s = small ? 14 : 24;
  return (
    <div
      style={{
        width: s,
        height: s,
        borderRadius: "50%",
        border: `${small ? 2 : 3}px solid ${small ? "rgba(255,255,255,0.3)" : brand.panel}`,
        borderTopColor: small ? "white" : brand.teal,
        animation: "spin 0.9s linear infinite",
      }}
    />
  );
}

// ===========================================================================
// PDF render tree - brochure-style A4 pages used as the source for export.
// Rendered hidden, off-screen, alongside the on-screen booklet.
// Layout: 1 full-bleed cover page, then content pages with 2 blocks each.
// ===========================================================================
const pdfBrand = {
  navy: "#111111",
  navyDeep: "#000000",
  gold: "#FFCC00",
  goldDeep: "#E6B800",
  cream: "#FFFFFF",
  paper: "#FFFFFF",
  ink: "#1A1A1A",
  inkSoft: "#4A4A4A",
  inkMute: "#6B6B6B",
  rule: "#E5E5E5",
  panel: "#F4F4F4",
};

const SECTION_META = {
  kadaster:        { kicker: "Eigendom",     title: "Kadaster" },
  kadastralekaart: { kicker: "Perceel",      title: "Kadastrale kaart" },
  bag:             { kicker: "BAG",          title: "Adres & gebouw" },
  bestemming:      { kicker: "Planologie",   title: "Bestemming" },
  buurt:           { kicker: "Locatie",      title: "Buurtprofiel" },
  fundering:       { kicker: "Constructie",  title: "Funderingsrisico" },
  wozhistorie:     { kicker: "Waarde",       title: "WOZ-historie" },
  energielabel:    { kicker: "Energie",      title: "Energielabel" },
  vergelijkbaar:   { kicker: "Markt",        title: "Vergelijkbare woningen" },
  markt:           { kicker: "Markt",        title: "Marktontwikkeling" },
  aankoop:         { kicker: "Advies",       title: "Aankoopoverwegingen" },
  hypotheek:       { kicker: "Financiering", title: "Hypotheekindicatie" },
  onderhoud:       { kicker: "Geschiedenis", title: "Onderhoudshistorie" },
  upload:          { kicker: "Bijlage",      title: "Document" },
};

const LARGE_BLOCK_TYPES = new Set([
  "vergelijkbaar",
  "onderhoud",
  "aankoop",
  "markt",
  "kadastralekaart",
  "energielabel",
  "buurt",
  "fundering",
]);

// Bron-attributie per sectie - getoond in de footer van elk blok, zoals de
// echte Domicilie/NVM-boekjes "Bron: Kadaster / FunderMaps / CBS" tonen.
const SECTION_SOURCE = {
  kadaster:        "Kadaster · Eigendomsinformatie (BRK)",
  bestemming:      "DSO Omgevingsloket · Geldend omgevingsplan",
  buurt:           "CBS Kerncijfers Buurten en Wijken",
  fundering:       "FunderMaps / KCAF · Funderingsrisico-indicator",
  kadastralekaart: "PDOK · Kadastrale Kaart (WMS)",
  bag:             "Kadaster BAG · PDOK Luchtfoto",
  wozhistorie:     "WOZ-waardeloket",
  energielabel:    "EP-Online (RVO) · Definitief energielabel",
  vergelijkbaar:   "Kadaster KOOG · NVM Brainbay (vertrouwelijk)",
  markt:           "CBS · Calcasa Marktindex",
  aankoop:         "Samengesteld door {company}",
  hypotheek:       "Indicatie - {company} · Financieringsadvies",
  onderhoud:       "Aangeleverd door eigenaar",
  upload:          "Door gebruiker geüpload",
};

// Generates a 12-year WOZ-historie regressing the current WOZ-waarde by ~6%
// per year, with a small per-year jitter so the line isn't perfectly smooth.
function deriveWozHistorie(currentWoz) {
  const num = typeof currentWoz === "number"
    ? currentWoz
    : Number(String(currentWoz).replace(/[^\d]/g, "")) || 0;
  if (!num) return [];
  const out = [];
  let v = num;
  const thisYear = new Date().getFullYear();
  // jitters chosen deterministically per year offset
  const jitters = [0, -0.01, 0.012, -0.008, 0.005, -0.015, 0.018, -0.004, 0.009, -0.012, 0.006, 0.0];
  for (let i = 0; i < 12; i++) {
    out.push({ jaar: thisYear - i, waarde: Math.round(v / 1000) * 1000 });
    const drop = 0.058 + (jitters[i] || 0);
    v = v / (1 + drop);
  }
  return out.reverse(); // chronological
}

// Picks a label deterministically from bouwjaar - older buildings get worse
// labels, newer buildings better. Matches what RVO/EP-Online would typically
// show for a property of that vintage.
function deriveEnergielabel(bouwjaar) {
  const yr = parseInt(String(bouwjaar).match(/\d{4}/)?.[0] || "1980", 10);
  let label;
  if (yr >= 2015) label = "A+++";
  else if (yr >= 2000) label = "A";
  else if (yr >= 1985) label = "B";
  else if (yr >= 1965) label = "C";
  else if (yr >= 1945) label = "D";
  else if (yr >= 1920) label = "E";
  else label = "F";
  return {
    label,
    geldig: "10 jaar (definitief)",
    afgegeven: yr < 1950 ? "12 september 2022" : "4 maart 2024",
    registratie: `EP-${10000000 + (yr * 731) % 9000000}`,
    methode: "NTA 8800 - opname op locatie",
  };
}

function deriveBag(property) {
  const k = property.kadaster || {};
  return {
    bagId: `0363010000${String((k.bouwjaar || "1900").slice(-4) * 731 + 1234567).slice(-7)}`,
    status: "Verblijfsobject in gebruik",
    gebruiksdoel: "Woonfunctie",
    oppervlakte: k.oppervlakte || "—",
    bouwjaar: k.bouwjaar || "—",
    gemeente: property.address?.city || "—",
  };
}

// Zwarte contactstrook met gele scheidings-vierkantjes - replica van de
// onderste strook op de officiële Domicilie-voorpagina.
function DomicilieContactStrip() {
  const Pip = () => (
    <span
      style={{
        display: "inline-block",
        width: "2.2mm",
        height: "2.2mm",
        background: pdfBrand.gold,
        margin: "0 2mm",
        verticalAlign: "middle",
      }}
    />
  );
  const offices = activeCompany.offices || [];
  if (offices.length === 0) return null;
  return (
    <div
      style={{
        background: "#000",
        color: "#fff",
        padding: "3.5mm 8mm",
        display: "flex",
        alignItems: "center",
        gap: "5mm",
        fontFamily: "var(--font-sans)",
        fontSize: "8.5pt",
        letterSpacing: "0.01em",
      }}
    >
      {/* Company logo in a white chip so it stays visible on the black strip
          regardless of the logo's own colour. */}
      {activeCompany.logo && (
        <div
          style={{
            background: "#fff",
            borderRadius: "1mm",
            padding: "1mm",
            display: "flex",
            alignItems: "center",
            flexShrink: 0,
          }}
        >
          <img
            src={activeCompany.logo}
            alt={activeCompany.name}
            crossOrigin="anonymous"
            style={{
              maxHeight: "6mm",
              maxWidth: "34mm",
              width: "auto",
              height: "auto",
              display: "block",
              objectFit: "contain",
            }}
          />
        </div>
      )}
      {/* NVM-logo alleen tonen voor aangesloten makelaars (per klant gezet). */}
      {activeCompany.nvm && (
        <img
          src="assets/NVM.png"
          alt="NVM"
          crossOrigin="anonymous"
          style={{ height: "11mm", width: "auto", display: "block", flexShrink: 0 }}
        />
      )}
      {/* Company name once in its own column; each office's details sit in a
          second column and wrap within it (so a wrapped line indents past the
          name rather than stacking under it). */}
      <div style={{ display: "flex", gap: "6mm", alignItems: "flex-start", flex: 1 }}>
        <span style={{ fontWeight: 600, flexShrink: 0, whiteSpace: "nowrap" }}>
          {activeCompany.name}
        </span>
        <div style={{ display: "flex", flexDirection: "column", gap: "1.2mm", flex: 1 }}>
          {offices.map((o, oi) => {
            const fields = [o.adres, o.postcode, o.tel, o.email].filter(Boolean);
            return (
              <div key={oi} style={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
                {fields.map((f, fi) => (
                  <React.Fragment key={fi}>
                    {fi > 0 && <Pip />}
                    <span>{f}</span>
                  </React.Fragment>
                ))}
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

function DomicilieLogo({ height, maxWidth = "62mm" }) {
  // Treat `height` as a max: bound width too so wide logos shrink to fit the
  // header rather than overflowing the page.
  return (
    <img
      src={activeCompany.logo}
      alt={activeCompany.name}
      crossOrigin="anonymous"
      style={{
        maxHeight: height,
        maxWidth,
        width: "auto",
        height: "auto",
        display: "block",
        objectFit: "contain",
      }}
    />
  );
}

function packBlocks(sections) {
  // Greedy packer: large blocks take half a page (2 per page),
  // small blocks pack 3 per page. Mixing on a page is allowed only
  // when filling leftover capacity.
  const pages = [];
  let current = [];
  let capacityUsed = 0; // 1.0 = full page

  const flush = () => {
    if (current.length) {
      pages.push(current);
      current = [];
      capacityUsed = 0;
    }
  };

  for (const s of sections) {
    const weight = LARGE_BLOCK_TYPES.has(s.type) ? 0.5 : 1 / 3;
    if (capacityUsed + weight > 1.0001) flush();
    current.push(s);
    capacityUsed += weight;
    if (capacityUsed > 0.999) flush();
  }
  flush();
  return pages;
}

function PdfBooklet({ property, extras }) {
  // Built-in data sections + uploads that we summarize as a block.
  const blockSections = [
    { type: "kadaster" },
    { type: "kadastralekaart" },
    { type: "bag" },
    { type: "bestemming" },
    { type: "wozhistorie" },
    { type: "energielabel" },
    { type: "buurt" },
    { type: "fundering" },
  ];
  // Uploads without rendered pdfPages → summary block (huisstijl-rebrand).
  // Uploads WITH pdfPages → each page becomes its own A4 page at the end.
  const fullPages = []; // [{ ex, pageIndex, dataUrl }]
  for (const e of extras) {
    if (e.kind === "upload" && Array.isArray(e.pdfPages) && e.pdfPages.length > 0) {
      e.pdfPages.forEach((p, idx) =>
        fullPages.push({ ex: e, pageIndex: idx, dataUrl: p.dataUrl })
      );
    } else {
      blockSections.push({ type: e.kind, ex: e });
    }
  }
  const grouped = packBlocks(blockSections);
  const totalPages = 1 + grouped.length + fullPages.length;
  const inhoudSections = [
    ...blockSections,
    ...fullPages.map((f) => ({ type: "upload", ex: f.ex })),
  ];
  return (
    <>
      <PdfCover property={property} totalPages={totalPages} sections={inhoudSections} />
      {grouped.map((blocks, i) => (
        <PdfContentPage
          key={`c-${i}`}
          property={property}
          blocks={blocks}
          pageNum={i + 2}
          totalPages={totalPages}
        />
      ))}
      {fullPages.map((f, i) => (
        <PdfFullPageUpload
          key={`u-${i}`}
          property={property}
          extra={f.ex}
          dataUrl={f.dataUrl}
          pageIndex={f.pageIndex}
          totalUploadPages={f.ex.pdfPages.length}
          pageNum={1 + grouped.length + i + 1}
          totalPages={totalPages}
        />
      ))}
    </>
  );
}

function PdfFullPageUpload({
  property,
  extra,
  dataUrl,
  pageIndex,
  totalUploadPages,
  pageNum,
  totalPages,
}) {
  return (
    <div
      className="pdf-a4-page"
      style={{
        width: "210mm",
        height: "297mm",
        background: pdfBrand.cream,
        color: pdfBrand.ink,
        fontFamily: "var(--font-sans)",
        display: "flex",
        flexDirection: "column",
        padding: "12mm 16mm 10mm",
        boxSizing: "border-box",
        overflow: "hidden",
        borderTop: `2mm solid ${pdfBrand.gold}`,
      }}
    >
      <div
        style={{
          display: "flex",
          justifyContent: "space-between",
          alignItems: "center",
          borderBottom: `1pt solid ${pdfBrand.navy}`,
          paddingBottom: "4mm",
          marginBottom: "5mm",
          gap: "6mm",
        }}
      >
        <DomicilieLogo height="10mm" />
        <div style={{ flex: 1, textAlign: "right" }}>
          <div
            style={{
              fontFamily: "var(--font-mono)",
              fontSize: "7.5pt",
              letterSpacing: "0.16em",
              textTransform: "uppercase",
              color: pdfBrand.gold,
            }}
          >
            Bijlage - {extra.fileType || "Document"}
          </div>
          <div
            style={{
              fontFamily: "var(--font-sans)",
              fontSize: "12pt",
              fontWeight: 600,
              color: pdfBrand.navy,
              lineHeight: 1.1,
              marginTop: "1mm",
            }}
          >
            {extra.title || extra.fileName || "Document"}
          </div>
        </div>
      </div>

      <div
        style={{
          flex: 1,
          minHeight: 0,
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
          background: "#fff",
          border: `1pt solid ${pdfBrand.rule}`,
          borderRadius: "2pt",
          overflow: "hidden",
        }}
      >
        <img
          src={dataUrl}
          alt={`${extra.fileName} - pagina ${pageIndex + 1}`}
          style={{
            maxWidth: "100%",
            maxHeight: "100%",
            objectFit: "contain",
            display: "block",
          }}
        />
      </div>

      <div
        style={{
          marginTop: "4mm",
          paddingTop: "3mm",
          borderTop: `1pt solid ${pdfBrand.rule}`,
          display: "flex",
          justifyContent: "space-between",
          fontSize: "7.5pt",
          color: pdfBrand.inkMute,
          letterSpacing: "0.04em",
        }}
      >
        <span>
          Bron · {extra.fileName} - pagina {pageIndex + 1} / {totalUploadPages}
        </span>
        <span>{pageNum} / {totalPages}</span>
      </div>
    </div>
  );
}

function PdfCover({ property, sections }) {
  const k = property.kadaster || {};
  const today = new Date().toLocaleDateString("nl-NL", {
    day: "2-digit", month: "long", year: "numeric",
  });
  return (
    <div
      className="pdf-a4-page"
      style={{
        width: "210mm",
        height: "297mm",
        background: pdfBrand.cream,
        color: pdfBrand.ink,
        fontFamily: "var(--font-sans)",
        display: "flex",
        flexDirection: "column",
        boxSizing: "border-box",
        overflow: "hidden",
        borderTop: `3mm solid ${pdfBrand.gold}`,
      }}
    >
      <div
        style={{
          padding: "10mm 16mm 6mm",
          display: "flex",
          justifyContent: "space-between",
          alignItems: "center",
        }}
      >
        <div style={{ display: "flex", flexDirection: "column", gap: "2mm", alignItems: "flex-start" }}>
          <DomicilieLogo height="14mm" />
          {activeCompany.tagline && (
            <span
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: "8.5pt",
                color: pdfBrand.inkSoft,
                letterSpacing: "0.01em",
                maxWidth: "95mm",
              }}
            >
              {activeCompany.tagline}
            </span>
          )}
        </div>
        <span
          style={{
            fontFamily: "var(--font-mono)",
            fontSize: "9pt",
            letterSpacing: "0.18em",
            textTransform: "uppercase",
            color: pdfBrand.inkSoft,
            whiteSpace: "nowrap",
          }}
        >
          Vooronderzoek · {today}
        </span>
      </div>

      <div
        style={{
          margin: "0 16mm",
          height: "128mm",
          borderRadius: "4pt",
          position: "relative",
          overflow: "hidden",
          color: "#fff",
          display: "flex",
          flexDirection: "column",
          justifyContent: "flex-end",
          boxSizing: "border-box",
        }}
      >
        {/* Hero background: real photo when available, fall back to SVG facade */}
        <div style={{ position: "absolute", inset: 0 }}>
          {property.heroPhoto ? (
            <img
              src={property.heroPhoto}
              alt=""
              crossOrigin="anonymous"
              style={{
                width: "100%",
                height: "100%",
                objectFit: "cover",
                display: "block",
              }}
            />
          ) : (
            <PropertyImage property={property} height="100%" />
          )}
        </div>
        {/* Dark gradient overlay for text legibility */}
        <div
          style={{
            position: "absolute",
            inset: 0,
            background:
              "linear-gradient(180deg, rgba(0,0,0,0) 40%, rgba(0,0,0,0.55) 75%, rgba(0,0,0,0.92) 100%)",
          }}
        />
        {/* Foreground text */}
        <div style={{ position: "relative", padding: "18mm 16mm" }}>
          <div
            style={{
              fontFamily: "var(--font-mono)",
              fontSize: "9pt",
              letterSpacing: "0.18em",
              textTransform: "uppercase",
              color: "rgba(255,255,255,0.7)",
              marginBottom: "6mm",
            }}
          >
            {property.address.city}
          </div>
          <h1
            style={{
              fontFamily: "var(--font-sans)",
              fontSize: "48pt",
              fontWeight: 700,
              lineHeight: 1.0,
              letterSpacing: "-0.02em",
              margin: 0,
              maxWidth: "160mm",
              textShadow: "0 2mm 8mm rgba(0,0,0,0.35)",
            }}
          >
            {property.address.street}
          </h1>
          {/* Domicilie-stijl gele accentstreep onder de titel. */}
          <div
            style={{
              width: "60mm",
              height: "1.6mm",
              background: pdfBrand.gold,
              marginTop: "5mm",
              boxShadow: "0 1mm 4mm rgba(0,0,0,0.25)",
            }}
          />
          <div
            style={{
              fontSize: "13pt",
              marginTop: "5mm",
              opacity: 0.9,
              letterSpacing: "0.04em",
            }}
          >
            {property.address.postal} · {property.address.city}
          </div>
        </div>
      </div>

      <div style={{ flex: 1 }} />

      {Array.isArray(sections) && sections.length > 0 && (
        <div
          style={{
            margin: "8mm 16mm 0",
            display: "flex",
            flexDirection: "column",
            gap: "2mm",
          }}
        >
          <div
            style={{
              fontFamily: "var(--font-mono)",
              fontSize: "8pt",
              letterSpacing: "0.16em",
              textTransform: "uppercase",
              color: pdfBrand.gold,
              marginBottom: "1mm",
            }}
          >
            Inhoud
          </div>
          <div
            style={{
              display: "grid",
              gridTemplateColumns: "repeat(2, 1fr)",
              columnGap: "10mm",
              rowGap: "1.5mm",
              fontSize: "10pt",
              color: pdfBrand.navy,
            }}
          >
            {sections.map((s, i) => {
              const meta = SECTION_META[s.type] || { title: "Bijlage" };
              const title =
                s.type === "upload"
                  ? s.ex?.title || s.ex?.fileName || "Document"
                  : meta.title;
              return (
                <div
                  key={i}
                  style={{
                    display: "flex",
                    gap: "3mm",
                    alignItems: "baseline",
                    borderBottom: `0.5pt dotted ${pdfBrand.rule}`,
                    padding: "1mm 0",
                  }}
                >
                  <span
                    style={{
                      color: pdfBrand.gold,
                      fontFamily: "var(--font-mono)",
                      fontSize: "8pt",
                      width: "6mm",
                    }}
                  >
                    {String(i + 1).padStart(2, "0")}
                  </span>
                  <span>{title}</span>
                </div>
              );
            })}
          </div>
        </div>
      )}

      <div
        style={{
          marginTop: "8mm",
          background: "#000",
          color: "#fff",
          display: "grid",
          gridTemplateColumns: "repeat(4, 1fr)",
          borderTop: `2mm solid ${pdfBrand.gold}`,
        }}
      >
        {[
          { lbl: "Bouwjaar",    val: k.bouwjaar    || "—" },
          { lbl: "Oppervlakte", val: k.oppervlakte || "—" },
          { lbl: "WOZ-waarde",  val: k.woz         || "—" },
          { lbl: "Eigendom",    val: k.eigendom    || "—" },
        ].map((c, i) => (
          <div
            key={i}
            style={{
              padding: "9mm 7mm",
              borderRight: i < 3 ? "1px solid rgba(255,255,255,0.15)" : "none",
              minWidth: 0,
            }}
          >
            <div
              style={{
                fontSize: "8pt",
                textTransform: "uppercase",
                letterSpacing: "0.14em",
                color: pdfBrand.gold,
                marginBottom: "3mm",
              }}
            >
              {c.lbl}
            </div>
            <div
              style={{
                fontFamily: "var(--font-sans)",
                fontSize: "14pt",
                lineHeight: 1.2,
                overflowWrap: "break-word",
              }}
            >
              {c.val}
            </div>
          </div>
        ))}
      </div>

      <DomicilieContactStrip />
    </div>
  );
}

function PdfContentPage({ property, blocks, pageNum, totalPages }) {
  const compact = blocks.length >= 3;
  return (
    <div
      className="pdf-a4-page"
      style={{
        width: "210mm",
        height: "297mm",
        background: pdfBrand.cream,
        color: pdfBrand.ink,
        fontFamily: "var(--font-sans)",
        display: "flex",
        flexDirection: "column",
        padding: "12mm 16mm 10mm",
        boxSizing: "border-box",
        overflow: "hidden",
        borderTop: `2mm solid ${pdfBrand.gold}`,
      }}
    >
      <div
        style={{
          display: "flex",
          justifyContent: "space-between",
          alignItems: "center",
          borderBottom: `1pt solid ${pdfBrand.navy}`,
          paddingBottom: "4mm",
          marginBottom: "5mm",
          gap: "6mm",
        }}
      >
        <DomicilieLogo height="10mm" />
        <div style={{ flex: 1, textAlign: "right" }}>
          <div
            style={{
              fontFamily: "var(--font-sans)",
              fontSize: "12pt",
              fontWeight: 600,
              color: pdfBrand.navy,
              lineHeight: 1.1,
            }}
          >
            {property.address.street}
          </div>
          <div style={{ fontSize: "8pt", color: pdfBrand.inkMute, marginTop: "1mm" }}>
            {property.address.postal} · {property.address.city}
          </div>
        </div>
      </div>

      <div
        style={{
          display: "flex",
          flexDirection: "column",
          gap: compact ? "4mm" : "6mm",
          flex: 1,
          minHeight: 0,
        }}
      >
        {blocks.map((b, i) => (
          <PdfBlock key={i} section={b} property={property} compact={compact} />
        ))}
      </div>

      <div
        style={{
          marginTop: "4mm",
          paddingTop: "3mm",
          borderTop: `1pt solid ${pdfBrand.rule}`,
          display: "flex",
          justifyContent: "space-between",
          fontSize: "7.5pt",
          color: pdfBrand.inkMute,
          letterSpacing: "0.04em",
        }}
      >
        <span>{activeCompany.name}</span>
        <span>{pageNum} / {totalPages}</span>
      </div>
    </div>
  );
}

function PdfBlock({ section, property, compact }) {
  const meta = SECTION_META[section.type] || { kicker: "Bijlage", title: "Bijlage" };
  const title =
    section.type === "upload"
      ? section.ex?.title || section.ex?.fileName || "Document"
      : meta.title;
  const kicker =
    section.type === "upload"
      ? section.ex?.fileType || "Bijlage"
      : meta.kicker;
  return (
    <div
      style={{
        flex: 1,
        minHeight: 0,
        background: pdfBrand.paper,
        border: `1pt solid ${pdfBrand.rule}`,
        borderLeft: `2pt solid ${pdfBrand.gold}`,
        borderRadius: "2pt",
        padding: compact ? "5mm 8mm" : "8mm 10mm",
        display: "flex",
        flexDirection: "column",
        overflow: "hidden",
      }}
    >
      <div style={{ marginBottom: compact ? "3mm" : "5mm" }}>
        <div
          style={{
            fontFamily: "var(--font-mono)",
            fontSize: "7.5pt",
            letterSpacing: "0.16em",
            textTransform: "uppercase",
            color: pdfBrand.gold,
            marginBottom: "1mm",
          }}
        >
          {kicker}
        </div>
        <div
          style={{
            fontFamily: "var(--font-sans)",
            fontSize: compact ? "14pt" : "18pt",
            fontWeight: 700,
            color: pdfBrand.navy,
            lineHeight: 1.05,
            letterSpacing: "-0.01em",
          }}
        >
          {title}
        </div>
      </div>
      <div style={{ flex: 1, minHeight: 0, overflow: "hidden" }}>
        <PdfBlockBody type={section.type} property={property} extra={section.ex} />
      </div>
      {SECTION_SOURCE[section.type] && (
        <div
          style={{
            marginTop: "3mm",
            paddingTop: "2mm",
            borderTop: `0.5pt dotted ${pdfBrand.rule}`,
            fontFamily: "var(--font-mono)",
            fontSize: "6.5pt",
            letterSpacing: "0.08em",
            textTransform: "uppercase",
            color: pdfBrand.inkMute,
          }}
        >
          Bron · {SECTION_SOURCE[section.type].replace("{company}", activeCompany.name)}
        </div>
      )}
    </div>
  );
}

function PdfBlockBody({ type, property, extra }) {
  const data = property[type];
  if (type === "kadaster" && data)
    return (
      <KvGrid
        rows={[
          ["Eigenaar", data.eigenaar],
          ["Perceel", data.perceel],
          ["Oppervlakte", data.oppervlakte],
          ["Eigendom", data.eigendom],
          ["Bouwjaar", data.bouwjaar],
          ["WOZ-waarde", data.woz],
          ["Peildatum", data.peildatum],
        ]}
      />
    );
  if (type === "bestemming" && data)
    return (
      <KvGrid
        rows={[
          ["Type", data.type],
          ["Gebruik", data.gebruik],
          ["Bouwhoogte", data.bouwhoogte],
          ["Uitbreiding", data.uitbreiding],
          ["Monument", data.monument],
          ["Laatst gewijzigd", data.laatstGewijzigd],
        ]}
      />
    );
  if (type === "buurt" && data) return <BuurtBody data={data} />;
  if (type === "fundering" && data) return <FunderingBody data={data} />;
  if (type === "kadastralekaart") return <KadastraleKaartBody property={property} />;
  if (type === "bag") return <BagBody data={deriveBag(property)} />;
  if (type === "wozhistorie")
    return (
      <WozHistorieBody
        data={property.wozhistorie || deriveWozHistorie(property.kadaster?.woz)}
      />
    );
  if (type === "energielabel")
    return <EnergielabelBody data={deriveEnergielabel(property.kadaster?.bouwjaar)} />;
  if (type === "vergelijkbaar" && data) return <VergelijkbaarBody data={data} />;
  if (type === "markt" && data) return <MarktBody data={data} />;
  if (type === "aankoop" && data) return <AankoopBody data={data} />;
  if (type === "hypotheek" && data)
    return (
      <KvGrid
        rows={[
          ["WOZ-waarde", data.woz],
          ["Hypotheek-indicatie", data.indicatie],
          ["Maandlast (indicatie)", data.maandlast],
          ["Rente", data.rente],
          ["Looptijd", data.looptijd],
        ]}
      />
    );
  if (type === "onderhoud" && data) return <OnderhoudBody data={data} />;
  if (type === "upload") return <UploadBody extra={extra} />;
  return null;
}

function KvGrid({ rows }) {
  return (
    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "4mm 10mm" }}>
      {rows.map(([k, v], i) => (
        <div key={i}>
          <div
            style={{
              fontSize: "7.5pt",
              textTransform: "uppercase",
              letterSpacing: "0.12em",
              color: pdfBrand.inkMute,
              marginBottom: "1mm",
            }}
          >
            {k}
          </div>
          <div style={{ fontSize: "11pt", color: pdfBrand.navy, fontWeight: 500 }}>
            {v || "—"}
          </div>
        </div>
      ))}
    </div>
  );
}

function KvCell({ lbl, val }) {
  return (
    <div style={{ flex: 1 }}>
      <div
        style={{
          fontSize: "7.5pt",
          textTransform: "uppercase",
          letterSpacing: "0.12em",
          color: pdfBrand.inkMute,
          marginBottom: "1mm",
        }}
      >
        {lbl}
      </div>
      <div style={{ fontSize: "10.5pt", color: pdfBrand.navy, fontWeight: 500 }}>
        {val || "—"}
      </div>
    </div>
  );
}

function BarMini({ title, rows }) {
  const max = Math.max(...rows.map((r) => r.v));
  return (
    <div>
      <div
        style={{
          fontSize: "8pt",
          textTransform: "uppercase",
          letterSpacing: "0.12em",
          color: pdfBrand.inkMute,
          marginBottom: "3mm",
        }}
      >
        {title}
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: "2mm" }}>
        {rows.map((r, i) => (
          <div
            key={i}
            style={{ display: "flex", alignItems: "center", gap: "3mm", fontSize: "8.5pt" }}
          >
            <div style={{ width: "26mm", color: pdfBrand.inkSoft }}>{r.label}</div>
            <div
              style={{
                flex: 1,
                height: "3mm",
                background: pdfBrand.panel,
                borderRadius: "1mm",
                overflow: "hidden",
              }}
            >
              <div
                style={{
                  width: `${(r.v / max) * 100}%`,
                  height: "100%",
                  background: pdfBrand.gold,
                }}
              />
            </div>
            <div style={{ width: "9mm", textAlign: "right", color: pdfBrand.navy, fontWeight: 500 }}>
              {r.v}%
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

function BuurtBody({ data }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "5mm", height: "100%" }}>
      <div style={{ display: "flex", gap: "8mm" }}>
        <KvCell lbl="Buurt" val={data.naam} />
        <KvCell lbl="Bewoners" val={data.bewoners} />
        <KvCell lbl="Dichtheid" val={data.dichtheid} />
        <KvCell lbl="Inkomen" val={data.inkomen} />
      </div>
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "1fr 1fr",
          gap: "8mm",
          flex: 1,
          minHeight: 0,
        }}
      >
        <BarMini title="Leeftijd" rows={data.leeftijd} />
        <BarMini title="Huishouden" rows={data.huishouden} />
      </div>
    </div>
  );
}

function FunderingBody({ data }) {
  const score = data.risicoScore || 0;
  const color = score > 0.5 ? "#c2410c" : score > 0.3 ? pdfBrand.gold : "#15803d";
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "5mm" }}>
      <KvGrid
        rows={[
          ["Type fundering", data.type],
          ["Laatste inspectie", data.laatsteInspectie],
          ["Grondwater", data.grondwater],
          ["Advies", data.advies],
        ]}
      />
      <div>
        <div
          style={{
            fontSize: "7.5pt",
            textTransform: "uppercase",
            letterSpacing: "0.12em",
            color: pdfBrand.inkMute,
            marginBottom: "2mm",
          }}
        >
          Risicoprofiel - {data.risico}
        </div>
        <div
          style={{
            height: "4mm",
            background: pdfBrand.panel,
            borderRadius: "1mm",
            overflow: "hidden",
          }}
        >
          <div style={{ width: `${score * 100}%`, height: "100%", background: color }} />
        </div>
      </div>
    </div>
  );
}

function VergelijkbaarBody({ data }) {
  return (
    <div>
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "2fr 1fr 1fr 1fr",
          fontSize: "7.5pt",
          textTransform: "uppercase",
          letterSpacing: "0.12em",
          color: pdfBrand.inkMute,
          paddingBottom: "2mm",
          borderBottom: `1pt solid ${pdfBrand.rule}`,
        }}
      >
        <div>Adres</div>
        <div>Oppervlakte</div>
        <div>Verkocht</div>
        <div style={{ textAlign: "right" }}>Prijs</div>
      </div>
      {data.map((r, i) => (
        <div
          key={i}
          style={{
            display: "grid",
            gridTemplateColumns: "2fr 1fr 1fr 1fr",
            padding: "3mm 0",
            borderBottom:
              i < data.length - 1 ? `1pt solid ${pdfBrand.rule}` : "none",
            fontSize: "10pt",
          }}
        >
          <div style={{ color: pdfBrand.navy, fontWeight: 500 }}>{r.adres}</div>
          <div style={{ color: pdfBrand.inkSoft }}>{r.m2} m²</div>
          <div style={{ color: pdfBrand.inkSoft }}>{r.verkocht}</div>
          <div style={{ textAlign: "right", color: pdfBrand.navy, fontWeight: 500 }}>
            {r.prijs}
          </div>
        </div>
      ))}
    </div>
  );
}

function MarktBody({ data }) {
  const max = Math.max(...data.serie);
  const min = Math.min(...data.serie);
  const range = max - min || 1;
  const w = 200, h = 40;
  const pts = data.serie
    .map((v, i) => {
      const x = (i / (data.serie.length - 1)) * w;
      const y = h - ((v - min) / range) * h;
      return `${x},${y}`;
    })
    .join(" ");
  const areaPts = `0,${h} ${pts} ${w},${h}`;
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "5mm", height: "100%" }}>
      <div style={{ display: "flex", gap: "10mm" }}>
        <KvCell lbl={`Trend (${data.periode})`} val={data.trend} />
        <KvCell lbl="Gemiddelde m²-prijs" val={data.gemiddeld} />
      </div>
      <svg
        viewBox={`0 0 ${w} ${h}`}
        style={{ width: "100%", height: "32mm" }}
        preserveAspectRatio="none"
      >
        <polygon points={areaPts} fill={`${pdfBrand.gold}22`} />
        <polyline
          points={pts}
          fill="none"
          stroke={pdfBrand.gold}
          strokeWidth="1.4"
          strokeLinejoin="round"
          strokeLinecap="round"
        />
      </svg>
    </div>
  );
}

function AankoopBody({ data }) {
  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "1fr 1fr",
        gap: "8mm",
        height: "100%",
      }}
    >
      <div>
        <div
          style={{
            fontSize: "8pt",
            textTransform: "uppercase",
            letterSpacing: "0.12em",
            color: pdfBrand.gold,
            marginBottom: "3mm",
          }}
        >
          Kansen
        </div>
        <ul
          style={{
            margin: 0,
            padding: 0,
            listStyle: "none",
            display: "flex",
            flexDirection: "column",
            gap: "2mm",
          }}
        >
          {data.kansen.map((k, i) => (
            <li
              key={i}
              style={{
                fontSize: "9.5pt",
                color: pdfBrand.ink,
                paddingLeft: "5mm",
                position: "relative",
                lineHeight: 1.45,
              }}
            >
              <span style={{ position: "absolute", left: 0, color: pdfBrand.gold, fontWeight: 600 }}>
                +
              </span>
              {k}
            </li>
          ))}
        </ul>
      </div>
      <div>
        <div
          style={{
            fontSize: "8pt",
            textTransform: "uppercase",
            letterSpacing: "0.12em",
            color: pdfBrand.navy,
            marginBottom: "3mm",
          }}
        >
          Risico's
        </div>
        <ul
          style={{
            margin: 0,
            padding: 0,
            listStyle: "none",
            display: "flex",
            flexDirection: "column",
            gap: "2mm",
          }}
        >
          {data.risicos.map((k, i) => (
            <li
              key={i}
              style={{
                fontSize: "9.5pt",
                color: pdfBrand.ink,
                paddingLeft: "5mm",
                position: "relative",
                lineHeight: 1.45,
              }}
            >
              <span style={{ position: "absolute", left: 0, color: pdfBrand.navy, fontWeight: 600 }}>
                −
              </span>
              {k}
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}

function OnderhoudBody({ data }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "0" }}>
      {data.map((r, i) => (
        <div
          key={i}
          style={{
            display: "grid",
            gridTemplateColumns: "20mm 1fr",
            padding: "3mm 0",
            borderBottom:
              i < data.length - 1 ? `1pt solid ${pdfBrand.rule}` : "none",
            alignItems: "baseline",
          }}
        >
          <div
            style={{
              fontFamily: "var(--font-sans)",
              color: pdfBrand.gold,
              fontSize: "15pt",
              lineHeight: 1,
            }}
          >
            {r.jaar}
          </div>
          <div style={{ fontSize: "10.5pt", color: pdfBrand.ink, lineHeight: 1.45 }}>
            {r.werk}
          </div>
        </div>
      ))}
    </div>
  );
}

function pdokKadastraleKaartUrl(rd, { width = 900, height = 600, span = 160 } = {}) {
  if (!rd) return null;
  const [cx, cy] = rd;
  // Match the requested pixel aspect so the WMS image doesn't get squashed.
  const halfW = span / 2;
  const halfH = (span / 2) * (height / width);
  const bbox = [cx - halfW, cy - halfH, cx + halfW, cy + halfH].join(",");
  const params = new URLSearchParams({
    service: "WMS",
    version: "1.3.0",
    request: "GetMap",
    layers: "Kadastralekaart",
    styles: "",
    crs: "EPSG:28992",
    bbox,
    width: String(width),
    height: String(height),
    format: "image/png",
    transparent: "false",
  });
  return `https://service.pdok.nl/kadaster/kadastralekaart/wms/v5_0?${params.toString()}`;
}

function KadastraleKaartBody({ property }) {
  const k = property.kadaster || {};
  const mapUrl = pdokKadastraleKaartUrl(property.rd);
  const [rx, ry] = property.rd || [];
  return (
    <div style={{ display: "flex", gap: "6mm", height: "100%" }}>
      <div
        style={{
          flex: 1,
          minHeight: 0,
          border: `1pt solid ${pdfBrand.rule}`,
          borderRadius: "2pt",
          overflow: "hidden",
          background: "#F7F8FB",
        }}
      >
        {mapUrl ? (
          <img
            src={mapUrl}
            alt="Kadastrale Kaart (PDOK)"
            crossOrigin="anonymous"
            style={{
              width: "100%",
              height: "100%",
              objectFit: "cover",
              display: "block",
            }}
          />
        ) : null}
      </div>
      <div style={{ width: "55mm", display: "flex", flexDirection: "column", gap: "3mm" }}>
        <KvCell lbl="Kadastrale aanduiding" val={k.perceel} />
        <KvCell lbl="Perceeloppervlakte" val={k.perceelOppervlakte || k.oppervlakte} />
        <KvCell
          lbl="Gemeente / sectie"
          val={(k.perceel || "—").split(" ").slice(0, 2).join(" / ")}
        />
        <KvCell lbl="Grens & grootte" val="Vastgesteld" />
        <KvCell
          lbl="Coördinaten (RD)"
          val={rx && ry ? `${rx.toLocaleString("nl-NL")} · ${ry.toLocaleString("nl-NL")}` : "—"}
        />
      </div>
    </div>
  );
}

function BagBody({ data }) {
  return (
    <KvGrid
      rows={[
        ["BAG-identificatie", data.bagId],
        ["Status", data.status],
        ["Gebruiksdoel", data.gebruiksdoel],
        ["Oorspronkelijk bouwjaar", data.bouwjaar],
        ["Gebruiksoppervlakte", data.oppervlakte],
        ["Gemeente", data.gemeente],
      ]}
    />
  );
}

function WozHistorieBody({ data }) {
  if (!data || data.length === 0) return null;
  const fmt = (n) => "€ " + n.toLocaleString("nl-NL").replace(/,/g, ".");
  const rows = [...data].reverse(); // nieuwste bovenaan
  // Split in twee kolommen zodat een 12-rij tabel niet enorm lang wordt
  const half = Math.ceil(rows.length / 2);
  const left = rows.slice(0, half);
  const right = rows.slice(half);
  const Col = ({ items }) => (
    <div style={{ flex: 1 }}>
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "1fr 1fr",
          fontSize: "7.5pt",
          textTransform: "uppercase",
          letterSpacing: "0.12em",
          color: pdfBrand.inkMute,
          paddingBottom: "1.5mm",
          borderBottom: `1pt solid ${pdfBrand.rule}`,
        }}
      >
        <div>Peildatum</div>
        <div style={{ textAlign: "right" }}>WOZ-waarde</div>
      </div>
      {items.map((d, i) => (
        <div
          key={d.jaar}
          style={{
            display: "grid",
            gridTemplateColumns: "1fr 1fr",
            padding: "2mm 0",
            borderBottom: i < items.length - 1 ? `0.5pt solid ${pdfBrand.rule}` : "none",
            fontSize: "10pt",
            alignItems: "baseline",
          }}
        >
          <div style={{ color: pdfBrand.inkSoft }}>01-01-{d.jaar}</div>
          <div style={{ textAlign: "right", color: pdfBrand.navy, fontWeight: 500 }}>
            {fmt(d.waarde)}
          </div>
        </div>
      ))}
    </div>
  );
  return (
    <div style={{ display: "flex", gap: "8mm", height: "100%" }}>
      <Col items={left} />
      <Col items={right} />
    </div>
  );
}

function EnergielabelBody({ data }) {
  const order = ["A++++", "A+++", "A++", "A+", "A", "B", "C", "D", "E", "F", "G"];
  const colors = {
    "A++++": "#0a7c3a",
    "A+++": "#0e8d3f",
    "A++": "#3aa84a",
    "A+": "#6cba50",
    A: "#9bc94e",
    B: "#cfd84a",
    C: "#f1d637",
    D: "#f1a531",
    E: "#ed7a2c",
    F: "#e25324",
    G: "#cf2723",
  };
  return (
    <div style={{ display: "flex", gap: "8mm", height: "100%", alignItems: "stretch" }}>
      <div style={{ display: "flex", flexDirection: "column", gap: "1mm", width: "32mm" }}>
        {order.map((l) => {
          const active = l === data.label;
          return (
            <div
              key={l}
              style={{
                display: "flex",
                alignItems: "center",
                gap: "3mm",
                background: colors[l],
                color: "#fff",
                padding: "1mm 3mm",
                fontFamily: "var(--font-sans)",
                fontWeight: 700,
                fontSize: active ? "11pt" : "8pt",
                borderRadius: "1mm",
                opacity: active ? 1 : 0.55,
                transform: active ? "scale(1.05)" : "none",
                transformOrigin: "left center",
              }}
            >
              <span>{l}</span>
              {active && (
                <span style={{ marginLeft: "auto", fontSize: "7pt", letterSpacing: "0.1em" }}>
                  ←
                </span>
              )}
            </div>
          );
        })}
      </div>
      <div style={{ flex: 1, display: "flex", flexDirection: "column", gap: "3mm" }}>
        <KvCell lbl="Definitief energielabel" val={data.label} />
        <KvCell lbl="Registratie" val={data.registratie} />
        <KvCell lbl="Afgegeven" val={data.afgegeven} />
        <KvCell lbl="Geldigheid" val={data.geldig} />
        <KvCell lbl="Methode" val={data.methode} />
      </div>
    </div>
  );
}

function UploadBody({ extra }) {
  if (!extra) return null;
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: "4mm" }}>
      <div
        style={{
          fontSize: "10pt",
          color: pdfBrand.ink,
          lineHeight: 1.55,
        }}
      >
        {extra.summary}
      </div>
      {Array.isArray(extra.bullets) && (
        <ul
          style={{
            margin: 0,
            padding: 0,
            listStyle: "none",
            display: "flex",
            flexDirection: "column",
            gap: "2mm",
          }}
        >
          {extra.bullets.map((b, i) => (
            <li
              key={i}
              style={{
                fontSize: "9.5pt",
                color: pdfBrand.ink,
                paddingLeft: "5mm",
                position: "relative",
                lineHeight: 1.45,
              }}
            >
              <span style={{ position: "absolute", left: 0, color: pdfBrand.gold }}>·</span>
              {b}
            </li>
          ))}
        </ul>
      )}
      <div
        style={{
          marginTop: "auto",
          display: "flex",
          gap: "8mm",
          fontSize: "8pt",
          color: pdfBrand.inkMute,
          paddingTop: "3mm",
          borderTop: `1pt solid ${pdfBrand.rule}`,
        }}
      >
        {extra.fileName && <span>Bron: {extra.fileName}</span>}
        {extra.date && <span>Datum: {extra.date}</span>}
        {extra.pages && <span>Omvang: {extra.pages} p.</span>}
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Bootstrap - read the company slug from the URL, load its branding from
// data/companies.json, theme the app, then render. The slug is the first path
// segment, e.g. preview.workflowautomations.nl/domicilie → "domicilie".
// Unknown/empty slug falls back to the neutral default theme.
// ---------------------------------------------------------------------------
async function bootstrap() {
  const slug = decodeURIComponent(location.pathname.replace(/^\/+|\/+$/g, "").split("/")[0] || "");
  try {
    const res = await fetch("/data/companies.json", { cache: "no-cache" });
    if (res.ok) {
      const manifest = await res.json();
      const companies = Array.isArray(manifest) ? manifest : manifest.companies || [];
      const company = companies.find((c) => c.slug === slug);
      if (company) applyCompanyTheme(company);
    }
  } catch (e) {
    // Offline / missing manifest → keep the neutral default theme.
    console.warn("Kon companies.json niet laden, val terug op standaardthema.", e);
  }
  ReactDOM.createRoot(document.getElementById("root")).render(<App />);
}

bootstrap();
