// Voordenker, data, options and scenario engine.

// ============== TOOL VERSIE ==============
// Verhoog dit nummer bij elke release (semver):
//   major (2.0.0)  - input-structuur breekt of grote UX-wijziging
//   minor (1.1.0)  - nieuwe drempel, nieuwe parameter, nieuwe scenario's
//   patch (1.0.1)  - kalibratie van getallen, tekstuele aanpassingen, bugfixes
//
// Bij release:
//   1. bash release.sh <NIEUW>   (snapshot huidige versie in archive/)
//   2. Verhoog TOOL_VERSION hier
//   3. Werk current_version bij in api/config.php
//
// Drie ontwikkelregels voor blijvende werking van oude share-links:
//   - nieuwe parameters altijd optioneel met default
//   - hernoem niet zonder migratie in api/migrations.php
//   - verwijder geen parameters die in oude shares voorkomen
const TOOL_VERSION = "1.0.0";
if (typeof window !== 'undefined') window.TOOL_VERSION = TOOL_VERSION;


const PROVINCIES = [
  {v:'gld', l:'Gelderland', net:'Liander', sub:['oost','zuid']},
  {v:'utr', l:'Utrecht', net:'Stedin'},
  {v:'nh',  l:'Noord-Holland', net:'Liander'},
  {v:'zh',  l:'Zuid-Holland', net:'Stedin', sub:['noord','zuid']},
  {v:'zl',  l:'Zeeland', net:'Stedin'},
  {v:'nb',  l:'Noord-Brabant', net:'Enexis'},
  {v:'lim', l:'Limburg', net:'Enexis'},
  {v:'ov',  l:'Overijssel', net:'Enexis'},
  {v:'dr',  l:'Drenthe', net:'Enexis'},
  {v:'gr',  l:'Groningen', net:'Enexis'},
  {v:'fr',  l:'Friesland', net:'Liander'},
  {v:'fl',  l:'Flevoland', net:'Liander'},
];

// W/m² approx. installed-power demand for all-electric scenarios
const BUILDING = [
  {v:'ikc',   l:'IKC / basisonderwijs',     w:25, vng:3850, woon:false},
  {v:'vo',    l:'VO',                       w:30, vng:3600, woon:false},
  {v:'ho',    l:'HO',                       w:50, vng:4100, woon:false},
  {v:'zorg',  l:'Zorg',                     w:60, vng:4900, woon:false},
  {v:'maats', l:'Maatschappelijk',          w:30, vng:3400, woon:false},
  {v:'app',   l:'Appartementen',            w:22, vng:2900, woon:true},
  {v:'egw',   l:'Eengezinswoningen',        w:18, vng:2700, woon:true},
  {v:'trans', l:'Transformatie (bestaand)', w:30, vng:3100, woon:false},
];

const OPGAVES = [
  {v:'nb',  l:'Nieuwbouw'},
  {v:'sln', l:'Sloop + Nieuwbouw'},
  {v:'ren', l:'Renovatie'},
];

const GAS = [
  {v:'beh', l:'Aanwezig + behouden'},
  {v:'uit', l:'Aanwezig + uitfaseren'},
  {v:'gn',  l:'Niet aanwezig'},
];

const AANSLUIT = [
  {v:'80',   l:'3×80A',   kva:55,   kw:47,  tag:'kleinverbruik-grens', cls:'kv'},
  {v:'100',  l:'3×100A',  kva:69,   kw:59,  tag:''},
  {v:'125',  l:'3×125A',  kva:87,   kw:74,  tag:''},
  {v:'160',  l:'3×160A',  kva:111,  kw:94,  tag:''},
  {v:'200',  l:'3×200A',  kva:139,  kw:118, tag:''},
  {v:'250',  l:'3×250A',  kva:173,  kw:147, tag:'zware LS'},
  {v:'400',  l:'3×400A',  kva:277,  kw:236, tag:''},
  {v:'630',  l:'3×630A',  kva:436,  kw:371, tag:'trafo'},
  {v:'800',  l:'3×800A',  kva:554,  kw:471, tag:'trafo'},
  {v:'1000', l:'3×1000A', kva:693,  kw:589, tag:'trafo'},
  {v:'1250', l:'3×1250A', kva:866,  kw:736, tag:'trafo'},
  {v:'1600', l:'3×1600A', kva:1108, kw:942, tag:'grote trafo'},
];

const TERUGLEV = [
  {v:'ja',  l:'Ja'},
  {v:'ngm', l:'Ja, niet essentieel'},
  {v:'nee', l:'Nee'},
];

// Tooltips, geen techneuten-taal, korte uitleg
const TIPS = {
  prov: 'Welke provincie ligt het project? Bepaalt mede de netbeheerder (Liander, Stedin, Enexis) en daarmee de wachttijd voor zwaarder vermogen.',
  sub:  'Sommige provincies hebben sterk verschillende netcongestie per regio. Bv. Gelderland-oost zit dichter tegen knelpunten dan Gelderland-zuid.',
  geb:  'Type gebouw bepaalt de stichtingskostennorm (VNG) en het verwacht vermogen per m². Een zorggebouw verbruikt circa twee tot drie keer zoveel als een basisschool.',
  opg:  'Sloop+nieuwbouw of nieuwbouw triggert vaak een ruimtelijke procedure; zuivere renovatie meestal niet.',
  gas:  'Bij gasloos worden warmtepompen en piekstroom maatgevend voor de aansluiting. Gas behouden bij renovatie kan het netbeslag halveren.',
  bvo:  'Bruto vloeroppervlak, de eerste sturing voor stichtingskosten en aansluitvermogen. Niet de m² gebruikersoppervlak.',
  een:  'Aantal woningen of eenheden. Telt mee bij wonen voor de normbenadering en bij appartementen voor het verwachte netbeslag.',
  aans: 'Voorgenomen elektrische hoofdaansluiting. 3×80A is de grens van kleinverbruik (≤55 kVA). Alles daarboven is grootverbruik met langere doorlooptijd en kans op congestie.',
  ter:  'Wil je stroom terugleveren aan het net (PV-overschot)? In congestiegebieden is teruglevering vaak het eerste dat sneuvelt.',
  opwek:'Eigen opwek/WKO verandert de netvraag. Een eigen accu of WKO kan de gevraagde piek met 30-50% verlagen.',
};

// ============== ENERGIE KENGETALLEN ==============
// W/m² baseline per gebouwtype, op anchor-BVO van 3000 m² in gas-variant.
const W_BASELINE_E = {
  ikc: 28, vo: 30, ho: 35, zorg: 50, maats: 24, app: 22, egw: 16, trans: 32,
};
// Floor en cap per type, voorkomt onrealistische extrapolatie bij extreme BVO.
const W_BOUNDS_E = {
  ikc:   {min:18, max:35},  vo:    {min:20, max:38},
  ho:    {min:24, max:42},  zorg:  {min:40, max:60},
  maats: {min:16, max:32},  app:   {min:14, max:28},
  egw:   {min:10, max:22},  trans: {min:20, max:40},
};
// Bron-correctie bij all-electric (gas !== 'beh')
const BRON_W = { lucht:10, bodem:5, stads:2, geen:0 };
// Eigen opwek-correctie
const OPWEK_W = { geen:0, pv:-2, pvBatterij:-6, smartgrid:-4 };
// Bijzondere toeslagen (boolean opties)
const TOESLAG_W = {
  grootkeuken:8, pantry:2, zwareIct:7, labs:5,
  evLicht:2, evZwaar:6, douches:3, zwembad:10,
};
// Gebruiksprofiel per gebouwtype (voor accu-balans)
const GEBRUIKSPROFIEL = {
  ikc:   {piekUur:6,  deellastUur:4, nachtUur:14, basislastFract:0.15},
  vo:    {piekUur:7,  deellastUur:3, nachtUur:14, basislastFract:0.15},
  ho:    {piekUur:8,  deellastUur:6, nachtUur:10, basislastFract:0.20},
  zorg:  {piekUur:12, deellastUur:6, nachtUur:6,  basislastFract:0.55},
  maats: {piekUur:8,  deellastUur:3, nachtUur:13, basislastFract:0.15},
  app:   {piekUur:4,  deellastUur:8, nachtUur:12, basislastFract:0.30},
  egw:   {piekUur:3,  deellastUur:7, nachtUur:14, basislastFract:0.25},
  trans: {piekUur:5,  deellastUur:4, nachtUur:15, basislastFract:0.10},
};
// Ruwe congestie-vuistregel per provincie/subregio
const CONGESTIE_NL = {
  gld_oost:'wachtrij', gld_zuid:'krap',
  gld:'krap',
  nb:'krap', lim:'krap', utr:'krap',
  zh_zuid:'krap', zh_noord:'krap', zh:'krap',
  nh:'redelijk', zl:'redelijk', ov:'redelijk', fl:'redelijk',
  dr:'ruim', gr:'ruim', fr:'ruim',
};
// ACM-prioriteringskader vanaf 1 juli 2026: onderwijs + zorg gaan voor
const ACM_PRIO_GEBS = ['ikc','vo','ho','zorg'];

function congestieVoor(b){
  const key = b.subregio ? (b.provincie + '_' + b.subregio) : b.provincie;
  return CONGESTIE_NL[key] || CONGESTIE_NL[b.provincie] || 'redelijk';
}

// ============== DEMAND-BEREKENING ==============
function calcDemand(b){
  const geb = b.geb || 'ikc';
  const bvo = +b.bvo || 0;
  const cosPhi = +b.cosPhi || 0.85;
  const baseline = W_BASELINE_E[geb] ?? W_BASELINE_E.ikc;
  const bounds   = W_BOUNDS_E[geb]   || {min:14, max:60};

  // Schaalfactor: -3 W/m² per BVO-verdubbeling vanaf 3000 m²
  let w = baseline;
  if(bvo > 0) w = baseline - 3 * Math.log2(bvo/3000);

  // All-electric bron-correctie (alleen als gas niet behouden blijft)
  const wb = b.warmteBron || 'lucht';
  if(b.gas !== 'beh' && wb !== 'geen'){
    w += (BRON_W[wb] ?? 0);
  }

  // Eigen opwek (string in nieuwe schema, bool-fallback voor oude shares)
  let opwek = b.eigenOpwek;
  if(typeof opwek === 'boolean') opwek = opwek ? 'pvBatterij' : 'geen';
  w += (OPWEK_W[opwek] ?? 0);

  // Toeslagen
  const tg = b.toeslagen || {};
  Object.keys(TOESLAG_W).forEach(k => { if(tg[k]) w += TOESLAG_W[k]; });

  // Bounds clamp
  w = Math.max(bounds.min, Math.min(bounds.max, w));

  const wPerM2 = Math.round(w*10)/10;
  const piekKw = Math.round(wPerM2 * bvo / 1000);
  const piekKva = Math.round(piekKw / cosPhi);

  // Advies-aansluiting: eerstvolgende waarvan kVA >= piekKva * 1,10
  const target = piekKva * 1.10;
  const adv = AANSLUIT.find(a => a.kva >= target) || AANSLUIT[AANSLUIT.length-1];

  return {
    wPerM2,
    piekKw,
    piekKva,
    adviesAansluiting: adv.v,
    adviesLabel: adv.l,
    adviesKva: adv.kva,
    adviesKw: adv.kw,
    cosPhi,
    // backward-compat veld voor oude UI (TreeEnergie verwacht dem.kva)
    kva: piekKva,
  };
}

// ============== ACCU-HAALBAARHEID ==============
function accuHaalbaarheid(piekKw, aansluitKw, profile){
  if(!profile) profile = GEBRUIKSPROFIEL.maats;
  const dagTekort   = Math.max(0, piekKw - aansluitKw) * profile.piekUur
                    + Math.max(0, piekKw*0.5 - aansluitKw) * profile.deellastUur;
  const nachtOplaad = Math.max(0, aansluitKw - piekKw*profile.basislastFract) * profile.nachtUur;
  const marge       = nachtOplaad - dagTekort;
  const haalbaar    = marge > 0;
  const robuust     = marge > dagTekort * 0.2;
  const accuAdvies  = haalbaar ? Math.round(dagTekort * 1.5) : 0;
  return {
    dagTekortKwh:      Math.round(dagTekort),
    nachtOplaadCapKwh: Math.round(nachtOplaad),
    margeKwh:          Math.round(marge),
    haalbaar,
    robuust,
    accuAdviesKwh:     accuAdvies,
  };
}

function aansluitInfo(v){ return AANSLUIT.find(x=>x.v===v) || AANSLUIT[0]; }

// inline translate helper: pick(lang, nl, en) → returns the right string
const _P = (lang, nl, en) => lang === 'en' ? en : nl;

// === DREMPEL SCENARIO LOGIC ===

function blockRO(b, lang='nl'){
  const T = (nl, en) => _P(lang, nl, en);
  const woon = (BUILDING.find(x=>x.v===b.geb)||{}).woon;
  const m2 = +b.bvo || 0;

  // 1. Transformatie = vrijwel altijd functiewijziging -> buitenplans (BOPA),
  //    ongeacht renovatie, sloop+nieuwbouw of nieuwbouw.
  if(b.geb === 'trans'){
    return {
      light:'amber',
      claim: T('Transformatie van bestaand vastgoed, functiewijziging vrijwel zeker.',
               'Transformation of existing real-estate, function change almost certain.'),
      text:[
        T('Een transformatie betekent meestal een andere functie (bijvoorbeeld kantoor naar wonen). Die past zelden binnen het geldende omgevingsplan, dus reken op een buitenplanse omgevingsplanactiviteit (BOPA).',
          'A transformation usually means a different function (e.g. office to housing). That rarely fits the current environmental plan, so expect an out-of-plan environmental permit (BOPA).'),
        T('Een vroeg conceptverzoek en het collegestandpunt ophalen scheelt vier tot zes maanden. Toets vroeg geluid, parkeren, bodem en milieuzonering, want die bepalen de haalbaarheid.',
          'An early concept request and the council position save four to six months. Check noise, parking, soil and zoning early, as they decide feasibility.'),
      ],
      route:'b-bopa',
      conf:[
        T('Vooroverleg / conceptverzoek gemeente','Pre-consultation / concept request'),
        T('BOPA-route in beeld','BOPA route in scope'),
      ],
      research:[
        {l:T('Collegestandpunt functiewijziging ophalen','Obtain council position on function change'),ext:''},
        {l:T('Participatie: check of de gemeente die verplicht heeft gesteld','Participation: check if the municipality made it mandatory'),ext:'IPLO'},
        {l:T('Geluid, parkeren, bodem en milieuzonering toetsen','Check noise, parking, soil and zoning'),ext:'OmgevingsLoket'},
      ],
    };
  }

  // 2. Renovatie zonder functiewijziging -> binnenplans, geen ruimtelijke procedure.
  if(b.opgave === 'ren'){
    return {
      light:'green',
      claim: T('Pure renovatie blijft vrijwel altijd binnen het omgevingsplan.',
               'Pure renovation almost always stays within the environmental plan.'),
      text:[
        T('Renovatie binnen de bestaande contouren en functie is vergunningvrij of valt onder een reguliere omgevingsvergunning. Geen ruimtelijke procedure nodig.',
          'Renovation within existing contours and function is permit-free or falls under a standard permit. No spatial procedure needed.'),
        T('Let op: zodra de functie wijzigt of de contouren uitbreiden kantelt dit naar een BOPA. Controleer ook of geluid-, parkeer- of veiligheidsregels meebewegen.',
          'Note: as soon as the function changes or contours expand, this flips to a BOPA. Also check whether noise, parking or safety rules shift.'),
      ],
      route:'a-renovatie',
      conf:[
        T('Bestaand omgevingsplan (tijdelijk deel) blijft van kracht','Existing environmental plan remains in force'),
        T('Geen planwijziging nodig','No plan amendment required'),
      ],
      research:[{l:T('Geluid- en parkeernormen check','Noise and parking norms check'),ext:'OmgevingsLoket'}],
    };
  }

  // 3. Grootschalige nieuwbouw of sloop+nieuwbouw -> zwaarste route: omgevingsplan wijzigen.
  if(m2 > 5000 || (woon && (+b.eenheden||0) > 25)){
    return {
      light:'amber',
      claim: T('Grootschalige opgave, wijziging van het omgevingsplan waarschijnlijk.',
               'Large-scale project, an environmental-plan amendment is likely.'),
      text:[
        T('Boven 5.000 m2 of meer dan 25 woningen volgt vaak een wijziging van het omgevingsplan in plaats van een BOPA. Reken op negen tot achttien maanden inclusief zienswijzen; beroep loopt rechtstreeks bij de Raad van State.',
          'Above 5,000 m2 or more than 25 dwellings, an environmental-plan amendment often follows instead of a BOPA. Plan for nine to eighteen months including objections; appeal goes directly to the Council of State.'),
        T('Stel vroeg een structuurontwerp op: een grove, globale inpassing van het programma op de locatie (massa, bouwenvelop, functies), geen detailontwerp. In Delft heet dat instrument een PUK (Projectopdracht Ruimtelijk Kader). Gebruik dat ontwerp in het participatietraject, dan haal je de drempels er vroeg uit en verloopt de latere omgevingsvergunning soepeler.',
          'Draw up a structural design early: a rough, global fit of the programme on the site (massing, building envelope, functions), not a detailed design. In Delft this instrument is called a PUK. Use it in the participation process to remove hurdles early and smooth the later permit.'),
      ],
      route:'c-omgevingsplan',
      conf:[
        T('Wijziging omgevingsplan in beeld','Environmental-plan amendment in scope'),
        T('Beroep rechtstreeks bij de Raad van State','Appeal directly to the Council of State'),
      ],
      research:[
        {l:T('Vormvrije m.e.r.-beoordeling (stedelijk ontwikkelingsproject)','Informal EIA screening (urban development project)'),ext:'IPLO'},
        {l:T('Ladder voor duurzame verstedelijking onderbouwen','Substantiate the urban-development ladder'),ext:'IPLO'},
        {l:T('Structuurontwerp + participatieplan vroeg starten','Start structural design + participation plan early'),ext:''},
      ],
    };
  }

  // 4. Sloop+nieuwbouw op normale schaal -> afwijken van het omgevingsplan (BOPA).
  if(b.opgave === 'sln'){
    return {
      light:'amber',
      claim: T('Sloop + nieuwbouw, afwijken van het omgevingsplan waarschijnlijk.',
               'Demolish + new build, deviation from the environmental plan likely.'),
      text:[
        T('Maatvoering en functie verschillen vaak van het oude plan, dus reken op een buitenplanse omgevingsplanactiviteit (BOPA) naast de sloopmelding en de omgevingsvergunning bouw.',
          'Dimensions and function often differ from the old plan, so expect a BOPA alongside the demolition notice and the building permit.'),
        T('Een vroeg conceptverzoek en het collegestandpunt scheelt vier tot zes maanden in de doorlooptijd.',
          'An early concept request and the council position save four to six months.'),
      ],
      route:'b-bopa',
      conf:[
        T('Sloopmelding bij gemeente','Demolition notice to municipality'),
        T('BOPA + omgevingsvergunning bouw','BOPA + building permit'),
      ],
      research:[
        {l:T('Conceptverzoek / vooroverleg gemeente','Concept request / pre-consultation'),ext:'OmgevingsLoket'},
        {l:T('Participatie: check of de gemeente die verplicht heeft gesteld','Participation: check if the municipality made it mandatory'),ext:'IPLO'},
      ],
    };
  }

  // 5. Kleinschalige nieuwbouw -> past binnen het omgevingsplan (binnenplans).
  return {
    light:'green',
    claim: T('Kleinschalige nieuwbouw, past binnen de bestaande regels.',
             'Small-scale new build, fits within existing rules.'),
    text:[
      T('Bij deze schaal volstaat doorgaans een reguliere omgevingsvergunning, mits het omgevingsplan functie, hoogte en oppervlakte dekt (binnenplanse omgevingsplanactiviteit).',
        'At this scale a standard permit usually suffices, provided the environmental plan covers function, height and area (within-plan activity).'),
    ],
    route:'a-binnenplans',
    conf:[
      T('Binnenplans toegestaan','Within-plan, allowed'),
      T('Reguliere doorlooptijd ~8 weken','Standard lead time ~8 weeks'),
    ],
    research:[{l:T('Conformiteit met omgevingsplan','Compliance with environmental plan'),ext:'OmgevingsLoket'}],
  };
}

// ============== ENERGIE SCENARIOS ==============
// Volgorde: specifiek -> algemeen. Eerste match wint.
// Elke scenario kent een trigger(ctx) en een build(ctx, T) die NL+EN copy genereert.
const ENERGIE_SCENARIOS = [
  // -------- MITIGATIES (gas of geplande accu lost het probleem op) --------
  {
    id: 'en-gas-overbrug',
    trigger: c => c.b.gas === 'beh' && c.ratio > 1,
    build: (c, T) => ({
      light:'amber',
      claim: T('Gas houdt de winterpiek beheersbaar, wel een eindigend pad.',
               'Gas keeps the winter peak manageable, but a finite path.'),
      text:[
        T(`Basis op WP, piek op gasketel. Elektrische piek ${c.demand.piekKw} kW past binnen ${c.aansluitObj.kw} kW.`,
          `WP as base, gas covers peak. Electric peak ${c.demand.piekKw} kW fits within ${c.aansluitObj.kw} kW.`),
        T('Strategie na 2035 in beeld houden, dan wordt aardgas voor utiliteit politiek lastiger. Tussenstap of pad naar gasloos vroeg vastleggen.',
          'Keep the post-2035 strategy in view, fossil gas for utility will be politically harder. Lock in a path to gas-free early.'),
      ],
      route:'oranje-gas',
      toggles:[
        {k:'hybride', l:T('Hybride WP + gas optimaliseren','Optimise hybrid HP + gas'), meta:T('eindigend pad','finite path')},
        {k:'bron', l:T('Bronkeuze bodem onderzoeken','Investigate ground source'), meta:T('verlaagt piek','lowers peak')},
      ],
      conf:[T(`Gas-piek past binnen ${c.aansluitObj.l}`, `Gas peak fits within ${c.aansluitObj.l}`)],
      research:[
        {l:T('Pad naar gasvrij (uiterlijk 2035)','Path to gas-free (by 2035)'), ext:'RVO'},
        {l:T('Hybride WP + ketel engineering','Hybrid HP + boiler engineering'), ext:''},
      ],
    }),
  },
  {
    id: 'en-accu-passend',
    trigger: c => c.ratio > 1 && c.accu.haalbaar && c.accu.robuust && (c.b.eigenOpwek === 'pvBatterij' || c.b.eigenOpwek === 'smartgrid'),
    build: (c, T) => ({
      light:'amber',
      claim: T('Aansluiting krap, accu plus slim laden dekt het tekort.',
               'Connection tight, battery plus smart charging covers the shortfall.'),
      text:[
        T(`Dagtekort ${c.accu.dagTekortKwh} kWh, nachtmarge ${c.accu.nachtOplaadCapKwh} kWh, buffer ${c.accu.margeKwh} kWh. Accu van circa ${c.accu.accuAdviesKwh} kWh dekt meerdaagse kou.`,
          `Day shortfall ${c.accu.dagTekortKwh} kWh, overnight margin ${c.accu.nachtOplaadCapKwh} kWh, buffer ${c.accu.margeKwh} kWh. A battery of about ${c.accu.accuAdviesKwh} kWh covers prolonged cold.`),
        T('Werkt mits BMS en EMS goed staan en de netbeheerder akkoord is met dynamisch laadprofiel.',
          'Works if BMS and EMS are well configured and the grid operator agrees to dynamic charging.'),
      ],
      route:'oranje-accu-passend',
      toggles:[
        {k:'ems', l:T('Energy management system in PvE','Include EMS in brief'), meta:T('verplicht','required')},
        {k:'bms', l:T('Brandveiligheid en BMS-architectuur','Fire safety and BMS architecture'), meta:''},
      ],
      conf:[
        T(`Accu-advies: ~${c.accu.accuAdviesKwh} kWh`, `Battery advice: ~${c.accu.accuAdviesKwh} kWh`),
        T(`Aansluiting ${c.aansluitObj.l} blijft toereikend`, `Connection ${c.aansluitObj.l} remains sufficient`),
      ],
      research:[
        {l:T('Aanbesteden accu + BMS','Procure battery + BMS'), ext:''},
        {l:T('Garantie-cycli en levensduur','Cycle warranty and lifespan'), ext:''},
      ],
    }),
  },
  {
    id: 'en-accu-krap',
    trigger: c => c.ratio > 1 && c.accu.haalbaar && !c.accu.robuust && (c.b.eigenOpwek === 'pvBatterij' || c.b.eigenOpwek === 'smartgrid'),
    build: (c, T) => ({
      light:'amber',
      claim: T('Accu kan net, weinig marge bij meerdaagse vorstperiode.',
               'Battery just suffices, little margin during prolonged frost.'),
      text:[
        T(`Marge ${c.accu.margeKwh} kWh tegenover dagtekort ${c.accu.dagTekortKwh} kWh. Geen 20%-buffer voor uitschieters.`,
          `Margin ${c.accu.margeKwh} kWh against day shortfall ${c.accu.dagTekortKwh} kWh. Less than the 20% safety buffer.`),
        T(`Drie keuzes: accu groter (~${Math.round(c.accu.accuAdviesKwh*1.4)} kWh), ATO-upgrade naar ${c.demand.adviesLabel}, of bronkeuze verlagen.`,
          `Three choices: larger battery (~${Math.round(c.accu.accuAdviesKwh*1.4)} kWh), connection upgrade to ${c.demand.adviesLabel}, or lower source choice.`),
      ],
      route:'oranje-accu-krap',
      toggles:[
        {k:'groter', l:T('Accu groter dimensioneren','Size battery up'), meta:T('+40% capex','+40% capex')},
        {k:'ato', l:T(`ATO-upgrade naar ${c.demand.adviesLabel}`, `Upgrade to ${c.demand.adviesLabel}`), meta:T('lange doorlooptijd','long lead time')},
      ],
      conf:[T(`Beperkt haalbaar met ~${c.accu.accuAdviesKwh} kWh`, `Marginally feasible with ~${c.accu.accuAdviesKwh} kWh`)],
      research:[
        {l:T('Smartgrid + dynamisch profielcontract','Smartgrid + dynamic profile contract'), ext:''},
        {l:T('Doorlooptijd ATO bij netbeheerder','Lead time for connection upgrade'), ext:'Liander capaciteitskaart'},
      ],
    }),
  },
  {
    id: 'en-accu-niet-vol',
    trigger: c => c.ratio > 1 && !c.accu.haalbaar && (c.b.eigenOpwek === 'pvBatterij' || c.b.eigenOpwek === 'smartgrid'),
    build: (c, T) => ({
      light:'red',
      claim: T('Beschikbare aansluiting met accu dekt de winterpiek niet.',
               'Available connection with battery does not cover the winter peak.'),
      text:[
        T(`Dagtekort op koudste dag ${c.accu.dagTekortKwh} kWh, nachtoplaad-capaciteit ${c.accu.nachtOplaadCapKwh} kWh. Marge ${c.accu.margeKwh} kWh (negatief).`,
          `Day shortfall on coldest day ${c.accu.dagTekortKwh} kWh, overnight recharge ${c.accu.nachtOplaadCapKwh} kWh. Margin ${c.accu.margeKwh} kWh (negative).`),
        T(`Drie opties: gas-overbrugging tot ATO-upgrade, zwaardere aansluiting aanvragen (${c.demand.adviesLabel}), of bronkeuze + scope herzien.`,
          `Three options: gas bridge until upgrade, request a heavier connection (${c.demand.adviesLabel}), or revise source and scope.`),
      ],
      route:'rood-accu-niet',
      conf:[],
      research:[
        {l:T(`ATO-aanvraag ${c.demand.adviesLabel}`, `Connection upgrade ${c.demand.adviesLabel}`), ext:'Liander capaciteitskaart'},
        {l:T('Hybride WP + tijdelijk gas','Hybrid HP with temporary gas'), ext:''},
        {l:T('Scope of fasering aanpassen','Adjust scope or phasing'), ext:''},
      ],
    }),
  },

  // -------- BVO-BAND ROUTES (vuistregels voor onderwijs/maatschappelijk) --------
  // Drie banden, elk met realistische opties i.p.v. meteen "rood, upgrade nodig":
  //   ≤ 4.500 m² → 3×80A + accu (~200 kWh)
  //   4.500-6.000 m² → 2× 3×80A + accu, of gas als overbrugging
  //   6.000-10.000 m² → min. 3×200A + accu en/of gas, blokspanning als alternatief
  // Triggert niet voor zorg (24/7-basislast), niet bij zware piekverbruikers,
  // en niet als de gebruiker al pvBatterij/smartgrid heeft gekozen (eigen accu-rules winnen).
  {
    id: 'en-accu-route-80a',
    trigger: c => {
      const tg = c.b.toeslagen || {};
      const zwarePiek = tg.labs || tg.grootkeuken || tg.zwareIct || tg.evZwaar || tg.zwembad;
      const bvo = +c.b.bvo || 0;
      return bvo > 0 && bvo <= 4500
          && c.b.geb !== 'zorg'
          && c.ratio > 1
          && !['pvBatterij','smartgrid'].includes(c.b.eigenOpwek)
          && !zwarePiek;
    },
    build: (c, T) => ({
      light:'amber',
      claim: T('3×80A kan, mits een accu (~200 kWh) en piekafvlakking in scope zitten.',
               '3×80A is feasible if a battery (~200 kWh) and peak shaving are in scope.'),
      text:[
        T(`Berekende piek ${c.demand.piekKw} kW past niet rauw in 3×80A (${c.aansluitObj.kw} kW), maar de feitelijke piek is kort. Een accu van circa 200 kWh + slim EMS (peak shaving + nachtladen) vangt het tekort op.`,
          `Calculated peak ${c.demand.piekKw} kW does not raw-fit a 3×80A connection (${c.aansluitObj.kw} kW), but the real peak is brief. A ~200 kWh battery + smart EMS (peak shaving + overnight charging) covers the shortfall.`),
        T('Vuistregel: tot circa 4.500 m² BVO werkt deze route voor onderwijs en maatschappelijk vastgoed, mits er geen zware piekverbruikers zijn (praktijklokalen, grootkeuken, labs, zwaar EV-laden, zwembad).',
          'Rule of thumb: up to about 4,500 m² GFA this works for education and social real estate, provided no heavy peak loads (practical workshops, commercial kitchen, labs, heavy EV charging, pool).'),
        T('Bijkomend voordeel: blijft binnen kleinverbruik-tarief, geen netcongestie-traject, geen ATO-doorlooptijd.',
          'Bonus: stays within small-user tariff, no congestion track, no upgrade lead time.'),
      ],
      route:'oranje-accu-suggest',
      toggles:[
        {k:'accu', l:T('Accu (~200 kWh) in PvE','Battery (~200 kWh) in brief'), meta:T('peak shaving','peak shaving')},
        {k:'ems', l:T('EMS voor laadprofiel','EMS for load profile'), meta:T('verplicht','required')},
        {k:'check', l:T('Geen zware piekverbruikers verifiëren','Verify no heavy peak loads'), meta:''},
      ],
      conf:[T('Blijft binnen kleinverbruik (3×80A)', 'Stays within small-user (3×80A)')],
      research:[
        {l:T('Dimensionering accu + EMS','Battery + EMS sizing'), ext:''},
        {l:T('TCO 3×80A+accu vs upgrade','TCO 3×80A + battery vs upgrade'), ext:''},
        {l:T('ACM peak-shave standaardprofielen','ACM peak-shave standard profiles'), ext:'ACM prioriteringskader'},
      ],
    }),
  },
  {
    id: 'en-route-4500-6000',
    trigger: c => {
      const tg = c.b.toeslagen || {};
      const zwarePiek = tg.labs || tg.grootkeuken || tg.zwareIct || tg.evZwaar || tg.zwembad;
      const bvo = +c.b.bvo || 0;
      return bvo > 4500 && bvo <= 6000
          && c.b.geb !== 'zorg'
          && !['pvBatterij','smartgrid'].includes(c.b.eigenOpwek)
          && !zwarePiek;
    },
    build: (c, T) => ({
      light:'amber',
      claim: T('4.500-6.000 m²: twee opties zonder dure upgrade — dubbele 3×80A + accu, of gas als overbrugging.',
               '4,500-6,000 m²: two options without expensive upgrade — dual 3×80A + battery, or gas as bridge.'),
      text:[
        T(`Berekende piek ${c.demand.piekKw} kW (${c.demand.piekKva} kVA). Dat past niet in één 3×80A (${c.aansluitObj.kw} kW als je die nu hebt staan), maar wel in de combinaties hieronder.`,
          `Calculated peak ${c.demand.piekKw} kW (${c.demand.piekKva} kVA). Does not fit a single 3×80A (${c.aansluitObj.kw} kW if currently selected), but does fit the combinations below.`),
        T('Optie A — twee aparte 3×80A-aansluitingen + accu (~300-400 kWh). Verdeel de belasting over de twee aansluitingen (bv. installaties op de ene, verlichting + stopcontacten op de andere). Blijft binnen kleinverbruik-tarief, geen ATO-doorlooptijd, geen wachtrij netbeheerder.',
          'Option A — two separate 3×80A connections + battery (~300-400 kWh). Split the load (e.g. HVAC on one, lighting + sockets on the other). Stays within small-user tariff, no upgrade lead time, no grid-operator queue.'),
        T('Optie B — gasaansluiting behouden als winterpiek-overbrugging, met hybride warmtepomp. Geeft tijd tot ATO-upgrade of vervangende techniek; vraagt wel een afbouwplan richting 2035.',
          'Option B — keep gas as winter-peak bridge with a hybrid heat pump. Buys time until upgrade or alternative tech; needs a phase-out plan toward 2035.'),
        T('Optie C — blokspanning* met grotere accu. Vraagt vroeg overleg met de netbeheerder en eigen ruimte voor een trafostation, maar geeft veel capaciteit en betere afspraken over piekvermogen.',
          'Option C — block-voltage connection* with larger battery. Requires early grid-operator coordination and your own substation space, but gives ample capacity and better peak-power terms.'),
      ],
      notes:[
        T('* Blokspanning = een aansluiting op middenspanning (meestal 10 kV) waarbij je een eigen trafostation op je terrein hebt. Je krijgt stroom op een hoger spanningsniveau binnen en transformeert die zelf naar het normale 230/400 V. Voordeel: veel meer vermogen beschikbaar (vanaf ~250 kVA tot enkele MVA) en je kunt vaak betere afspraken maken met de netbeheerder over piekgebruik. Nadeel: je hebt zelf een ruimte (≈3-4 m²) nodig voor het trafohuisje, je bent verantwoordelijk voor het onderhoud ervan, en de aanvraag duurt langer (vroeg starten!).',
          '* Block-voltage (Dutch "blokspanning") = a connection at medium voltage (typically 10 kV) where you have your own substation on site. Power comes in at a higher voltage and you transform it yourself to standard 230/400 V. Pro: much more capacity available (from ~250 kVA up to several MVA) and you can often negotiate better peak-use terms with the grid operator. Con: you need your own room (≈3-4 m²) for the transformer cabin, you maintain it yourself, and the application takes longer (start early!).'),
      ],
      route:'oranje-4500-6000',
      toggles:[
        {k:'dual80', l:T('Dubbele 3×80A onderzoeken','Investigate dual 3×80A'), meta:T('split installaties + verlichting','split HVAC + lighting')},
        {k:'gasbrug', l:T('Gas behouden als overbrugging','Keep gas as bridge'), meta:T('hybride WP','hybrid HP')},
        {k:'blok', l:T('Blokspanning verkennen','Explore block-voltage'), meta:T('vroeg overleg netbeheerder','early grid talks')},
      ],
      conf:[T('Meerdere routes mogelijk zonder direct ATO-upgrade', 'Multiple routes available without immediate upgrade')],
      research:[
        {l:T('Splitsbaarheid belasting (installaties/verlichting)','Load splitability (HVAC/lighting)'), ext:''},
        {l:T('Hybride WP + gas TCO 2026-2035','Hybrid HP + gas TCO 2026-2035'), ext:'RVO'},
        {l:T('Blokspanning: aanvraag + ruimtebeslag trafohuisje','Block-voltage: application + cabin footprint'), ext:'Liander capaciteitskaart'},
      ],
    }),
  },
  {
    id: 'en-route-6000-10000',
    trigger: c => {
      const tg = c.b.toeslagen || {};
      const zwarePiek = tg.labs || tg.grootkeuken || tg.zwareIct || tg.evZwaar || tg.zwembad;
      const bvo = +c.b.bvo || 0;
      return bvo > 6000 && bvo <= 10000
          && c.b.geb !== 'zorg'
          && !['pvBatterij','smartgrid'].includes(c.b.eigenOpwek)
          && !zwarePiek;
    },
    build: (c, T) => ({
      light:'amber',
      claim: T('6.000-10.000 m²: minimaal 3×200A met accu of gas als overbrugging. Blokspanning* is een sterk alternatief.',
               '6,000-10,000 m²: at least 3×200A with battery or gas bridge. Block-voltage* is a strong alternative.'),
      text:[
        T(`Berekende piek ${c.demand.piekKw} kW (${c.demand.piekKva} kVA). Op dit BVO-niveau wordt 3×80A te krap, ook met grote accu. Drie reële routes hieronder.`,
          `Calculated peak ${c.demand.piekKw} kW (${c.demand.piekKva} kVA). At this size, 3×80A becomes too tight even with a large battery. Three realistic routes below.`),
        T(`Optie A — 3×200A (${139} kVA) als grootverbruik-aansluiting, plus accu (~300-500 kWh) voor piekafvlakking. Houdt het paneelvermogen in toom en geeft ruimte voor groei. Doorlooptijd ATO: 6-18 maanden afhankelijk van regio.`,
          `Option A — 3×200A (${139} kVA) large-user connection, plus battery (~300-500 kWh) for peak shaving. Keeps panel power manageable and leaves growth room. Application lead time: 6-18 months by region.`),
        T('Optie B — 3×200A + gas behouden als winterpiek-overbrugging (hybride WP). Verlaagt benodigde accu-capaciteit en geeft tijd tot upgrade of vervolg-fase.',
          'Option B — 3×200A + keep gas as winter-peak bridge (hybrid HP). Lowers required battery capacity and buys time to next phase.'),
        T('Optie C — blokspanning* met eigen trafostation + accu. Hoger startbedrag maar maximale flexibiliteit, vaak betere onderhandeling met netbeheerder over piekvermogen. Begin minimaal 12-18 maanden voor go-live met de aanvraag.',
          'Option C — block-voltage* with own substation + battery. Higher upfront cost but maximum flexibility, often better grid-operator negotiation on peak power. Start the application at least 12-18 months before go-live.'),
      ],
      notes:[
        T('* Blokspanning = een aansluiting op middenspanning (meestal 10 kV) waarbij je een eigen trafostation op je terrein hebt. Je krijgt stroom op een hoger spanningsniveau binnen en transformeert die zelf naar het normale 230/400 V. Voordeel: veel meer vermogen beschikbaar (vanaf ~250 kVA tot enkele MVA) en je kunt vaak betere afspraken maken met de netbeheerder over piekgebruik. Nadeel: je hebt zelf een ruimte (≈3-4 m²) nodig voor het trafohuisje, je bent verantwoordelijk voor het onderhoud ervan, en de aanvraag duurt langer (vroeg starten!).',
          '* Block-voltage (Dutch "blokspanning") = a connection at medium voltage (typically 10 kV) where you have your own substation on site. Power comes in at a higher voltage and you transform it yourself to standard 230/400 V. Pro: much more capacity available (from ~250 kVA up to several MVA) and you can often negotiate better peak-use terms with the grid operator. Con: you need your own room (≈3-4 m²) for the transformer cabin, you maintain it yourself, and the application takes longer (start early!).'),
      ],
      route:'oranje-6000-10000',
      toggles:[
        {k:'ato200', l:T('ATO-aanvraag 3×200A starten','Start 3×200A upgrade application'), meta:T('6-18 mnd','6-18 mo')},
        {k:'gasbrug', l:T('Gas als winter-overbrugging','Gas as winter bridge'), meta:T('hybride WP','hybrid HP')},
        {k:'blok', l:T('Blokspanning + eigen trafo','Block-voltage + own substation'), meta:T('12-18 mnd aanvraag','12-18 mo application')},
        {k:'accu', l:T('Accu 300-500 kWh dimensioneren','Size battery 300-500 kWh'), meta:''},
      ],
      conf:[T('Drie routes beschikbaar, kies op basis van locatie en tijdsdruk', 'Three routes available, choose based on site and timing')],
      research:[
        {l:T('Doorlooptijd ATO 3×200A in regio','Lead time 3×200A upgrade by region'), ext:'Liander capaciteitskaart'},
        {l:T('Hybride WP + gas overbrugging TCO','Hybrid HP + gas bridge TCO'), ext:'RVO'},
        {l:T('Blokspanning: ruimtelijke + technische randvoorwaarden','Block-voltage: spatial + technical requirements'), ext:'Enexis netcapaciteit'},
        {l:T('Accu-dimensionering 300-500 kWh','Battery sizing 300-500 kWh'), ext:''},
      ],
    }),
  },

  // -------- ROOD specifiek en vangnet --------
  {
    id: 'en-zorg-24-7',
    trigger: c => c.b.geb === 'zorg' && c.ratio > 1,
    build: (c, T) => ({
      light:'red',
      claim: T('Zorggebouw met 24/7-belasting. Aansluiting moet de basislast aankunnen.',
               '24/7 healthcare load. Connection must carry the base load.'),
      text:[
        T(`Basislast in zorg is circa 55% van piek, dus continu hoog. Berekende piek ${c.demand.piekKw} kW, beschikbaar ${c.aansluitObj.kw} kW.`,
          `Base load in healthcare is around 55% of peak, continuously high. Calculated peak ${c.demand.piekKw} kW, available ${c.aansluitObj.kw} kW.`),
        T('Een accu lost dit minder goed op dan elders: te weinig nachtmarge om te laden. Bronkeuze (bodem/WKO) verlaagt de piek substantieel.',
          'A battery helps less here: too little overnight margin to recharge. Source choice (ground/WKO) substantially lowers the peak.'),
      ],
      route:'rood-zorg',
      conf:[],
      research:[
        {l:T(`ATO-upgrade naar ${c.demand.adviesLabel}`, `Upgrade connection to ${c.demand.adviesLabel}`), ext:'Liander capaciteitskaart'},
        {l:T('WKO of bodemwarmte ipv lucht-WP','WKO or ground source instead of air'), ext:'RVO'},
        {l:T('ACM-prioriteringskader inroepen (zorg)','Invoke ACM priority framework (healthcare)'), ext:'ACM prioriteringskader'},
      ],
    }),
  },
  {
    id: 'en-cong-wacht',
    trigger: c => c.ratio > 1 && (c.congestie === 'krap' || c.congestie === 'wachtrij'),
    build: (c, T) => ({
      light:'red',
      claim: T('Netcongestie en capaciteitstekort, doorlooptijd loopt op.',
               'Grid congestion plus capacity shortfall, long lead time.'),
      text:[
        T(`Netbeheerder geeft ${c.congestie==='wachtrij'?'wachtrij':'krap aanbod'} aan voor jouw regio. Aanvraag ${c.demand.adviesLabel} duurt 18 tot 36 maanden of langer.`,
          `Grid operator reports ${c.congestie==='wachtrij'?'a waitlist':'tight supply'} in your region. Application for ${c.demand.adviesLabel} takes 18 to 36 months or more.`),
        c.acmPrio
          ? T('Onderwijs en zorg krijgen voorrang vanaf 1 juli 2026. Mogelijk sneller in beeld bij netbeheerder.',
              'Education and healthcare get priority from July 2026. May get faster slot with grid operator.')
          : T('Parallel-spoor: accu, NSA-aansluiting of bronkeuze die de piek halveert.',
              'Parallel track: battery, non-firm connection or source choice that halves the peak.'),
      ],
      route:'rood-cong',
      conf: c.acmPrio ? [T('ACM-prioritering van toepassing','ACM priority applies')] : [],
      research:[
        {l:T('Capaciteitskaart voor exacte status','Check capacity map for exact status'), ext:'Liander capaciteitskaart'},
        {l:T('NSA / non-firm voorwaarden','Non-firm connection terms'), ext:'Enexis netcapaciteit'},
        {l:T('Bodemwarmte of WKO als alternatief','Ground source or WKO as alternative'), ext:'TNO netcongestie maatschappelijk vastgoed'},
      ],
    }),
  },
  {
    id: 'en-overdimensie',
    trigger: c => c.ratio > 2,
    build: (c, T) => ({
      light:'red',
      claim: T('Gevraagde piek is meer dan dubbel zo groot als beschikbare aansluiting.',
               'Required peak is more than double the available connection.'),
      text:[
        T(`Berekende piek ${c.demand.piekKw} kW (${c.demand.piekKva} kVA), beschikbaar ${c.aansluitObj.kw} kW (${c.aansluitObj.kva} kVA). Ratio ${Math.round(c.ratio*100)}%.`,
          `Calculated peak ${c.demand.piekKw} kW (${c.demand.piekKva} kVA), available ${c.aansluitObj.kw} kW (${c.aansluitObj.kva} kVA). Ratio ${Math.round(c.ratio*100)}%.`),
        T(`Met ${c.demand.adviesLabel} (${c.demand.adviesKva} kVA) past het wel. Heroverweeg bron-keuze, BVO-fasering of een lagere all-electric-ambitie.`,
          `${c.demand.adviesLabel} (${c.demand.adviesKva} kVA) would fit. Reconsider heat source, phasing or lower the all-electric ambition.`),
      ],
      route:'rood-overdim',
      conf:[],
      research:[
        {l:T(`ATO-aanvraag voor ${c.demand.adviesLabel} bij netbeheerder`, `Connection upgrade to ${c.demand.adviesLabel} with grid operator`), ext:'Liander capaciteitskaart'},
        {l:T('Bronkeuze opnieuw evalueren (bodem ipv lucht)','Re-evaluate heat source (ground vs air)'), ext:'RVO'},
        {l:T('Fasering programma overwegen','Consider programme phasing'), ext:''},
      ],
    }),
  },

  // -------- ORANJE advies en krap --------
  {
    id: 'en-bron-piek-laag',
    trigger: c => c.b.gas !== 'beh' && c.b.warmteBron === 'lucht' && c.ratio > 0.7,
    build: (c, T) => ({
      light:'amber',
      claim: T('Lucht-WP geeft hoogste winterpiek. Bodembron verlaagt netbeslag.',
               'Air source HP causes the highest winter peak. Ground source lowers grid load.'),
      text:[
        T(`Met lucht-WP zit de piek op ${c.demand.piekKw} kW. Bodem-WP of WKO verlaagt dat naar circa ${Math.round(c.demand.piekKw*0.7)} kW.`,
          `With air HP, peak is ${c.demand.piekKw} kW. Ground HP or WKO lowers this to about ${Math.round(c.demand.piekKw*0.7)} kW.`),
        T('Bodem vraagt vooronderzoek (boringen, vergunning), maar bespaart op de aansluitstap en lange-termijn-energie.',
          'Ground source needs ground survey and permit, but saves on connection step and long-term energy.'),
      ],
      route:'oranje-bron',
      toggles:[
        {k:'bodem', l:T('Bodemgeschiktheidsstudie','Ground suitability study'), meta:T('4-8 weken','4-8 weeks')},
        {k:'wko', l:T('WKO-systeem onderzoeken','Investigate WKO system'), meta:T('groter project','larger project')},
      ],
      conf:[T(`Huidige keuze (lucht) past in ${c.aansluitObj.l}`, `Current choice (air) fits in ${c.aansluitObj.l}`)],
      research:[
        {l:T('Bodemgeschiktheid en SDE++','Ground suitability and SDE++'), ext:'RVO'},
        {l:T('TCO bodem versus lucht','TCO ground vs air'), ext:''},
      ],
    }),
  },
  {
    id: 'en-terug-cong',
    trigger: c => c.b.teruglev === 'ja' && (c.congestie === 'krap' || c.congestie === 'wachtrij'),
    build: (c, T) => ({
      light:'amber',
      claim: T('Terugleveren is moeilijk in congestiegebied.',
               'Feed-in is difficult in a congested area.'),
      text:[
        T('Netbeheerders staan vaak geen onbeperkte teruglevering meer toe. Salderingsregeling vervalt per 1 januari 2027.',
          'Grid operators often no longer allow unlimited feed-in. Net-metering scheme ends 1 January 2027.'),
        T('Beter: accu + eigen verbruik, of nul-op-de-meter ontwerp. PV blijft zinvol, maar reken niet op terugleveren als verdienmodel.',
          'Better: battery + own use, or net-zero design. PV remains useful, but do not bank on feed-in as revenue.'),
      ],
      route:'oranje-terug',
      toggles:[
        {k:'eigen', l:T('PV op eigen verbruik dimensioneren','Size PV to own consumption'), meta:''},
        {k:'accu', l:T('Accu voor opslag overdag','Battery for daytime storage'), meta:''},
      ],
      conf:[],
      research:[
        {l:T('Terug-feed contract bij netbeheerder','Feed-in contract with grid operator'), ext:'Liander capaciteitskaart'},
        {l:T('Salderingsregeling afbouw 2027','Net-metering phase-out 2027'), ext:'RVO'},
      ],
    }),
  },
  {
    id: 'en-krap',
    trigger: c => c.ratio >= 0.8 && c.ratio <= 1,
    build: (c, T) => ({
      light:'amber',
      claim: T('Aansluiting krap maar voldoende. Geen extra capaciteit voor toekomst.',
               'Connection tight but sufficient. No spare capacity for the future.'),
      text:[
        T(`Piek ${c.demand.piekKva} kVA tegenover ${c.aansluitObj.kva} kVA, gebruik ${Math.round(c.ratio*100)}%.`,
          `Peak ${c.demand.piekKva} kVA vs ${c.aansluitObj.kva} kVA, utilisation ${Math.round(c.ratio*100)}%.`),
        T(`Voor klimaatadaptatie, EV-laden of een aanbouw is ${c.demand.adviesLabel} verstandiger. Beslis nu, anders zit je later vast.`,
          `For climate adaptation, EV charging or extensions, ${c.demand.adviesLabel} is wiser. Decide now or get locked in later.`),
      ],
      route:'oranje-krap',
      toggles:[
        {k:'reserve', l:T(`Reservecapaciteit naar ${c.demand.adviesLabel}`, `Reserve capacity to ${c.demand.adviesLabel}`), meta:T('+10-15% capex','+10-15% capex')},
        {k:'ev', l:T('EV-laden slim plannen','Plan EV charging smartly'), meta:''},
      ],
      conf:[T(`Past binnen ${c.aansluitObj.l}`, `Fits within ${c.aansluitObj.l}`)],
      research:[
        {l:T('Reservecapaciteit voor klimaatadaptatie','Spare capacity for climate adaptation'), ext:''},
        {l:T('Laadinfra-strategie EV','EV charging strategy'), ext:'RVO Frisse Scholen'},
      ],
    }),
  },

  // -------- GROEN (passend en proactief) --------
  {
    id: 'en-eigen-opwek-licht',
    trigger: c => (c.b.eigenOpwek === 'pvBatterij' || c.b.eigenOpwek === 'smartgrid') && c.ratio < 0.8,
    build: (c, T) => ({
      light:'green',
      claim: T('PV plus batterij houdt netbeslag laag, ruimte voor groei.',
               'PV plus battery keeps grid load low, room to grow.'),
      text:[
        T(`Piek ${c.demand.piekKva} kVA tegenover ${c.aansluitObj.kva} kVA, gebruik ${Math.round(c.ratio*100)}%.`,
          `Peak ${c.demand.piekKva} kVA vs ${c.aansluitObj.kva} kVA, utilisation ${Math.round(c.ratio*100)}%.`),
        T('Combinatie van opwek en opslag dempt de pieken. Goede positie om toekomstige laadinfra of uitbreiding op te vangen.',
          'Combining generation and storage smooths peaks. Strong base for future charging or expansion.'),
      ],
      route:'groen-opwek',
      conf:[
        T(`Aansluiting ${c.aansluitObj.l} toereikend`, `Connection ${c.aansluitObj.l} sufficient`),
        T('PV en batterij in scope','PV and battery in scope'),
      ],
      research:[
        {l:T('Dimensionering batterij optimaliseren','Optimise battery sizing'), ext:''},
        {l:T('EMS-strategie voor piekafvlakking','EMS strategy for peak shaving'), ext:''},
      ],
    }),
  },
  {
    id: 'en-bron-licht',
    trigger: c => c.b.warmteBron === 'bodem' && c.ratio < 1,
    build: (c, T) => ({
      light:'green',
      claim: T('Bodembron met passende aansluiting. Klaar voor de toekomst.',
               'Ground source with suitable connection. Future-ready.'),
      text:[
        T(`Bodem-WP geeft de laagste winterpiek: ${c.demand.piekKw} kW past in ${c.aansluitObj.kw} kW.`,
          `Ground HP yields the lowest winter peak: ${c.demand.piekKw} kW fits in ${c.aansluitObj.kw} kW.`),
        T('Hogere investering nu, maar lage exploitatie en geen ATO-upgrade nodig op middellange termijn.',
          'Higher capex now, but low operating cost and no upgrade needed in the medium term.'),
      ],
      route:'groen-bron',
      conf:[
        T('Bodembron geselecteerd','Ground source selected'),
        T(`Aansluiting ${c.aansluitObj.l} toereikend`, `Connection ${c.aansluitObj.l} sufficient`),
      ],
      research:[{l:T('Beheer en monitoring WKO','WKO operations and monitoring'), ext:''}],
    }),
  },
  {
    id: 'en-acm-prio',
    trigger: c => c.acmPrio && c.congestie !== 'ruim' && c.ratio < 1,
    build: (c, T) => ({
      light:'green',
      claim: T('Onderwijs en zorg krijgen voorrang bij de netbeheerder vanaf 1 juli 2026.',
               'Education and healthcare get priority with the grid operator from 1 July 2026.'),
      text:[
        T(`Piek ${c.demand.piekKva} kVA past binnen ${c.aansluitObj.kva} kVA. In jouw regio (${c.congestie}) speelt netcongestie wel, maar je gebouwtype krijgt voorrang.`,
          `Peak ${c.demand.piekKva} kVA fits within ${c.aansluitObj.kva} kVA. Your area shows congestion (${c.congestie}), but your building type gets priority.`),
        T('Aanvraag met onderbouwing van maatschappelijke functie versnelt het proces.',
          'Application with social-function justification speeds up the process.'),
      ],
      route:'groen-prio',
      conf:[T('ACM-prioritering van toepassing','ACM priority applies')],
      research:[
        {l:T('Aanvraag met prioritering-onderbouwing','Application with priority justification'), ext:'ACM prioriteringskader'},
      ],
    }),
  },
  {
    id: 'en-passend',
    trigger: c => c.ratio < 0.8,
    build: (c, T) => ({
      light:'green',
      claim: T(`Aansluiting past comfortabel binnen capaciteit, ruimte voor groei.`,
               `Connection fits comfortably within capacity, room to grow.`),
      text:[
        T(`Piek ${c.demand.piekKva} kVA tegenover ${c.aansluitObj.kva} kVA, gebruik ${Math.round(c.ratio*100)}%.`,
          `Peak ${c.demand.piekKva} kVA vs ${c.aansluitObj.kva} kVA, utilisation ${Math.round(c.ratio*100)}%.`),
        T('Goed moment om PV en laadinfra mee te ontwerpen, dat verbreedt het netbeslag niet noemenswaardig.',
          'Good moment to integrate PV and EV charging, this barely widens the grid load.'),
      ],
      route:'groen-passend',
      conf:[
        T(`Aansluiting ${c.aansluitObj.l} ruim voldoende`, `Connection ${c.aansluitObj.l} more than sufficient`),
        T('Geen netcongestie verwacht voor deze omvang','No grid congestion expected for this scale'),
      ],
      research:[{l:T('PV en laadinfra in PvE meenemen','Include PV and EV charging in brief'), ext:''}],
    }),
  },
];



// ============== ACTIE-OPBOUW (kort/midden/lang) ==============
function buildEnergieActies(b, demand, accu, scenarioId, T){
  const kort = [], midden = [], lang = [];

  const congKnap = ['krap','wachtrij'].some(s => scenarioId.includes('cong'));
  const accuPath = scenarioId.includes('accu');
  const broonPath = scenarioId.includes('bron') || b.warmteBron === 'lucht';
  const gasPath = scenarioId.includes('gas') || b.gas === 'beh';

  // Korte termijn (0-6 mnd)
  if(scenarioId.startsWith('rood') || (scenarioId.startsWith('oranje') && scenarioId !== 'oranje-gas')){
    kort.push(T(`GVA-aanvraag starten voor ${demand.adviesLabel}`, `Start GVA application for ${demand.adviesLabel}`));
  }
  if(accuPath){
    kort.push(T('Voorgesprek batterij-leveranciers', 'Pre-talk with battery suppliers'));
  }
  kort.push(T('Energie-blok in PvE definitief maken', 'Finalise energy block in brief'));

  // Middellange termijn (1-3 jr)
  if(broonPath && (scenarioId.includes('bron') || scenarioId.startsWith('rood'))){
    midden.push(T('Bodemgeschiktheid en WKO-vergunning onderzoeken', 'Ground suitability and WKO permit study'));
  }
  if(accuPath){
    midden.push(T('Batterij + BMS engineering en aanbesteding', 'Battery + BMS engineering and procurement'));
  }
  if(b.eigenOpwek === 'geen' || b.eigenOpwek === 'pv'){
    midden.push(T('PV plus batterij scenario doorrekenen', 'Calculate PV plus battery scenario'));
  }

  // Lange termijn (5+ jr)
  if(gasPath){
    lang.push(T('Pad naar gasvrij vastleggen, uiterlijk 2035', 'Define path to gas-free, latest 2035'));
  }
  if(accu && accu.haalbaar === false){
    lang.push(T('ATO-upgrade plannen na netversterking', 'Plan connection upgrade after grid reinforcement'));
  }
  if(congKnap){
    lang.push(T('Herijking aansluitstrategie bij grootschalige uitbreiding', 'Reassess connection strategy at major expansion'));
  }

  return { kort, midden, lang };
}

// ============== ENERGIE BLOK ==============
function blockEnergie(b, lang='nl'){
  const T = (nl, en) => _P(lang, nl, en);
  const demand     = calcDemand(b);
  const aansluitObj= aansluitInfo(b.aansluit);
  const got        = aansluitObj.kva;
  const ratio      = got > 0 ? demand.piekKva / got : 999;
  const profile    = GEBRUIKSPROFIEL[b.geb] || GEBRUIKSPROFIEL.maats;
  const accu       = accuHaalbaarheid(demand.piekKw, aansluitObj.kw, profile);
  const congestie  = congestieVoor(b);
  const acmPrio    = ACM_PRIO_GEBS.indexOf(b.geb) !== -1;
  const ctx = { b, demand, accu, ratio, congestie, acmPrio, aansluitObj };

  let scenario = null;
  for(const s of ENERGIE_SCENARIOS){
    if(s.trigger(ctx)){
      scenario = { id: s.id, ...s.build(ctx, T) };
      break;
    }
  }
  if(!scenario){
    // Fallback: zou niet moeten gebeuren, maar voor robuustheid
    scenario = {
      id:'en-fallback', light:'amber',
      claim: T('Energie-scenario kon niet bepaald worden.','Energy scenario could not be determined.'),
      text:[T('Controleer of alle parameters zijn ingevuld.','Check that all parameters are filled in.')],
      route:'fallback', conf:[], research:[],
    };
  }

  const acties = buildEnergieActies(b, demand, accu, scenario.id, T);

  // Backward-compat velden voor de bestaande UI (TreeEnergie verwacht dem.kva + got)
  return {
    ...scenario,
    dem: { kva: demand.piekKva, kw: demand.piekKw, wPerM2: demand.wPerM2 },
    got,
    demand,
    accu,
    acties,
    congestie,
  };
}


function blockEcologie(b, lang='nl'){
  const T = (nl, en) => _P(lang, nl, en);
  const natRisk = ['gld','utr','nb','ov','fr','dr','zl','gr'].includes(b.provincie);
  const woon = (BUILDING.find(x=>x.v===b.geb)||{}).woon;

  if(b.opgave === 'ren'){
    return {
      light:'green',
      claim: T('Renovatie binnen het bestaande gebouw, beperkt ecologisch risico.',
               'Renovation inside the existing building, limited ecological risk.'),
      text:[
        T('Binnen-renovatie raakt natuur­vergunning meestal niet. Stikstof­depositie tijdens werkzaamheden blijft binnen marges van bestaand gebruik.',
          'Interior renovation usually leaves the nature permit untouched. Nitrogen deposition during works stays within existing-use margins.'),
        T('Wel een quickscan flora & fauna voor vleermuizen en gierzwaluwen onder dakranden, verplicht bij elke ingreep aan de schil.',
          'A flora & fauna quick scan is still required for bats and swifts under the eaves, mandatory for any envelope work.'),
      ],
      route:'a-quick',
      conf:[
        T('Geen Wet natuurbescherming-traject','No Nature Conservation Act track'),
        T('Quickscan flora/fauna volstaat','Flora/fauna quick scan suffices'),
      ],
      research:[{l:T('Quickscan ecologie inplannen','Schedule ecology quick scan'), ext:''}],
    };
  }
  if(natRisk && (b.opgave==='sln'||b.opgave==='nb') && +b.bvo>5000){
    return {
      light:'amber',
      claim: T('Mogelijke stikstof­depositie op nabijgelegen Natura 2000.',
               'Possible nitrogen deposition on nearby Natura 2000.'),
      text:[
        T('Provincie kent gevoelige natuur­gebieden. Bij nieuwbouw of sloop+nieuwbouw boven 2.500 m² is een AERIUS-berekening voor zowel realisatie­fase als gebruiks­fase nodig.',
          'The province has sensitive nature areas. For new build or demolish+new build above 2,500 m², an AERIUS calculation for both construction and operation phase is needed.'),
        T('Bouw­methode wordt sturend: emissieloos bouwen of intern salderen zijn beproefde routes.',
          'Construction method becomes decisive: emission-free construction or internal balancing are proven routes.'),
      ],
      route:'b-aerius',
      conf:[T('Quickscan flora/fauna verplicht','Flora/fauna quick scan required')],
      research:[
        {l:T('AERIUS-berekening realisatie­fase','AERIUS calculation construction phase'), ext:'AERIUS'},
        {l:T('Emissieloos materieel toets','Emission-free equipment check'),  ext:''},
        {l:T('Intern salderen onderzoek','Internal balancing study'),     ext:''},
      ],
    };
  }
  return {
    light:'green',
    claim: T('Geen Natura 2000 in directe nabijheid, standaard scan volstaat.',
             'No Natura 2000 in the immediate vicinity, standard scan suffices.'),
    text:[
      T('Op gepaste afstand van stikstof­gevoelige natuur. Toch verplicht: een quickscan flora & fauna inclusief beschermd­e soorten check.',
        'At a comfortable distance from nitrogen-sensitive nature. Still required: a flora & fauna quick scan including protected species check.'),
      woon
        ? T('Bij wonen extra aandacht voor gierzwaluw- en huismus­voorzieningen in de gevel.',
            'For housing, pay extra attention to swift and house-sparrow features in the facade.')
        : T('Voor utiliteit met grote daken: bekijk integratie van soort­voorzieningen in dak­randen.',
            'For non-residential buildings with large roofs: consider integrating species features in roof edges.'),
    ],
    route:'a-quick',
    conf:[
      T('Geen N2000-traject','No Natura 2000 track'),
      T('Quickscan flora/fauna','Flora/fauna quick scan'),
    ],
    research:[{l:T('Soort­specifieke voorzieningen ontwerp','Species-specific features in design'), ext:''}],
  };
}

function blockStico(b, lang='nl'){
  const T = (nl, en) => _P(lang, nl, en);
  const build = BUILDING.find(x=>x.v===b.geb) || BUILDING[0];
  const vng = build.vng;
  const m2 = +b.bvo || 0;
  const marktLow  = vng * 1.05;
  const marktHigh = vng * 1.30;
  if(m2 === 0){
    return {light:'green', claim:T('Voer BVO in om stichtings­kosten richting te zien.','Enter GFA to see project-cost direction.'), text:[''], route:'a-binnen', conf:[], research:[]};
  }
  const allElec = b.gas==='gn'||b.gas==='uit';
  const upcharge = (b.opgave==='sln' ? 0.08 : 0) + (allElec? 0.06 : 0);
  const norm = vng;
  const realLow  = Math.round(marktLow * (1+upcharge));
  const realHigh = Math.round(marktHigh * (1+upcharge));
  const overshoot = realLow / norm;
  const fmt = (n) => lang==='en' ? n.toLocaleString('en-GB') : n.toLocaleString('nl-NL');
  const buildLbl = (window.COPY_VD?.[lang]?.building?.[build.v]) || build.l;

  if(overshoot > 1.20){
    return {
      light:'red',
      claim: T(`VNG-norm dekt naar verwachting niet meer dan ${Math.round(norm/realLow*100)}% van de marktprijs.`,
               `The VNG norm is expected to cover no more than ${Math.round(norm/realLow*100)}% of the market price.`),
      text:[
        T(`VNG-richt­bedrag ${buildLbl.toLowerCase()}: €${fmt(vng)}/m². Markt-bandbreedte voor jouw scenario: €${fmt(realLow)}-€${fmt(realHigh)}/m².`,
          `VNG indicative budget ${buildLbl.toLowerCase()}: €${fmt(vng)}/m². Market range for your scenario: €${fmt(realLow)}-€${fmt(realHigh)}/m².`),
        T('Een herijking van het krediet of een gefaseerde aanbesteding zijn de twee gangbare uitwegen. Geen herijking betekent ontwerpen op een norm die markt niet meer levert.',
          'Recalibrating the budget or phased procurement are the two common ways out. No recalibration means designing to a norm the market no longer delivers.'),
      ],
      route:'red',
      conf:[T(`VNG-norm: €${fmt(vng)}/m²`, `VNG norm: €${fmt(vng)}/m²`)],
      research:[
        {l:T('Markt-prijspeil­onderzoek (BDB-index, AVB)','Market price index study (BDB, AVB)'), ext:''},
        {l:T('Herijkings-traject met bestuur','Recalibration track with the board'), ext:''},
        {l:T('Bouwteam met open begroting','Bouwteam with open-book budget'), ext:''},
      ],
    };
  }
  if(overshoot > 1.05){
    return {
      light:'amber',
      claim: T('VNG-norm dekt krap, kompas wijst naar herijking of scope-keuzes.',
               'VNG norm only just covers, the compass points to recalibration or scope choices.'),
      text:[
        T(`VNG-richt­bedrag €${fmt(vng)}/m². Markt-bandbreedte €${fmt(realLow)}-€${fmt(realHigh)}/m². Krap binnen marge.`,
          `VNG indicative budget €${fmt(vng)}/m². Market range €${fmt(realLow)}-€${fmt(realHigh)}/m². Tight margin.`),
        T('Twee paden: scope-keuzes maken (functioneel programma trimmen) óf vroege markt­consultatie om bandbreedte aan te scherpen voor herijking.',
          'Two paths: scope choices (trim the functional brief) or early market consultation to sharpen the range before recalibration.'),
      ],
      route:'amber',
      conf:[
        T(`VNG-norm: €${fmt(vng)}/m²`, `VNG norm: €${fmt(vng)}/m²`),
        T(`Indicatief: €${fmt(realLow)}/m² ondergrens markt`, `Indicative: €${fmt(realLow)}/m² market low`),
      ],
      research:[
        {l:T('Marktconsultatie 2-3 aannemers','Market consultation with 2-3 contractors'), ext:''},
        {l:T('PvE op functionele specs','Brief based on functional specs'), ext:''},
      ],
    };
  }
  return {
    light:'green',
    claim: T('VNG-norm dekt het scenario binnen markt-bandbreedte.',
             'VNG norm covers the scenario within the market range.'),
    text:[
      T(`VNG-richt­bedrag €${fmt(vng)}/m². Markt-bandbreedte €${fmt(realLow)}-€${fmt(realHigh)}/m². Past binnen marge.`,
        `VNG indicative budget €${fmt(vng)}/m². Market range €${fmt(realLow)}-€${fmt(realHigh)}/m². Within margin.`),
    ],
    route:'green',
    conf:[T(`VNG-norm: €${fmt(vng)}/m²`, `VNG norm: €${fmt(vng)}/m²`)],
    research:[{l:T('Eventuele optimalisatie bouwteam','Optional bouwteam optimisation'), ext:''}],
  };
}

// === DEFAULTS, voorbeeld scenario uit spec ===
const DEFAULTS = {
  provincie:'gld', subregio:'oost', geb:'ikc',
  opgave:'sln', gas:'uit',
  bvo:3000, eenheden:0,
  aansluit:'80',
  teruglev:'nee',
  eigenOpwek:'geen',         // 'geen' | 'pv' | 'pvBatterij' | 'smartgrid'
  warmteBron:'lucht',         // 'lucht' | 'bodem' | 'stads' | 'geen'
  toeslagen:{},               // booleans: grootkeuken, pantry, zwareIct, labs, evLicht, evZwaar, douches, zwembad
  cosPhi:0.85,                // BINX-praktijk
};

Object.assign(window, {
  PROVINCIES, BUILDING, OPGAVES, GAS, AANSLUIT, TERUGLEV, TIPS,
  W_BASELINE_E, W_BOUNDS_E, BRON_W, OPWEK_W, TOESLAG_W,
  GEBRUIKSPROFIEL, CONGESTIE_NL, ACM_PRIO_GEBS,
  ENERGIE_SCENARIOS,
  calcDemand, aansluitInfo, accuHaalbaarheid, congestieVoor, buildEnergieActies,
  blockRO, blockEnergie, blockEcologie, blockStico,
  VD_DEFAULTS: DEFAULTS,
});
