// ============================================================
// PaperZmena — návrh na zmenu rozhodnutia o úprave výkonu rodičovských
// práv a povinností k maloletému dieťaťu (§ 26 a nasl. zákona
// č. 36/2005 Z. z. o rodine).
// ============================================================

// SUDY — zoznam okresných a mestských súdov SR je definovaný v components/sudy.js
// a vystavený ako window.SUDY.

const removeDiacritics = (str) => str.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase();

// ============================================================
// Gender helpers — prechyľovanie procesných označení (§ 60 a nasl. CSP)
// a rodinnoprávnych označení podľa pohlavia. Pohlavie odporcu odvodzujeme
// ako opak navrhovateľa (rodičia maloletého dieťaťa) — len jediný vstup
// pre celý dokument.
// ============================================================
const POHLAVIE_FORMS = {
  navrhovatel: {
    muz:  { nom: 'navrhovateľ',   gen: 'navrhovateľa',  dat: 'navrhovateľovi', ak: 'navrhovateľa',  lok: 'navrhovateľovi', instr: 'navrhovateľom' },
    zena: { nom: 'navrhovateľka', gen: 'navrhovateľky', dat: 'navrhovateľke',  ak: 'navrhovateľku', lok: 'navrhovateľke',  instr: 'navrhovateľkou' },
  },
  odporca: {
    muz:  { nom: 'odporca',   gen: 'odporcu',   dat: 'odporcovi', ak: 'odporcu',   lok: 'odporcovi', instr: 'odporcom' },
    zena: { nom: 'odporkyňa', gen: 'odporkyne', dat: 'odporkyni', ak: 'odporkyňu', lok: 'odporkyni', instr: 'odporkyňou' },
  },
};
const oznacenie = (rola, pohlavie, pad = 'nom') => POHLAVIE_FORMS[rola][pohlavie][pad];
const oznacenieCap = (rola, pohlavie, pad = 'nom') => {
  const s = oznacenie(rola, pohlavie, pad);
  return s.charAt(0).toUpperCase() + s.slice(1);
};

// Sloveso v minulom čase, 1. osoba sg. — zaklad = mužský tvar (uzavrel,
// oznámil, uvedomil...), pre ženu pridáme '-a'. Pokrýva všetky pravidelné
// slovenské slovesá — slovenský minulý čas je v tomto symetrický.
const slovesoMinuly = (zaklad, pohlavie) => pohlavie === 'zena' ? zaklad + 'a' : zaklad;

// Privlastňovacie zámeno 3. osoby sg. — "jeho" / "jej".
const privlastn = (pohlavie) => pohlavie === 'muz' ? 'jeho' : 'jej';

// Rodinnoprávne role v singulári (otec/matka) — používané v opisoch
// striedavej starostlivosti a styku, kde právny jazyk pracuje s rodičovskými
// rolami a nie s procesnými označeniami. Mapping: muž ako navrhovateľ → otec,
// žena ako navrhovateľka → matka. Pohlavie odporcu = opak.
const ROLA_RODICA_FORMS = {
  otec:  { nom: 'otec',  gen: 'otca',  dat: 'otcovi', ak: 'otca',  lok: 'otcovi', instr: 'otcom' },
  matka: { nom: 'matka', gen: 'matky', dat: 'matke',  ak: 'matku', lok: 'matke',  instr: 'matkou' },
};
const rolaRodicaKey = (role, navrhovatelPohlavie) => {
  if (role === 'navrhovatel') return navrhovatelPohlavie === 'muz' ? 'otec' : 'matka';
  return navrhovatelPohlavie === 'muz' ? 'matka' : 'otec';
};
const rolaRodica = (role, navrhovatelPohlavie, pad = 'nom') =>
  ROLA_RODICA_FORMS[rolaRodicaKey(role, navrhovatelPohlavie)][pad];
const rolaRodicaCap = (role, navrhovatelPohlavie, pad = 'nom') => {
  const s = rolaRodica(role, navrhovatelPohlavie, pad);
  return s.charAt(0).toUpperCase() + s.slice(1);
};
// Tvar v páde priamo z key (matka/otec) — bez navrhovatelPohlavie.
const rolaRodicaPad = (key, pad = 'nom') => ROLA_RODICA_FORMS[key][pad];

// Sloveso "oprávnený/-á" pre rodičovskú rolu — gender-aware koncovka.
const rolaOpravneny = (role, navrhovatelPohlavie) =>
  rolaRodicaKey(role, navrhovatelPohlavie) === 'matka' ? 'oprávnená' : 'oprávnený';

// Singulár/plurál pre "maloleté dieťa" / "maloleté deti" so všetkými pádmi.
// Pre 0 detí používame plurál (rendrovať placeholder hint riešia callsite).
const DETI_SLOVO_FORMS = {
  sg: { nom: 'maloleté dieťa', gen: 'maloletého dieťaťa', dat: 'maloletému dieťaťu', ak: 'maloleté dieťa', lok: 'maloletom dieťati', instr: 'maloletým dieťaťom' },
  pl: { nom: 'maloleté deti',  gen: 'maloletých detí',    dat: 'maloletým deťom',    ak: 'maloleté deti',  lok: 'maloletých deťoch', instr: 'maloletými deťmi' },
};
const detiSlovo = (pocet, pad = 'nom') =>
  DETI_SLOVO_FORMS[pocet === 1 ? 'sg' : 'pl'][pad];

// Sloveso "byť" v 3. osobe budúceho času — "bude" (sg) / "budú" (pl).
// Používané pred detiSlovo v sampleStriedavka_* textoch (subjekt = dieťa/deti).
const bude = (pocet) => pocet === 1 ? 'bude' : 'budú';

// Sloveso "byť" v 3. osobe minulého času — "bolo" (sg neutrum) / "boli" (pl).
// Použité v sampleSpolocna pre konštrukciu "aby bolo/boli ... zverené".
const bolo = (pocet) => pocet === 1 ? 'bolo' : 'boli';

// Heuristika pohlavia z priezviska. Posledný token, prípony typické pre
// slovenské feminíny (-ová, -cká, -ská, -ná, -tá, -lá), fallback -á.
// Známe edge cases: "Eva", "Andrea", "Smola", "Procházka" (bez diakritiky)
// → muz fallback. Cudzojazyčné mená môžu byť mimo vzoru.
const FEM_NAME_RE = /(?:ová|cká|ská|ná|tá|lá|á)$/i;
const detectGenderFromName = (fullName) => {
  if (!fullName) return null;
  const tokens = fullName.trim().split(/\s+/);
  if (!tokens.length || !tokens[tokens.length - 1]) return null;
  const last = tokens[tokens.length - 1].normalize('NFC');
  return FEM_NAME_RE.test(last) ? 'zena' : 'muz';
};

// Formát dátumu narodenia v štýle d.m.rrrr (bez vodiacich núl, napr. 5.5.2013).
// Vstup môže byť "DD. MM. RRRR", "DD.MM.RRRR", "D.M.RRRR" a podobné varianty.
// Ak sa nedá parsnúť, vráti pôvodný string (trimmed).
const formatDatumDmRRRR = (s) => {
  const m = String(s || '').match(/(\d{1,2})\s*\.\s*(\d{1,2})\s*\.\s*(\d{4})/);
  if (!m) return String(s || '').trim();
  return `${parseInt(m[1], 10)}.${parseInt(m[2], 10)}.${m[3]}`;
};

// ============================================================
// Sample texty pre Čl. III — maloleté dieťa a úprava výkonu
// rodičovských práv. Gender-aware varianty (pNav).
// ============================================================
const SAMPLE_311_M = 'Narodenie nášho prvého dieťaťa bolo pre mňa jednou z najkrajších udalostí v živote. Spolu s druhým rodičom sme sa intenzívne pripravovali na rodičovstvo. Od narodenia detí som sa aktívne zapájal do starostlivosti — vstával som k nim v noci, kúpal ich, kŕmil, neskôr som ich vodil do škôlky a venoval sa im pri voľnočasových aktivitách. Vzťah s deťmi je vrelý a otvorený, deti mi dôverujú a rád trávim s nimi čas. V súčasnosti sa o deti staráme spoločne — ja zabezpečujem ranné vstávanie a odvoz do školy, popoludní sa s nimi venujem úlohám a krúžkom, druhý rodič má na starosti zdravotné prehliadky a komunikáciu so školou. Deti sú zdravé, šťastné a v škole úspešné.';

const SAMPLE_311_Z = 'Narodenie nášho prvého dieťaťa bolo pre mňa jednou z najkrajších udalostí v živote. Spolu s druhým rodičom sme sa intenzívne pripravovali na rodičovstvo. Od narodenia detí som sa aktívne starala o ich potreby — dojčila som, vstávala k nim v noci, sprevádzala ich pri prvých krokoch a slovách, neskôr ich vodila do škôlky a venovala sa im pri voľnočasových aktivitách. Vzťah s deťmi je vrelý a otvorený, deti mi dôverujú a vyhľadávajú moju spoločnosť. V súčasnosti zabezpečujem každodennú starostlivosť — ranné vstávanie, odvozy do školy a krúžkov, prípravu jedla, kontrolu úloh, zdravotné prehliadky a komunikáciu so školou. Deti sú zdravé, šťastné a v škole úspešné.';

const SAMPLE_312_M = 'Z pozitívnych skúseností uvádzam, že druhý rodič sa o deti dlhodobo staral s láskou — najmä v období ich raného detstva, keď bol/-a na materskej alebo rodičovskej dovolenke. Ja som sa v tom čase venoval zabezpečeniu rodiny. Postupom času sa však naša spolupráca v starostlivosti o deti zhoršila. Druhý rodič začal/-a v prítomnosti detí kritizovať moju osobu, napríklad pri jednej z hádok v máji 2024 pred deťmi povedal/-a: ,Otec sa o vás nikdy poriadne nestaral.\' Považujem za dôležité uviesť, že [opíšte konkrétne príklady, ktoré chcete uviesť]. Tieto situácie negatívne pôsobia na duševný stav detí a obmedzujú môj vzťah s nimi.';

const SAMPLE_312_Z = 'Z pozitívnych skúseností uvádzam, že druhý rodič sa do narodenia mladšieho dieťaťa zapájal do starostlivosti aktívnejšie — chodil s nami na prechádzky, hral sa s deťmi cez víkendy. Postupom času sa však jeho zapojenie znížilo. Najmä v posledných dvoch rokoch som ostala s každodennou starostlivosťou prakticky sama. Druhý rodič pri jednej z hádok v máji 2024 pred deťmi povedal: ,Aj tak si robíš, čo chceš.\' Považujem za dôležité uviesť, že [opíšte konkrétne príklady, ktoré chcete uviesť]. Tieto situácie negatívne pôsobia na duševný stav detí.';

// 3.2 — dva smery: A = zverenie sebe, B = zverenie druhému rodičovi.
const SAMPLE_32_A_M = 'Vzhľadom na doterajší priebeh starostlivosti a vzťah, ktorý mám s deťmi, navrhujem, aby boli maloleté deti zverené do mojej osobnej starostlivosti. Som schopný a ochotný zabezpečiť všetky ich potreby — bývanie, výživu, oblečenie, vzdelanie aj voľnočasové aktivity. S druhým rodičom som ochotný komunikovať vo veciach týkajúcich sa detí a podporujem ich pravidelný styk s ním/ňou. Verím, že takéto usporiadanie je v najlepšom záujme detí.';

const SAMPLE_32_A_Z = 'Vzhľadom na doterajší priebeh starostlivosti a vzťah, ktorý mám s deťmi, navrhujem, aby boli maloleté deti zverené do mojej osobnej starostlivosti. Som schopná a ochotná zabezpečiť všetky ich potreby — bývanie, výživu, oblečenie, vzdelanie aj voľnočasové aktivity. S druhým rodičom som ochotná komunikovať vo veciach týkajúcich sa detí a podporujem ich pravidelný styk s ním/ňou. Verím, že takéto usporiadanie je v najlepšom záujme detí.';

const SAMPLE_32_B_M = 'Po dôkladnom zvážení doterajšieho priebehu starostlivosti, životnej situácie oboch rodičov a najmä najlepšieho záujmu detí, navrhujem, aby boli maloleté deti zverené do osobnej starostlivosti druhého rodiča. Som pripravený plniť si vyživovaciu povinnosť a aktívne sa stýkať s deťmi tak, aby bol zachovaný môj vrelý vzťah s nimi. Považujem za dôležité, aby deti mali stabilné prostredie a aby ich každodenné fungovanie nebolo narušené.';

const SAMPLE_32_B_Z = 'Po dôkladnom zvážení doterajšieho priebehu starostlivosti, životnej situácie oboch rodičov a najmä najlepšieho záujmu detí, navrhujem, aby boli maloleté deti zverené do osobnej starostlivosti druhého rodiča. Som pripravená plniť si vyživovaciu povinnosť a aktívne sa stýkať s deťmi tak, aby bol zachovaný môj vrelý vzťah s nimi. Považujem za dôležité, aby deti mali stabilné prostredie a aby ich každodenné fungovanie nebolo narušené.';

// ============================================================
// 3.3(b) — Striedavá osobná starostlivosť, vzorové texty (4 sekcie).
// Plurál-aware cez detiSlovo(pCount, pad). Symetrické (otec/matka),
// nezávisí na pohlaví navrhovateľa — stačí pCount.
// ============================================================
const sampleStriedavka_BeznyCyklus = (pCount) =>
  `S výnimkou osobitnej úpravy počas letných, zimných a veľkonočných prázdnin ${bude(pCount)} ${detiSlovo(pCount, 'nom')} v osobnej starostlivosti matky každý párny kalendárny týždeň od pondelka od 8:00 hod. do nasledujúceho pondelka nepárneho kalendárneho týždňa do 8:00 hod. a v osobnej starostlivosti otca každý nepárny kalendárny týždeň od pondelka od 8:00 hod. do nasledujúceho pondelka párneho kalendárneho týždňa do 8:00 hod.`;

const sampleStriedavka_LetnePrazdniny = (pCount) =>
  `Počas letných prázdnin ${bude(pCount)} ${detiSlovo(pCount, 'nom')} v osobnej starostlivosti matky v každom kalendárnom roku vždy od 15. 7. od 19:00 hod. do 1. 8. do 9:00 hod. a od 15. 8. od 19:00 hod. do 31. 8. do 19:00 hod. V osobnej starostlivosti otca ${bude(pCount)} ${detiSlovo(pCount, 'nom')} v každom kalendárnom roku vždy od 1. 7. od 9:00 hod. do 15. 7. do 19:00 hod. a od 1. 8. od 9:00 hod. do 15. 8. do 19:00 hod.`;

const sampleStriedavka_ZimnePrazdniny = (pCount) =>
  `Počas zimných prázdnin ${bude(pCount)} ${detiSlovo(pCount, 'nom')} v nepárnom kalendárnom roku v osobnej starostlivosti otca od 24. 12. od 16:00 hod. do 25. 12. do 18:00 hod., matky od 25. 12. od 18:00 hod. do 1. 1. nasledujúceho párneho roka do 10:00 hod., otca od 1. 1. párneho roka od 10:00 hod. do 6. 1. do 18:00 hod. V párnom kalendárnom roku ${bude(pCount)} ${detiSlovo(pCount, 'nom')} v osobnej starostlivosti matky od 24. 12. od 16:00 hod. do 25. 12. do 18:00 hod., otca od 25. 12. od 18:00 hod. do 1. 1. nasledujúceho nepárneho roka do 10:00 hod., matky od 1. 1. nepárneho roka od 10:00 hod. do 6. 1. do 18:00 hod.`;

const sampleStriedavka_VelkonocnePrazdniny = (pCount) =>
  `Počas veľkonočných prázdnin ${bude(pCount)} ${detiSlovo(pCount, 'nom')} v osobnej starostlivosti matky každý párny kalendárny rok od Zeleného štvrtka od 10:00 hod. do Veľkonočného pondelka do 14:00 hod. a v osobnej starostlivosti otca každý nepárny kalendárny rok od Zeleného štvrtka od 10:00 hod. do Veľkonočného pondelka do 14:00 hod.`;

// Záverečná veta o miestach prevzatia/odovzdania — spoločná pre striedavku
// (3.3 b) aj styk (3.5). Singulár/plurál cez detiSlovo + zhodný tvar.
const sampleVetaOdovzdanie = (pCount) =>
  `Miestom prevzatia a odovzdania ${detiSlovo(pCount, 'gen')} bude predškolské alebo školské zariadenie, ktoré ${pCount === 1 ? 'maloletý navštevuje' : 'maloletí navštevujú'}, a v čase ${pCount === 1 ? 'jeho' : 'ich'} neprítomnosti v tomto zariadení bydlisko odovzdávajúceho rodiča.`;

// 3.3(c) — spoločná osobná starostlivosť, sample text pre Ed block.
// Plural-aware cez detiSlovo + bolo/boli zhoda slovesa byť s podmetom.
const sampleSpolocna = (pCount) =>
  `Navrhujem, aby ${bolo(pCount)} ${detiSlovo(pCount, 'nom')} zverené do spoločnej osobnej starostlivosti oboch rodičov podľa § 24 ods. 2 zákona č. 36/2005 Z. z. o rodine. Vieme sa dohodnúť a komunikovať vo veciach výchovy ${detiSlovo(pCount, 'gen')}.`;

// Bežný cyklus pre "vlastné" striedanie — placeholder na vyplnenie užívateľom.
const SAMPLE_STRIEDAVKA_BEZNY_VLASTNE = '[Vyplňte vlastný režim striedania - pozor režim musí byť napísaný tak, aby bol vykonateľný.]';

// Spojený text všetkých 4 sekcií 3.3(b) + záverečná veta o odovzdaní —
// vkladá sa do Ed bloku po kliknutí "Použiť tento text". BEZ sub-headings:
// holé odseky oddelené prázdnym riadkom (Ed.block má white-space: pre-wrap,
// takže \n\n sa rendrujú ako vizuálne odsadenie odsekov).
const sample33bJoined = (typ, pCount) => {
  const bezny = typ === 'vlastne'
    ? SAMPLE_STRIEDAVKA_BEZNY_VLASTNE
    : sampleStriedavka_BeznyCyklus(pCount);
  return [
    bezny,
    sampleStriedavka_LetnePrazdniny(pCount),
    sampleStriedavka_ZimnePrazdniny(pCount),
    sampleStriedavka_VelkonocnePrazdniny(pCount),
    sampleVetaOdovzdanie(pCount),
  ].join('\n\n');
};

// ============================================================
// 3.5 — Vzor styku rodiča, ktorému deti neboli zverené (4 sekcie).
// nezverenyKey = 'otec' | 'matka'.
// ============================================================
const sampleStyk_BeznyStyk = (nezverenyKey, pCount) => {
  const opravneny = nezverenyKey === 'matka' ? 'oprávnená' : 'oprávnený';
  const rolaCap = nezverenyKey === 'matka' ? 'Matka' : 'Otec';
  return `${rolaCap} je ${opravneny} stýkať sa s ${detiSlovo(pCount, 'instr')} každý párny kalendárny týždeň od piatka od 16:00 hod. do nedele do 19:00 hod. a každý kalendárny týždeň v utorok od 15:00 hod. do 19:00 hod.`;
};

const sampleStyk_LetnePrazdniny = (nezverenyKey, pCount) => {
  const opravneny = nezverenyKey === 'matka' ? 'oprávnená' : 'oprávnený';
  const rolaCap = nezverenyKey === 'matka' ? 'Matka' : 'Otec';
  if (nezverenyKey === 'otec') {
    return `${rolaCap} je ${opravneny} stýkať sa s ${detiSlovo(pCount, 'instr')} v každom kalendárnom roku vždy od 1. 7. od 9:00 hod. do 15. 7. do 19:00 hod. a od 1. 8. od 9:00 hod. do 15. 8. do 19:00 hod.`;
  }
  return `${rolaCap} je ${opravneny} stýkať sa s ${detiSlovo(pCount, 'instr')} v každom kalendárnom roku vždy od 15. 7. od 19:00 hod. do 1. 8. do 9:00 hod. a od 15. 8. od 19:00 hod. do 31. 8. do 19:00 hod.`;
};

const sampleStyk_ZimnePrazdniny = (nezverenyKey, pCount) => {
  const opravneny = nezverenyKey === 'matka' ? 'oprávnená' : 'oprávnený';
  const rolaCap = nezverenyKey === 'matka' ? 'Matka' : 'Otec';
  if (nezverenyKey === 'otec') {
    return `${rolaCap} je ${opravneny} stýkať sa s ${detiSlovo(pCount, 'instr')} v nepárnom kalendárnom roku od 24. 12. od 16:00 hod. do 25. 12. do 18:00 hod. a od 1. 1. párneho roka od 10:00 hod. do 6. 1. do 18:00 hod. V párnom kalendárnom roku od 25. 12. od 18:00 hod. do 1. 1. nasledujúceho nepárneho roka do 10:00 hod.`;
  }
  return `${rolaCap} je ${opravneny} stýkať sa s ${detiSlovo(pCount, 'instr')} v nepárnom kalendárnom roku od 25. 12. od 18:00 hod. do 1. 1. nasledujúceho párneho roka do 10:00 hod. V párnom kalendárnom roku od 24. 12. od 16:00 hod. do 25. 12. do 18:00 hod. a od 1. 1. nepárneho roka od 10:00 hod. do 6. 1. do 18:00 hod.`;
};

const sampleStyk_VelkonocnePrazdniny = (nezverenyKey, pCount) => {
  const opravneny = nezverenyKey === 'matka' ? 'oprávnená' : 'oprávnený';
  const rolaCap = nezverenyKey === 'matka' ? 'Matka' : 'Otec';
  const parityWord = nezverenyKey === 'matka' ? 'párny' : 'nepárny';
  return `${rolaCap} je ${opravneny} stýkať sa s ${detiSlovo(pCount, 'instr')} každý ${parityWord} kalendárny rok od Zeleného štvrtka od 10:00 hod. do Veľkonočného pondelka do 14:00 hod.`;
};

// Spojený text všetkých 4 sekcií 3.5 styku + záverečná veta o odovzdaní —
// vkladá sa do Ed bloku po kliknutí "Použiť tento text". BEZ sub-headings.
const sampleStyk_Joined = (nezverenyKey, pCount) => [
  sampleStyk_BeznyStyk(nezverenyKey, pCount),
  sampleStyk_LetnePrazdniny(nezverenyKey, pCount),
  sampleStyk_ZimnePrazdniny(nezverenyKey, pCount),
  sampleStyk_VelkonocnePrazdniny(nezverenyKey, pCount),
  sampleVetaOdovzdanie(pCount),
].join('\n\n');

// Singulárové varianty pre 1 dieťa — gramatický stredný rod ("dieťa")
// + zámená "ho/mu/ním", neutrálne pre nepoznané pohlavie dieťaťa.
const SAMPLE_311_M_SG = 'Narodenie nášho dieťaťa bolo pre mňa jednou z najkrajších udalostí v živote. Spolu s druhým rodičom sme sa intenzívne pripravovali na rodičovstvo. Od narodenia dieťaťa som sa aktívne zapájal do starostlivosti — vstával som k nemu v noci, kúpal ho, kŕmil, neskôr som ho vodil do škôlky a venoval sa mu pri voľnočasových aktivitách. Vzťah s dieťaťom je vrelý a otvorený, dieťa mi dôveruje a rád trávim s ním čas. V súčasnosti sa o dieťa staráme spoločne — ja zabezpečujem ranné vstávanie a odvoz do školy, popoludní sa s ním venujem úlohám a krúžkom, druhý rodič má na starosti zdravotné prehliadky a komunikáciu so školou. Dieťa je zdravé, šťastné a v škole úspešné.';

const SAMPLE_311_Z_SG = 'Narodenie nášho dieťaťa bolo pre mňa jednou z najkrajších udalostí v živote. Spolu s druhým rodičom sme sa intenzívne pripravovali na rodičovstvo. Od narodenia dieťaťa som sa aktívne starala o jeho potreby — dojčila som, vstávala k nemu v noci, sprevádzala ho pri prvých krokoch a slovách, neskôr ho vodila do škôlky a venovala sa mu pri voľnočasových aktivitách. Vzťah s dieťaťom je vrelý a otvorený, dieťa mi dôveruje a vyhľadáva moju spoločnosť. V súčasnosti zabezpečujem každodennú starostlivosť — ranné vstávanie, odvozy do školy a krúžkov, prípravu jedla, kontrolu úloh, zdravotné prehliadky a komunikáciu so školou. Dieťa je zdravé, šťastné a v škole úspešné.';

const SAMPLE_312_M_SG = 'Z pozitívnych skúseností uvádzam, že druhý rodič sa o dieťa dlhodobo staral s láskou — najmä v období jeho raného detstva, keď bol/-a na materskej alebo rodičovskej dovolenke. Ja som sa v tom čase venoval zabezpečeniu rodiny. Postupom času sa však naša spolupráca v starostlivosti o dieťa zhoršila. Druhý rodič začal/-a v prítomnosti dieťaťa kritizovať moju osobu, napríklad pri jednej z hádok v máji 2024 pred dieťaťom povedal/-a: ,Otec sa o teba nikdy poriadne nestaral.\' Považujem za dôležité uviesť, že [opíšte konkrétne príklady, ktoré chcete uviesť]. Tieto situácie negatívne pôsobia na duševný stav dieťaťa a obmedzujú môj vzťah s ním.';

const SAMPLE_312_Z_SG = 'Z pozitívnych skúseností uvádzam, že druhý rodič sa v prvých rokoch dieťaťa zapájal do starostlivosti aktívnejšie — chodil s nami na prechádzky, hral sa s ním cez víkendy. Postupom času sa však jeho zapojenie znížilo. Najmä v posledných dvoch rokoch som ostala s každodennou starostlivosťou prakticky sama. Druhý rodič pri jednej z hádok v máji 2024 pred dieťaťom povedal: ,Aj tak si robíš, čo chceš.\' Považujem za dôležité uviesť, že [opíšte konkrétne príklady, ktoré chcete uviesť]. Tieto situácie negatívne pôsobia na duševný stav dieťaťa.';

const SAMPLE_32_A_M_SG = 'Vzhľadom na doterajší priebeh starostlivosti a vzťah, ktorý mám s dieťaťom, navrhujem, aby bolo maloleté dieťa zverené do mojej osobnej starostlivosti. Som schopný a ochotný zabezpečiť všetky jeho potreby — bývanie, výživu, oblečenie, vzdelanie aj voľnočasové aktivity. S druhým rodičom som ochotný komunikovať vo veciach týkajúcich sa dieťaťa a podporujem jeho pravidelný styk s ním/ňou. Verím, že takéto usporiadanie je v najlepšom záujme dieťaťa.';

const SAMPLE_32_A_Z_SG = 'Vzhľadom na doterajší priebeh starostlivosti a vzťah, ktorý mám s dieťaťom, navrhujem, aby bolo maloleté dieťa zverené do mojej osobnej starostlivosti. Som schopná a ochotná zabezpečiť všetky jeho potreby — bývanie, výživu, oblečenie, vzdelanie aj voľnočasové aktivity. S druhým rodičom som ochotná komunikovať vo veciach týkajúcich sa dieťaťa a podporujem jeho pravidelný styk s ním/ňou. Verím, že takéto usporiadanie je v najlepšom záujme dieťaťa.';

const SAMPLE_32_B_M_SG = 'Po dôkladnom zvážení doterajšieho priebehu starostlivosti, životnej situácie oboch rodičov a najmä najlepšieho záujmu dieťaťa, navrhujem, aby bolo maloleté dieťa zverené do osobnej starostlivosti druhého rodiča. Som pripravený plniť si vyživovaciu povinnosť a aktívne sa stýkať s dieťaťom tak, aby bol zachovaný môj vrelý vzťah s ním. Považujem za dôležité, aby dieťa malo stabilné prostredie a aby jeho každodenné fungovanie nebolo narušené.';

const SAMPLE_32_B_Z_SG = 'Po dôkladnom zvážení doterajšieho priebehu starostlivosti, životnej situácie oboch rodičov a najmä najlepšieho záujmu dieťaťa, navrhujem, aby bolo maloleté dieťa zverené do osobnej starostlivosti druhého rodiča. Som pripravená plniť si vyživovaciu povinnosť a aktívne sa stýkať s dieťaťom tak, aby bol zachovaný môj vrelý vzťah s ním. Považujem za dôležité, aby dieťa malo stabilné prostredie a aby jeho každodenné fungovanie nebolo narušené.';

// Sample helpery — vyberajú variant podľa pohlavia navrhovateľa A počtu detí.
// pCount === 1 → singulárová varianta; inak (0, 2+) plurálová (defaultne).
const sample311 = (pNav, pCount) => {
  const sg = pCount === 1;
  if (pNav === 'zena') return sg ? SAMPLE_311_Z_SG : SAMPLE_311_Z;
  return sg ? SAMPLE_311_M_SG : SAMPLE_311_M;
};
const sample312 = (pNav, pCount) => {
  const sg = pCount === 1;
  if (pNav === 'zena') return sg ? SAMPLE_312_Z_SG : SAMPLE_312_Z;
  return sg ? SAMPLE_312_M_SG : SAMPLE_312_M;
};
const sample32A = (pNav, pCount) => {
  const sg = pCount === 1;
  if (pNav === 'zena') return sg ? SAMPLE_32_A_Z_SG : SAMPLE_32_A_Z;
  return sg ? SAMPLE_32_A_M_SG : SAMPLE_32_A_M;
};
const sample32B = (pNav, pCount) => {
  const sg = pCount === 1;
  if (pNav === 'zena') return sg ? SAMPLE_32_B_Z_SG : SAMPLE_32_B_Z;
  return sg ? SAMPLE_32_B_M_SG : SAMPLE_32_B_M;
};

// fillTemplate — generický placeholder substitučný helper. Použité aj v Čl. III
// PaperZmena (popis zmeny pomerov, vzory zverenia, výživného, styku).
const fillTemplate = (template, vars) =>
  Object.entries(vars).reduce(
    (acc, [k, v]) => acc.replace(new RegExp('\\{' + k + '\\}', 'g'), v),
    template
  );

// ============================================================
// Čl. II — Doterajšia úprava pomerov rozhodnutím súdu.
// Storage keys + helpers pre reference predchádzajúceho rozhodnutia.
// ============================================================
const CL2_SUD_KEY = 'vyzivnenadieta.zmena.cl2-sud.v1';
const CL2_SUD2_KEY = 'vyzivnenadieta.zmena.cl2-sud2.v1';

// Druh rozhodnutia v inštrumentáli ("rozsudkom" / "uznesením") — dosadí sa
// pred názov súdu v genitíve ("rozsudkom Okresného súdu Bratislava I").
const druhInstrumental = (druh) =>
  druh === 'rozsudok' ? 'rozsudkom' : 'uznesením';

// buildSudRef — referencia na predchádzajúce rozhodnutie. Užívateľ zadáva
// názov súdu už v genitíve (TIP v Čl. II), takže názov sa použije ako-je.
// Vracia inline string (alebo prázdny string ak prvý súd nie je vyplnený).
const buildSudRef = (sud1, sud2) => {
  if (!sud1 || !sud1.nazov || !sud1.nazov.trim()) return '';
  const part1 =
    `${druhInstrumental(sud1.druh)} ${sud1.nazov.trim()}` +
    (sud1.sznacka && sud1.sznacka.trim() ? `, sp. zn. ${sud1.sznacka.trim()}` : '') +
    (sud1.datum   && sud1.datum.trim()   ? `, zo dňa ${formatDatumDmRRRR(sud1.datum)}` : '');
  if (!sud2 || !sud2.nazov || !sud2.nazov.trim()) return part1;
  const part2 =
    `${druhInstrumental(sud2.druh)} ${sud2.nazov.trim()}` +
    (sud2.sznacka && sud2.sznacka.trim() ? `, sp. zn. ${sud2.sznacka.trim()}` : '') +
    (sud2.datum   && sud2.datum.trim()   ? `, zo dňa ${formatDatumDmRRRR(sud2.datum)}` : '');
  return `${part1}, v spojení s ${part2}`;
};

// Variant pre petit — "rozhodnutie {NAZOV_SUDU_GEN}, sp. zn. ..., zo dňa ..."
// (nominatív v "Týmto sa mení rozhodnutie ..."). Druhá časť po "v spojení s"
// je v inštrumentáli. Užívateľ zadáva názov v genitíve.
const buildSudRefPetit = (sud1, sud2) => {
  if (!sud1 || !sud1.nazov || !sud1.nazov.trim()) return '';
  const part1 =
    `rozhodnutie ${sud1.nazov.trim()}` +
    (sud1.sznacka && sud1.sznacka.trim() ? `, sp. zn. ${sud1.sznacka.trim()}` : '') +
    (sud1.datum   && sud1.datum.trim()   ? `, zo dňa ${formatDatumDmRRRR(sud1.datum)}` : '');
  if (!sud2 || !sud2.nazov || !sud2.nazov.trim()) return part1;
  const part2 =
    `rozhodnutím ${sud2.nazov.trim()}` +
    (sud2.sznacka && sud2.sznacka.trim() ? `, sp. zn. ${sud2.sznacka.trim()}` : '') +
    (sud2.datum   && sud2.datum.trim()   ? `, zo dňa ${formatDatumDmRRRR(sud2.datum)}` : '');
  return `${part1}, v spojení s ${part2}`;
};

// ============================================================
// Čl. III — Zmena pomerov a návrh úpravy.
// Storage keys + sample texty pre 4 podsekcie (3.2 popis, 3.3 zverenie,
// 3.4 výživné, 3.6 styk).
// ============================================================
const CL3Z_VYBER_KEY = 'vyzivnenadieta.zmena.cl3-vyber.v1'; // 4 checkboxy
const CL3Z_POPIS_KEY = 'vyzivnenadieta.zmena.cl3-popis.v1'; // textarea zmeny pomerov
const CL3Z_3_KEY     = 'vyzivnenadieta.zmena.cl3-3.v1';     // zverenie (radio + odôvodnenie)
const CL3Z_4_KEY     = 'vyzivnenadieta.zmena.cl3-4.v1';     // výživné (suma + radio + splatnosť + odôvodnenie)
const CL3Z_5_KEY     = 'vyzivnenadieta.zmena.cl3-5.v1';     // zastupovanie (radio + odôvodnenie)
const CL3Z_6_KEY     = 'vyzivnenadieta.zmena.cl3-6.v1';     // styk (aktuálny + nový + odôvodnenie)

// Pomocná funkcia placeholderov pre Čl. III bod 3.2 (popis zmeny pomerov)
// + 3.3 vzory (zverenie navrhovateľovi / odporcovi).
const cl3zVars = (navrhovatelPohlavie, pCount, sudRef) => {
  const navrhKey = navrhovatelPohlavie === 'muz' ? 'otec' : 'matka';
  const druhyKey = navrhovatelPohlavie === 'muz' ? 'matka' : 'otec';
  const navrh = ROLA_RODICA_FORMS[navrhKey];
  const druhy = ROLA_RODICA_FORMS[druhyKey];
  const sg = pCount === 1;
  return {
    SUD_REF: sudRef || '[Doplňte v Čl. II údaje o predchádzajúcom rozhodnutí]',
    NAVRH_RODIC_NOM: navrh.nom,
    NAVRH_RODIC_GEN: navrh.gen,
    NAVRH_RODIC_DAT: navrh.dat,
    NAVRH_RODIC_AK: navrh.ak,
    DRUHY_RODIC_NOM: druhy.nom,
    DRUHY_RODIC_GEN: druhy.gen,
    DRUHY_RODIC_DAT: druhy.dat,
    DRUHY_RODIC_AK: druhy.ak,
    DRUHY_RODIC_INSTR: druhy.instr,
    DRUHY_RODIC_NOM_VELKE: druhy.nom.charAt(0).toUpperCase() + druhy.nom.slice(1),
    DIETA_VS_DETI: sg ? 'dieťa' : 'deti',
    DIETATA_VS_DETI_GEN: sg ? 'dieťaťa' : 'detí',
    DIETATOM_VS_DETMI: sg ? 'dieťaťom' : 'deťmi',
    MALOLETEHO_VS_MALOLETYCH: sg ? 'maloletého' : 'maloletých',
    MALOLETYM_VS_MALOLETYMI: sg ? 'maloletým' : 'maloletými',
    MAJU_VS_MA: sg ? 'má' : 'majú',
    MOJE: 'moje',
    S_DRUHYM_RODICOM: druhyKey === 'matka' ? 's matkou' : 's otcom',
  };
};

// POZOR: paragrafy v § 24 si pred použitím over v aktuálnom znení zákona o rodine.

// 3.2 — popis zmeny pomerov, 4 varianty (A/B/C/D).
const SAMPLE_CL3Z_2_A = 'Od vydania rozhodnutia {SUD_REF} došlo k podstatnej zmene pomerov na strane {DRUHY_RODIC_GEN}. {DRUHY_RODIC_NOM_VELKE} v čase rozhodovania súdu disponoval/-a [popíšte aký bol vtedajší príjem alebo majetkové pomery], pričom v súčasnosti [popíšte aktuálny stav — zvýšenie príjmu, zmena zamestnania, vznik ďalšej vyživovacej povinnosti, zhoršenie alebo zlepšenie majetkových pomerov]. Zmena je trvalá a má taký rozsah, že odôvodňuje úpravu predchádzajúceho rozhodnutia v zmysle § 78 ods. 1 zákona č. 36/2005 Z. z. o rodine.';

const SAMPLE_CL3Z_2_B = 'Od vydania rozhodnutia {SUD_REF} došlo k podstatnej zmene pomerov na strane {MALOLETEHO_VS_MALOLETYCH} {DIETATA_VS_DETI_GEN}. V čase rozhodovania súdu malo {DIETA_VS_DETI} [napríklad: predškolský vek / nastupovalo do prvého ročníka základnej školy], pričom v súčasnosti [popíšte aktuálne potreby — nástup na druhý stupeň ZŠ, prechod na strednú školu, prechod na vysokú školu, dochádzanie do iného mesta, zvýšené náklady spojené s krúžkami a štúdiom]. Odôvodnené potreby {MALOLETEHO_VS_MALOLETYCH} {DIETATA_VS_DETI_GEN} sa od rozhodnutia súdu zvýšili v takom rozsahu, že je v záujme {DIETATA_VS_DETI_GEN} pristúpiť k zmene predchádzajúceho rozhodnutia v zmysle § 62 ods. 2 v spojení s § 78 ods. 1 zákona č. 36/2005 Z. z. o rodine.';

const SAMPLE_CL3Z_2_C = 'Od vydania rozhodnutia {SUD_REF} došlo k podstatnej zmene pomerov spočívajúcej v [vyberte: zhoršení zdravotného stavu {MALOLETEHO_VS_MALOLETYCH} {DIETATA_VS_DETI_GEN} / zhoršení zdravotného stavu navrhovateľa/-ky / zhoršení zdravotného stavu {DRUHY_RODIC_GEN}]. Zdravotný stav si vyžaduje [popíšte konkrétne — pravidelnú liečbu, špeciálnu starostlivosť, zvýšené náklady na lieky a zdravotnícke pomôcky, asistenciu, prerušenie alebo obmedzenie pracovnej činnosti rodiča]. Táto zmena podstatným spôsobom ovplyvňuje doterajšiu úpravu pomerov a v záujme {DIETATA_VS_DETI_GEN} je preto potrebné pristúpiť k zmene predchádzajúceho rozhodnutia v zmysle § 78 ods. 1 zákona č. 36/2005 Z. z. o rodine.';

const SAMPLE_CL3Z_2_D = 'Od vydania rozhodnutia {SUD_REF} došlo k podstatnej zmene životnej situácie účastníkov spočívajúcej v [popíšte konkrétne — sťahovanie jedného z rodičov, vznik ďalšej vyživovacej povinnosti voči inému dieťaťu, zmena rodinných pomerov, dlhodobá nezamestnanosť, narodenie ďalšieho dieťaťa povinnému/-ej rodičovi, zmena spoločnej domácnosti, marenie styku, iné okolnosti]. Táto zmena má trvalý charakter a podstatne ovplyvňuje doterajšiu úpravu výkonu rodičovských práv a povinností. V záujme {MALOLETEHO_VS_MALOLETYCH} {DIETATA_VS_DETI_GEN} je preto potrebné pristúpiť k zmene predchádzajúceho rozhodnutia v zmysle § 26 zákona č. 36/2005 Z. z. o rodine.';

// 3.3 — odôvodnenie zverenia, 4 vzory:
//   _3_1  — zverenie navrhovateľovi (sebe)
//   _3_1B — zverenie odporcovi (druhému rodičovi)
//   _3_2  — striedavá starostlivosť
//   _3_3  — spoločná starostlivosť (po novele 2023, § 24 ods. 4)
const SAMPLE_CL3Z_3_1 = 'Žiadam, aby maloleté {DIETA_VS_DETI} bolo zverené do mojej osobnej starostlivosti. O {DIETA_VS_DETI} sa fakticky starám prevažne ja a {DIETA_VS_DETI} {MAJU_VS_MA} ku mne pevné citové väzby. {MOJE} výchovné prostredie je stabilné a primerané potrebám {DIETATA_VS_DETI_GEN}. Vzhľadom na zmenu pomerov uvedenú v bode 3.2 je v najlepšom záujme {MALOLETEHO_VS_MALOLETYCH} {DIETATA_VS_DETI_GEN} zveriť ho do mojej osobnej starostlivosti v zmysle § 24 ods. 1 zákona č. 36/2005 Z. z. o rodine.';

const SAMPLE_CL3Z_3_1B = 'Žiadam, aby maloleté {DIETA_VS_DETI} bolo zverené do osobnej starostlivosti {DRUHY_RODIC_GEN}. O {DIETA_VS_DETI} sa fakticky stará prevažne {DRUHY_RODIC_NOM} a {DIETA_VS_DETI} {MAJU_VS_MA} k {DRUHY_RODIC_DAT} pevné citové väzby. Výchovné prostredie {DRUHY_RODIC_GEN} je stabilné a primerané potrebám {DIETATA_VS_DETI_GEN}. Vzhľadom na zmenu pomerov uvedenú v bode 3.2 je v najlepšom záujme {MALOLETEHO_VS_MALOLETYCH} {DIETATA_VS_DETI_GEN} zveriť ho do osobnej starostlivosti {DRUHY_RODIC_GEN} v zmysle § 24 ods. 1 zákona č. 36/2005 Z. z. o rodine.';

const SAMPLE_CL3Z_3_2 = 'Žiadam, aby maloleté {DIETA_VS_DETI} bolo zverené do striedavej osobnej starostlivosti oboch rodičov v zmysle § 24 ods. 3 zákona č. 36/2005 Z. z. o rodine. Obaja rodičia sme spôsobilí dieťa vychovávať a máme o jeho osobnú starostlivosť záujem. Striedavá starostlivosť bude najlepšie zaisťovať potreby {MALOLETEHO_VS_MALOLETYCH} {DIETATA_VS_DETI_GEN}, jeho vyvážený vzťah s oboma rodičmi a kontinuitu výchovného prostredia. Navrhovaný režim striedavej starostlivosti je [popíšte konkrétny režim — napr. striedanie po týždňoch, dvojtýždňové intervaly, model 5-2-2-5].';

const SAMPLE_CL3Z_3_3 = 'Žiadam, aby maloleté {DIETA_VS_DETI} bolo zverené do spoločnej osobnej starostlivosti oboch rodičov v zmysle § 24 ods. 4 zákona č. 36/2005 Z. z. o rodine. Obaja rodičia sme spôsobilí dieťa vychovávať, žijeme v geograficky blízkej oblasti a sme schopní vo veciach výchovy {MALOLETEHO_VS_MALOLETYCH} {DIETATA_VS_DETI_GEN} efektívne spolupracovať. Súhlas oboch rodičov so spoločnou osobnou starostlivosťou je doložený [popíšte — písomná dohoda rodičov / spoločné stanovisko rodičov uvedené v tomto návrhu].';

// 3.4 — odôvodnenie výživného. Per-dieťa štruktúra (FÁZA refactor): sample funkcia
// generuje finálny text s odrážkami a) b) c) podľa filledKids + perDieta sumy.
// Pri 0/1 dieťati sa zjednoduší formulácia (bez odrážok). Sumy sa berú z perDieta
// mapy v čase kliknutia tlačidla — nie placeholdery.
const formatujKidPreVyzivne = (kid) => {
  const meno = (kid.meno || '').trim() || '[meno dieťaťa]';
  const dat = (kid.datumNarodenia || '').trim();
  return dat ? `${meno}, nar. ${formatDatumDmRRRR(dat)}` : meno;
};
const sampleVyzivneZmena = (typ, perDieta, filledKids, navrhovatelPohlavie) => {
  const kidsWithName = filledKids.filter(k => k.meno && k.meno.trim());
  const navrhKey = navrhovatelPohlavie === 'muz' ? 'otec' : 'matka';
  const druhyKey = navrhovatelPohlavie === 'muz' ? 'matka' : 'otec';
  const navrhGen = ROLA_RODICA_FORMS[navrhKey].gen;
  const druhyGen = ROLA_RODICA_FORMS[druhyKey].gen;
  const get = (kid) => {
    const r = (perDieta && perDieta[kid.id]) || {};
    return {
      stara: (r.staraVyska || '').trim() || '[doterajšia suma]',
      nova: (r.novaVyska || '').trim() || '[nová suma]',
    };
  };
  const detiGen = kidsWithName.length === 1 ? 'maloletého dieťaťa' : 'maloletých detí';

  if (typ === 'zvysenie') {
    if (kidsWithName.length <= 1) {
      const kid = kidsWithName[0];
      const refKid = kid ? `na maloletého ${formatujKidPreVyzivne(kid)} ` : '';
      const { stara, nova } = kid ? get(kid) : { stara: '[doterajšia suma]', nova: '[nová suma]' };
      return `Žiadam zvýšenie výživného ${refKid}z doterajšej sumy ${stara} EUR mesačne na sumu ${nova} EUR mesačne, vždy do 15. dňa kalendárneho mesiaca vopred, k rukám ${navrhGen}, počnúc dňom podania tohto návrhu na súd. Doterajšia výška výživného neodpovedá odôvodneným potrebám ${detiGen} a nezohľadňuje aktuálne schopnosti, možnosti a majetkové pomery ${druhyGen} v zmysle § 62 ods. 2 zákona č. 36/2005 Z. z. o rodine. Vzhľadom na zmenu pomerov uvedenú v bode 3.2 je odôvodnené pristúpiť k zvýšeniu výživného.`;
    }
    const odrazky = kidsWithName.map((kid, i) => {
      const { stara, nova } = get(kid);
      const letter = String.fromCharCode(97 + i);
      const sep = i === kidsWithName.length - 1 ? '.' : ';';
      return `${letter}) na maloletého ${formatujKidPreVyzivne(kid)} z doterajšej sumy ${stara} EUR mesačne na sumu ${nova} EUR mesačne${sep}`;
    }).join(' ');
    return `Žiadam zvýšenie výživného nasledovne: ${odrazky} Výživné je splatné vždy do 15. dňa kalendárneho mesiaca vopred, k rukám ${navrhGen}, počnúc dňom podania tohto návrhu na súd. Doterajšia výška výživného neodpovedá odôvodneným potrebám maloletých detí a nezohľadňuje aktuálne schopnosti, možnosti a majetkové pomery ${druhyGen} v zmysle § 62 ods. 2 zákona č. 36/2005 Z. z. o rodine. Vzhľadom na zmenu pomerov uvedenú v bode 3.2 je odôvodnené pristúpiť k zvýšeniu výživného.`;
  }

  if (typ === 'znizenie') {
    if (kidsWithName.length <= 1) {
      const kid = kidsWithName[0];
      const refKid = kid ? `na maloletého ${formatujKidPreVyzivne(kid)} ` : '';
      const { stara, nova } = kid ? get(kid) : { stara: '[doterajšia suma]', nova: '[nová suma]' };
      return `Žiadam zníženie výživného ${refKid}z doterajšej sumy ${stara} EUR mesačne na sumu ${nova} EUR mesačne, vždy do 15. dňa kalendárneho mesiaca vopred, k rukám ${navrhGen}, počnúc dňom podania tohto návrhu na súd. Doterajšia výška výživného presahuje moje aktuálne schopnosti a možnosti v zmysle § 62 ods. 2 zákona č. 36/2005 Z. z. o rodine. Vzhľadom na zmenu pomerov uvedenú v bode 3.2 (najmä [konkretizujte — pokles príjmu, vznik ďalšej vyživovacej povinnosti, dlhodobá nezamestnanosť, zhoršenie zdravotného stavu]) nie som schopný/-á zabezpečovať výživné v doterajšej výške.`;
    }
    const odrazky = kidsWithName.map((kid, i) => {
      const { stara, nova } = get(kid);
      const letter = String.fromCharCode(97 + i);
      const sep = i === kidsWithName.length - 1 ? '.' : ';';
      return `${letter}) na maloletého ${formatujKidPreVyzivne(kid)} z doterajšej sumy ${stara} EUR mesačne na sumu ${nova} EUR mesačne${sep}`;
    }).join(' ');
    return `Žiadam zníženie výživného nasledovne: ${odrazky} Zmena platí vždy do 15. dňa kalendárneho mesiaca vopred, k rukám ${navrhGen}, počnúc dňom podania tohto návrhu na súd. Doterajšia výška výživného presahuje moje aktuálne schopnosti a možnosti v zmysle § 62 ods. 2 zákona č. 36/2005 Z. z. o rodine. Vzhľadom na zmenu pomerov uvedenú v bode 3.2 (najmä [konkretizujte — pokles príjmu, vznik ďalšej vyživovacej povinnosti, dlhodobá nezamestnanosť, zhoršenie zdravotného stavu]) nie som schopný/-á zabezpečovať výživné v doterajšej výške.`;
  }

  if (typ === 'zrusenie') {
    if (kidsWithName.length <= 1) {
      const kid = kidsWithName[0];
      const refKid = kid ? `voči maloletému ${formatujKidPreVyzivne(kid)}` : `voči maloletému dieťaťu`;
      return `Žiadam zrušenie vyživovacej povinnosti ${refKid} ku dňu [doplňte deň]. Vyživovacia povinnosť zaniká [vyberte dôvod — dosiahnutie schopnosti dieťaťa živiť sa samé, ukončenie štúdia, iný dôvod podľa § 62 ods. 1 zákona č. 36/2005 Z. z. o rodine]. ${kidsWithName.length === 1 ? 'Maloletý/-á' : 'Maloletý/-á'} [popíšte aktuálny stav — nastúpilo do zamestnania, ukončilo vysokoškolské štúdium, iné okolnosti].`;
    }
    const odrazky = kidsWithName.map((kid, i) => {
      const letter = String.fromCharCode(97 + i);
      const sep = i === kidsWithName.length - 1 ? '.' : ';';
      return `${letter}) voči maloletému ${formatujKidPreVyzivne(kid)} ku dňu [doplňte deň]${sep}`;
    }).join(' ');
    return `Žiadam zrušenie vyživovacej povinnosti nasledovne: ${odrazky} Vyživovacia povinnosť zaniká [vyberte dôvod — dosiahnutie schopnosti dieťaťa živiť sa samé, ukončenie štúdia, iný dôvod podľa § 62 ods. 1 zákona č. 36/2005 Z. z. o rodine]. Maloleté deti [popíšte aktuálny stav — nastúpili do zamestnania, ukončili štúdium, iné okolnosti].`;
  }

  return '';
};

// 3.6 — odôvodnenie styku, 2 vzory.
const SAMPLE_CL3Z_6_1 = 'Žiadam rozšírenie styku {DRUHY_RODIC_GEN} s {MALOLETYM_VS_MALOLETYMI} {DIETATOM_VS_DETMI}. Aktuálne nastavený styk podľa pôvodného rozhodnutia [popíšte aktuálny rozsah — napr. každý druhý víkend od piatka do nedele] už nezodpovedá potrebám {MALOLETEHO_VS_MALOLETYCH} {DIETATA_VS_DETI_GEN} ani záujmu na rozvíjaní vzťahu {S_DRUHYM_RODICOM}. Vzhľadom na zmenu pomerov uvedenú v bode 3.2 navrhujem rozšírenie styku v zmysle § 25 zákona č. 36/2005 Z. z. o rodine na nasledovný rozsah: [popíšte navrhovaný styk — víkendy, polovica prázdnin, sviatky, denný styk].';

const SAMPLE_CL3Z_6_2 = 'Žiadam obmedzenie styku {DRUHY_RODIC_GEN} s {MALOLETYM_VS_MALOLETYMI} {DIETATOM_VS_DETMI}. Aktuálne nastavený styk podľa pôvodného rozhodnutia [popíšte aktuálny rozsah] nie je v záujme {MALOLETEHO_VS_MALOLETYCH} {DIETATA_VS_DETI_GEN} z dôvodu [popíšte dôvody — opakované marenie styku, ohrozenie záujmu dieťaťa, zhoršenie zdravotného alebo psychického stavu dieťaťa po stykoch, vzdialené bydlisko {DRUHY_RODIC_GEN}, iné okolnosti]. Navrhujem obmedzenie styku v zmysle § 25 ods. 3 zákona č. 36/2005 Z. z. o rodine na nasledovný rozsah: [popíšte navrhovaný obmedzený styk].';

const fillTemplateZmena = (template, vars) => fillTemplate(template, vars);

// Controlled contentEditable — to isté pole žije na dvoch miestach (bod 1.1
// a petit) a synchronizuje sa cez zdieľaný state.
//
// Cursor preservation: písanie do tohto inputu nesmie spôsobiť prepis textContent
// (cursor by skočil na začiatok). isTypingRef príznak rozlíši, či zmena value
// prišla z tohto inputu (skip DOM write) alebo z druhej inštancie (write).
// noPersist=true → pridá class `ed-no-persist`. Persist.jsx tieto polia preskakuje
// (save aj restore), takže ich obsah riadi výlučne React state. Použité pre dynamické
// kolekcie (deti), ktorých počet/poradie sa mení a Persistov ordinálny scope by
// pri delete-and-reload prehadzoval hodnoty medzi riadkami.
const SyncedEd = ({ value, onChange, placeholder, lg, num, noPersist }) => {
  const ref = React.useRef(null);
  const isTypingRef = React.useRef(false);

  React.useEffect(() => {
    if (ref.current && !isTypingRef.current && ref.current.textContent !== value) {
      ref.current.textContent = value;
    }
    isTypingRef.current = false;
  }, [value]);

  const cls = [
    "ed",
    lg && "ed-lg",
    num && "ed-num",
    !value && "ed-empty",
    noPersist && "ed-no-persist",
  ].filter(Boolean).join(" ");

  return (
    <span
      ref={ref}
      className={cls}
      contentEditable
      suppressContentEditableWarning
      onInput={(e) => {
        isTypingRef.current = true;
        onChange(e.currentTarget.textContent);
      }}
      data-placeholder={placeholder}
      role="textbox"
      aria-label={placeholder}
    />
  );
};

// Modul-level komponent — stabilná funkčná referencia, vďaka čomu si <input>
// drží focus medzi keystrokes. State žije v Paper a tečie cez props, takže
// hlavička aj bod 1.3 zdieľajú ten istý vybraný súd.
const SudAutocomplete = ({ sudQuery, setSudQuery, sudVybrany, setSudVybrany, sudDropdown, setSudDropdown, sudFiltered }) => (
  <span style={{ position: 'relative', display: 'inline-block', minWidth: 280 }}>
    <input
      type="text"
      value={sudVybrany ? sudVybrany.nazov : sudQuery}
      onChange={(e) => { setSudQuery(e.target.value); setSudVybrany(null); setSudDropdown(true); }}
      onFocus={() => setSudDropdown(true)}
      onBlur={() => setTimeout(() => setSudDropdown(false), 150)}
      placeholder="začnite písať názov súdu..."
      style={{
        padding: '3px 8px',
        border: '1px solid var(--rule)',
        borderRadius: 'var(--r-sm)',
        fontFamily: 'var(--serif)',
        fontSize: '0.95em',
        background: 'var(--ed-bg, #fefce8)',
        width: '100%',
      }}
    />
    {sudDropdown && sudFiltered.length > 0 && (
      <ul style={{
        position: 'absolute',
        top: '100%',
        left: 0,
        right: 0,
        background: 'var(--paper, #ffffff)',
        backdropFilter: 'none',
        border: '1px solid var(--rule)',
        borderRadius: 'var(--r-sm)',
        boxShadow: '0 4px 16px rgba(0,0,0,0.10)',
        listStyle: 'none',
        margin: 0,
        padding: '4px 0',
        zIndex: 1000,
        maxHeight: 220,
        overflowY: 'auto',
      }}>
        {sudFiltered.map(s => (
          <li
            key={s.nazov}
            onMouseDown={() => { setSudVybrany(s); setSudQuery(''); setSudDropdown(false); }}
            style={{
              padding: '2px 12px',
              cursor: 'pointer',
              fontSize: '0.9em',
              fontFamily: 'var(--serif)',
              background: 'var(--paper, #ffffff)',
            }}
            onMouseEnter={e => e.currentTarget.style.background = 'var(--ivory-2)'}
            onMouseLeave={e => e.currentTarget.style.background = 'var(--paper, #ffffff)'}
          >
            {s.nazov}
          </li>
        ))}
      </ul>
    )}
  </span>
);

// ============================================================
// TipBtn — floating "TIP" pin v gutteri papiera. Definovaný NA module-leveli
// (mimo Paper), aby React zachoval identitu komponentu cez Paper re-rendery.
// Inak (keď bol TipBtn definovaný vnútri Paper) každý Paper render mu pridelil
// novú function reference → React unmount + mount → useLayoutEffect zbehol
// znova a krátky frame s initial topPx=0 spôsoboval vizuálny "preskok" tipov
// pri scrolle (scroll-spy IntersectionObserver triggeruje setActiveArticle/
// setActiveTipKey, čo Paper re-renderuje).
//
// Top sa počíta RAZ pri reálnom mount-e + na zmenu výšky .paper-a cez
// ResizeObserver (otvorenie wizardu, vkladanie vzoru, edit textu, viewport
// resize). Počas scrollu sa NEPREPOČÍTAVA → tipy sú vizuálne stabilné.
// activeTipKey + onTipClick sú doručené cez TipContext, takže prop drilling
// do 13 call-sites netreba.
// ============================================================
const TipContext = React.createContext({ activeTipKey: null, onTipClick: null });

const TipBtn = ({ pointKey }) => {
  const { activeTipKey, onTipClick } = React.useContext(TipContext);
  const buttonRef = React.useRef(null);
  const [topPx, setTopPx] = React.useState(0);

  React.useLayoutEffect(() => {
    const button = buttonRef.current;
    if (!button) return;
    const anchor = button.parentNode;
    const paper = button.closest('.paper');
    if (!paper || !anchor) return;

    const update = () => {
      // offsetTop chain anchor → .paper. Po našich CSS zmenách je anchor.offsetParent
      // priamo .paper, walk je defenzívny pre prípad neskoršieho pozicovaného wrapperu.
      let top = anchor.offsetTop;
      let p = anchor.offsetParent;
      while (p && p !== paper) {
        top += p.offsetTop;
        p = p.offsetParent;
      }
      setTopPx(top + 2);
    };
    update();

    const ro = new ResizeObserver(update);
    ro.observe(paper);
    window.addEventListener('resize', update);
    return () => { ro.disconnect(); window.removeEventListener('resize', update); };
  }, []);

  return (
    <button
      ref={buttonRef}
      type="button"
      className={`tip-pin no-print ${activeTipKey === pointKey ? 'active' : ''}`}
      data-tip-key={pointKey}
      onClick={(e) => { e.stopPropagation(); onTipClick && onTipClick(pointKey); }}
      aria-label={`Zobraziť tip k bodu ${pointKey}`}
      title={`Tip k bodu ${pointKey}`}
      contentEditable={false}
      style={{ top: `${topPx}px` }}
    >
      TIP
    </button>
  );
};

// Sekcia maloletých detí — vlastná serializácia, mimo Persist.jsx.
// Persist ukladá .ed polia podľa ordinálneho indexu vo svojom scope. Pre dynamickú
// kolekciu, kde môže používateľ mazať uprostred a pridávať na konci, by to po
// reload-e prehadzovalo hodnoty medzi riadkami. Preto kids držíme ako JSON pole
// v samostatnom localStorage kľúči a Ed polia označujeme noPersist (Persist
// preskakuje class `ed-no-persist`).
// ============================================================
// Petit (rozsudok) — pure helpers + generátor výrokov.
// generujPetit() je čistá funkcia, vstup = ctx zo state-u, výstup =
// pole { label, body } pre render. Používa existujúce helpery
// (oznacenie, oznacenieCap, rolaOpravneny, rolaRodicaKey, detiSlovo,
// sampleStriedavka_*) + nové: rolaPovinny, PetitPh, orPh, formatujKidsList.
// ============================================================
const PetitPh = ({ children }) => (
  <span className="no-copy no-print" style={{ fontStyle: 'italic', color: 'var(--ink-3)' }}>{children}</span>
);
const orPh = (val, hint) =>
  (val && String(val).trim()) ? val : <PetitPh>[{hint}]</PetitPh>;

// Sloveso "povinný/-á" pre rodičovskú rolu — gendered koncovka.
// Analogicky k rolaOpravneny (FÁZA B).
const rolaPovinny = (role, navrhovatelPohlavie) =>
  rolaRodicaKey(role, navrhovatelPohlavie) === 'matka' ? 'povinná' : 'povinný';

// formatujKidsList — vracia ReactNode "Meno1, nar. dátum1, [a] MenoN, nar. dátumN"
// s placeholdrami pre prázdne polia. Skrátené "nar." je rod-neutrálne.
const formatujKidsList = (kids) => {
  if (!kids || kids.length === 0) return '';
  const renderKid = (k) => (
    <>
      {orPh(k.meno, 'meno?')}, nar. {orPh(k.datumNarodenia, 'dátum?')}
    </>
  );
  if (kids.length === 1) return renderKid(kids[0]);
  return (
    <>
      {kids.map((k, i) => (
        <React.Fragment key={k.id}>
          {renderKid(k)}
          {i === kids.length - 2
            ? (kids.length === 2 ? ' a ' : ', a ')
            : (i < kids.length - 1 ? ', ' : '')}
        </React.Fragment>
      ))}
    </>
  );
};

// formatujKidsListPreVyzivne — pre Výrok III: zoznam detí so sumami v jednej vete.
// "maloletého dieťaťa Anton Novák, nar. 4. 1. 2015, sumou 200 eur mesačne[, a maloletého dieťaťa ...]"
const formatujKidsListPreVyzivne = (kids, getVyzivne) => {
  if (!kids || kids.length === 0) return '';
  const renderKid = (k) => {
    const row = getVyzivne(k.id);
    return (
      <>
        maloletého dieťaťa {orPh(k.meno, 'meno?')}, nar. {orPh(k.datumNarodenia, 'dátum?')}, sumou {orPh(row && row.suma, 'suma')} eur mesačne
      </>
    );
  };
  if (kids.length === 1) return renderKid(kids[0]);
  return (
    <>
      {kids.map((k, i) => (
        <React.Fragment key={k.id}>
          {renderKid(k)}
          {i === kids.length - 2
            ? (kids.length === 2 ? ' a ' : ', a ')
            : (i < kids.length - 1 ? ', ' : '')}
        </React.Fragment>
      ))}
    </>
  );
};

// Default voľba zastupovania — VŽDY 'obaja' bez ohľadu na formu/zverenie/pohlavie.
// Súdna prax (§ 28 ods. 1 + § 31 ods. 1 ZoR) je, že obaja rodičia ostávajú
// zákonnými zástupcami, iný režim je výnimočný. userTouchedZastupovanie
// uzamkne ďalšie auto-zmeny po prvom explicit prepnutí na matka/otec.
const computeZastupovanieDefault = (_formaStarostlivosti, _zvereniePri_a, _navrhovatelPohlavie) => 'obaja';

const ROMAN_PETIT = ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII'];

// Helper na splitnutie multi-paragraph Ed-content (line breaks) na ReactNodes.
const splitParagraphs = (text) =>
  String(text || '')
    .split(/\n\s*\n/)
    .map(s => s.trim())
    .filter(Boolean);

function generujPetit(ctx) {
  const {
    navrhovatelPohlavie, odporcaPohlavie,
    menoNavrhovatela, menoOdporcu,
    filledKids, cl3,
    ed33bContent, ed35Content,
    getVyzivne,
  } = ctx;

  const pCount = filledKids.length;
  // Každý výrok = { label, paragraphs: ReactNode[] }. Multi-paragraph používa
  // Výrok striedavka (úvod + 4 sekcie + odovzdanie); ostatné majú 1 paragraph.
  const verdicts = [];
  let lastOuter = 0;

  if (pCount > 0) {
    const kidsList = formatujKidsList(filledKids);

    // Výrok I — zverenie do osobnej starostlivosti.
    lastOuter = 1;
    if (cl3.formaStarostlivosti === 'a') {
      // Rodinnoprávne označenie zvereného rodiča (matka/otec) v 2. páde —
      // bez procesných označení a bez mena. Cleaner právna formulácia.
      const zverenyKey = rolaRodicaKey(cl3.zvereniePri_a, navrhovatelPohlavie);
      verdicts.push({
        label: ROMAN_PETIT[lastOuter],
        paragraphs: [(
          <>
            Maloleté {pCount === 1 ? 'dieťa' : 'deti'} {kidsList} sa {pCount === 1 ? 'zveruje' : 'zverujú'} do osobnej starostlivosti {rolaRodicaPad(zverenyKey, 'gen')}.
          </>
        )],
      });
    } else if (cl3.formaStarostlivosti === 'b') {
      // Petit striedavka — jednotne pre 1tyz aj vlastne: petit reflektuje
      // čisto Ed-content 3.3(b). Default vzor sa už NEgeneruje automaticky;
      // ak user neklikol "Použiť tento text", inline placeholder upozorní
      // na chýbajúci obsah (no-print, v PDF zmizne).
      const paragraphs = [];
      paragraphs.push(
        <>
          Maloleté {pCount === 1 ? 'dieťa' : 'deti'} {kidsList} sa {pCount === 1 ? 'zveruje' : 'zverujú'} do striedavej osobnej starostlivosti oboch rodičov nasledovne:
        </>
      );
      if (ed33bContent && ed33bContent.trim()) {
        splitParagraphs(ed33bContent).forEach(p =>
          paragraphs.push(<span style={{ whiteSpace: 'pre-wrap' }}>{p}</span>)
        );
      } else {
        paragraphs.push(<PetitPh>[doplňte režim striedania v Čl. III bod 3.3]</PetitPh>);
      }
      verdicts.push({ label: ROMAN_PETIT[lastOuter], paragraphs });
    } else if (cl3.formaStarostlivosti === 'c') {
      verdicts.push({
        label: ROMAN_PETIT[lastOuter],
        paragraphs: [(
          <>
            Maloleté {pCount === 1 ? 'dieťa' : 'deti'} {kidsList} sa {pCount === 1 ? 'zveruje' : 'zverujú'} do spoločnej osobnej starostlivosti oboch rodičov podľa § 24 ods. 2 zákona č. 36/2005 Z. z. o rodine.
          </>
        )],
      });
    }

    // Výrok II — zastupovanie a správa majetku.
    lastOuter = 2;
    const zastText = cl3.zastupovanie === 'obaja'
      ? 'budú obaja rodičia'
      : cl3.zastupovanie === 'matka'
        ? 'bude matka'
        : 'bude otec';
    verdicts.push({
      label: ROMAN_PETIT[lastOuter],
      paragraphs: [(
        <>
          Zastupovať maloleté {pCount === 1 ? 'dieťa' : 'deti'} {kidsList} a spravovať {pCount === 1 ? 'jeho' : 'ich'} majetok {zastText}.
        </>
      )],
    });

    // Výrok III — výživné.
    lastOuter = 3;
    const rezim = cl3.formaStarostlivosti === 'a'
      ? 'i'
      : (cl3.formaStarostlivosti === 'b' ? cl3.rezimVyzivnehoPri_b : cl3.rezimVyzivnehoPri_c);

    if (rezim === 'i') {
      // JEDEN výrok bez pod-indexov — všetky deti so sumami v jednej vete.
      // Subjekt + adresát cez rolaRodica (matka/otec), žiadne procesné označenia.
      const platiRole = cl3.formaStarostlivosti === 'a'
        ? (cl3.zvereniePri_a === 'navrhovatel' ? 'odporca' : 'navrhovatel')
        : 'odporca';
      const prijemcaRole = cl3.formaStarostlivosti === 'a'
        ? cl3.zvereniePri_a
        : 'navrhovatel';
      const platiKey = rolaRodicaKey(platiRole, navrhovatelPohlavie);
      const prijemcaKey = rolaRodicaKey(prijemcaRole, navrhovatelPohlavie);
      const platiCap = platiKey === 'matka' ? 'Matka' : 'Otec';
      const platiPovinnyTvar = platiKey === 'matka' ? 'povinná' : 'povinný';
      const prijemcaGen = rolaRodicaPad(prijemcaKey, 'gen');

      verdicts.push({
        label: ROMAN_PETIT[lastOuter],
        paragraphs: [(
          <>
            {platiCap} je {platiPovinnyTvar} prispievať na výživu {formatujKidsListPreVyzivne(filledKids, getVyzivne)}, vždy do 15. dňa kalendárneho mesiaca vopred, k rukám {prijemcaGen}, počnúc dňom podania tohto návrhu na súd.
          </>
        )],
      });
    } else {
      // rezim === 'ii'. Pri striedavke (b) má vlastnú formuláciu (kratšia, právne čistá).
      // Pri spoločnej (c) zachováme pôvodnú o "počas obdobia osobnej starostlivosti".
      if (cl3.formaStarostlivosti === 'b') {
        verdicts.push({
          label: ROMAN_PETIT[lastOuter],
          paragraphs: [(
            <>Počas trvania striedavej osobnej starostlivosti rodičov súd výživné neurčuje.</>
          )],
        });
      } else {
        verdicts.push({
          label: ROMAN_PETIT[lastOuter],
          paragraphs: [(
            <>Výživné na maloleté {pCount === 1 ? 'dieťa' : 'deti'} sa neurčuje.</>
          )],
        });
      }
    }

    // Výrok IV — styk (len pri formaStarostlivosti='a').
    if (cl3.formaStarostlivosti === 'a') {
      lastOuter = 4;
      const nezverenyRole = cl3.zvereniePri_a === 'navrhovatel' ? 'odporca' : 'navrhovatel';
      const nezverenyPohlavie = nezverenyRole === 'navrhovatel' ? navrhovatelPohlavie : odporcaPohlavie;
      const nezverenyMeno = nezverenyRole === 'navrhovatel' ? menoNavrhovatela : menoOdporcu;

      if (cl3.styk === 'i') {
        // Multi-paragraph: úvodná veta + Ed-content rozdelený na odseky.
        const paragraphs = [];
        if (ed35Content && ed35Content.trim()) {
          // Prvý odsek prilepí úvodnú vetu so subjektom.
          const userParas = splitParagraphs(ed35Content);
          paragraphs.push(
            <>
              {oznacenieCap(nezverenyRole, nezverenyPohlavie)} {orPh(nezverenyMeno, 'meno rodiča')} je {rolaOpravneny(nezverenyRole, navrhovatelPohlavie)} stýkať sa s {detiSlovo(pCount, 'instr')} v nasledujúcom rozsahu: {userParas[0] && <span style={{ whiteSpace: 'pre-wrap' }}>{userParas[0]}</span>}
            </>
          );
          // Ďalšie odseky z Ed-content samostatne.
          userParas.slice(1).forEach(p =>
            paragraphs.push(<span style={{ whiteSpace: 'pre-wrap' }}>{p}</span>)
          );
        } else {
          paragraphs.push(
            <>
              {oznacenieCap(nezverenyRole, nezverenyPohlavie)} {orPh(nezverenyMeno, 'meno rodiča')} je {rolaOpravneny(nezverenyRole, navrhovatelPohlavie)} stýkať sa s {detiSlovo(pCount, 'instr')} v nasledujúcom rozsahu: <PetitPh>[doplňte rozsah styku v Čl. III bod 3.5]</PetitPh>.
            </>
          );
        }
        verdicts.push({ label: ROMAN_PETIT[lastOuter], paragraphs });
      } else { // styk === 'ii'
        const nezverenyKey = rolaRodicaKey(nezverenyRole, navrhovatelPohlavie);
        verdicts.push({
          label: ROMAN_PETIT[lastOuter],
          paragraphs: [(
            <>Styk {rolaRodicaPad(nezverenyKey, 'gen')} s {detiSlovo(pCount, 'instr')} sa neupravuje.</>
          )],
        });
      }
    }
  }

  // Posledný výrok — trovy konania (vždy, dynamický index).
  lastOuter += 1;
  verdicts.push({
    label: ROMAN_PETIT[lastOuter],
    paragraphs: [(
      <>O trovách konania súd rozhodne osobitným uznesením po právoplatnosti rozsudku vo veci samej.</>
    )],
  });

  return verdicts;
}

const KIDS_STORAGE_KEY = 'vyzivnenadieta.kids-zmena.v1';
const newKid = () => ({
  id: 'kid-' + Math.random().toString(36).slice(2, 9),
  meno: '',
  datumNarodenia: '',
  bytom: '',
});

// Meta state PaperZmena (gender + ďalšie ne-Ed nastavenia). Persist.jsx ukladá
// iba .ed contentEditable polia; pre React state s vlastnou logikou držíme
// vlastnú JSON serializáciu.
const META_STORAGE_KEY = 'vyzivnenadieta.meta-zmena.v1';

// ============================================================
// Čl. IV — Pomery rodičov a výdavky na maloleté deti.
// Default 9 + 9 položiek tabuliek (mesačné + ročné výdavky), per-kid sumy
// indexované cez kid.id. Status pracovnej situácie navrhovateľa pre sample.
// ============================================================
const CL4_STORAGE_KEY = 'vyzivnenadieta.cl4-zmena.v1';

const DEFAULT_VYDAVKY_MESACNE = {
  'mes-strava':       { nazov: 'Strava (potraviny a denné jedlo)', sumy: {} },
  'mes-byvanie':      { nazov: 'Bývanie (alikvotná časť — nájomné, energie, voda)', sumy: {} },
  'mes-hygiena':      { nazov: 'Hygienické potreby a drogéria', sumy: {} },
  'mes-doprava':      { nazov: 'Doprava (MHD, palivo na odvoz)', sumy: {} },
  'mes-skola':        { nazov: 'Školské obedy a školské potreby', sumy: {} },
  'mes-kruzky':       { nazov: 'Záujmové krúžky a športové aktivity', sumy: {} },
  'mes-tel':          { nazov: 'Telefón / internet / digitálne predplatné', sumy: {} },
  'mes-vreckove':     { nazov: 'Vreckové', sumy: {} },
  'mes-zdravie':      { nazov: 'Lieky, doplnky výživy, zdravotná starostlivosť', sumy: {} },
};
const DEFAULT_VYDAVKY_ROCNE = {
  'roc-letnyT':       { nazov: 'Letný tábor / dovolenka', sumy: {} },
  'roc-zimnyT':       { nazov: 'Zimná dovolenka / lyžiarsky výcvik', sumy: {} },
  'roc-oblec':        { nazov: 'Sezónne oblečenie a obuv', sumy: {} },
  'roc-darceky':      { nazov: 'Vianoce a narodeniny (darčeky)', sumy: {} },
  'roc-ucebnice':     { nazov: 'Učebnice a školské pomôcky na začiatok školského roka', sumy: {} },
  'roc-stomato':      { nazov: 'Stomatologická starostlivosť (preventívne aj ošetrenia)', sumy: {} },
  'roc-okuliare':     { nazov: 'Okuliare alebo ortodontický aparát', sumy: {} },
  'roc-elektronika':  { nazov: 'Elektronika pre školu (notebook, tablet)', sumy: {} },
  'roc-kurzy':        { nazov: 'Mimoškolské kurzy a doučovanie', sumy: {} },
};
const DEFAULT_CL4 = {
  vydavkyMesacne: DEFAULT_VYDAVKY_MESACNE,
  vydavkyRocne: DEFAULT_VYDAVKY_ROCNE,
  navrhPomerStatus: 'a',           // 'a' Zamestnanec | 'b' SZČO | 'c' Spoločník | 'd' Nezamestnaný | 'e' Dôchodca | 'f' Mat./rod. dovolenka | 'g' Iné
  navrhPomerInecaste: '',          // pre status 'g' vlastný popis
  uvadzamPomerOdporcu: false,      // checkbox 4.5
};

const STATUS_LABELS = {
  a: 'Zamestnanec',
  b: 'SZČO / živnostník',
  c: 'Spoločník alebo konateľ obchodnej spoločnosti',
  d: 'Nezamestnaný / evidovaný uchádzač o zamestnanie',
  e: 'Dôchodca',
  f: 'Materská alebo rodičovská dovolenka',
  g: 'Iné',
};
const statusLabel = (s) => STATUS_LABELS[s] || STATUS_LABELS.a;

// Výpočtová funkcia 4.3 — sumarizácia za jedno dieťa.
const spocitajVydavky = (vydavkyMesacne, vydavkyRocne, kidId) => {
  const sumMap = (mapa) => Object.values(mapa || {}).reduce((acc, p) => {
    const v = parseFloat(((p && p.sumy) || {})[kidId] || '0') || 0;
    return acc + v;
  }, 0);
  const mesacne = sumMap(vydavkyMesacne);
  const rocne = sumMap(vydavkyRocne);
  const rocnePrepocitane = rocne / 12;
  const priemernaSumaMesacne = mesacne + rocnePrepocitane;
  return { mesacne, rocne, rocnePrepocitane, priemernaSumaMesacne };
};

// ============================================================
// 4.4 sample texty — 3 vzory × m/f. Selektor sample44(status, pNav)
// vráti príslušný text podľa pracovného statusu navrhovateľa.
// Status 'g' → null (žiadny vzor, len Ed block).
// ============================================================
const SAMPLE_44_VZOR1_M = 'V súčasnosti som zamestnaný v spoločnosti {{ZAMESTNAVATEL}} na pracovnej pozícii {{POZICIA}} na základe pracovnej zmluvy uzatvorenej dňa [dátum]. Môj priemerný čistý mesačný príjem za posledných 12 mesiacov predstavuje {{PRIJEM}} eur. Okrem hlavného pracovného pomeru poberám [iné príjmy / žiadne iné príjmy]. Vlastním nehnuteľnosť [bytovú jednotku / rodinný dom] na adrese [adresa], motorové vozidlo [značka, rok], a finančné prostriedky vo výške [suma] eur. Mám tieto záväzky: [hypotekárny úver / spotrebný úver / žiadne]. Okrem maloletých detí, ktoré sú predmetom tohto konania, mám [aj iné vyživovacie povinnosti / žiadne iné vyživovacie povinnosti].';

const SAMPLE_44_VZOR1_Z = 'V súčasnosti som zamestnaná v spoločnosti {{ZAMESTNAVATEL}} na pracovnej pozícii {{POZICIA}} na základe pracovnej zmluvy uzatvorenej dňa [dátum]. Môj priemerný čistý mesačný príjem za posledných 12 mesiacov predstavuje {{PRIJEM}} eur. Okrem hlavného pracovného pomeru poberám [iné príjmy / žiadne iné príjmy]. Vlastním nehnuteľnosť [bytovú jednotku / rodinný dom] na adrese [adresa], motorové vozidlo [značka, rok], a finančné prostriedky vo výške [suma] eur. Mám tieto záväzky: [hypotekárny úver / spotrebný úver / žiadne]. Okrem maloletých detí, ktoré sú predmetom tohto konania, mám [aj iné vyživovacie povinnosti / žiadne iné vyživovacie povinnosti].';

const SAMPLE_44_VZOR2_M = 'V súčasnosti som samostatne zárobkovo činnou osobou — vykonávam podnikateľskú činnosť na základe živnostenského oprávnenia, IČO [IČO], v predmete podnikania {{PREDMET}}. Môj čistý zisk po zdanení podľa daňového priznania za rok [rok] predstavoval [suma] eur, čo zodpovedá priemernému mesačnému čistému príjmu {{PRIJEM}} eur. Okrem podnikateľskej činnosti [poberám / nepoberám] iné príjmy. Vlastním nehnuteľnosť [adresa], motorové vozidlo [značka], finančné prostriedky vo výške [suma] eur. Mám tieto záväzky: [úver / leasing / žiadne]. Okrem maloletých detí, ktoré sú predmetom tohto konania, mám [aj iné vyživovacie povinnosti / žiadne iné vyživovacie povinnosti].';

const SAMPLE_44_VZOR2_Z = 'V súčasnosti som samostatne zárobkovo činnou osobou — vykonávam podnikateľskú činnosť na základe živnostenského oprávnenia, IČO [IČO], v predmete podnikania {{PREDMET}}. Môj čistý zisk po zdanení podľa daňového priznania za rok [rok] predstavoval [suma] eur, čo zodpovedá priemernému mesačnému čistému príjmu {{PRIJEM}} eur. Okrem podnikateľskej činnosti [poberám / nepoberám] iné príjmy. Vlastním nehnuteľnosť [adresa], motorové vozidlo [značka], finančné prostriedky vo výške [suma] eur. Mám tieto záväzky: [úver / leasing / žiadne]. Okrem maloletých detí, ktoré sú predmetom tohto konania, mám [aj iné vyživovacie povinnosti / žiadne iné vyživovacie povinnosti].';

const SAMPLE_44_VZOR3_M = 'V súčasnosti som nezamestnaný. [Som / nie som] evidovaný ako uchádzač o zamestnanie na Úrade práce, sociálnych vecí a rodiny [príslušný úrad] od [dátum evidencie]. [Poberám dávku v nezamestnanosti vo výške {{PRIJEM}} eur mesačne / Nepoberám dávku v nezamestnanosti.] Okrem toho [poberám / nepoberám] [pomoc v hmotnej núdzi / dávku sociálneho poistenia / iné dávky] vo výške [suma] eur mesačne. Vlastním nehnuteľnosť [adresa / žiadnu], motorové vozidlo [značka / žiadne], finančné prostriedky vo výške [suma] eur. Mám tieto záväzky: [úver / žiadne]. Okrem maloletých detí, ktoré sú predmetom tohto konania, mám [aj iné vyživovacie povinnosti / žiadne]. Aktívne hľadám zamestnanie.';

const SAMPLE_44_VZOR3_Z = 'V súčasnosti som nezamestnaná. [Som / nie som] evidovaná ako uchádzačka o zamestnanie na Úrade práce, sociálnych vecí a rodiny [príslušný úrad] od [dátum evidencie]. [Poberám dávku v nezamestnanosti vo výške {{PRIJEM}} eur mesačne / Nepoberám dávku v nezamestnanosti.] Okrem toho [poberám / nepoberám] [pomoc v hmotnej núdzi / dávku sociálneho poistenia / iné dávky] vo výške [suma] eur mesačne. Vlastním nehnuteľnosť [adresa / žiadnu], motorové vozidlo [značka / žiadne], finančné prostriedky vo výške [suma] eur. Mám tieto záväzky: [úver / žiadne]. Okrem maloletých detí, ktoré sú predmetom tohto konania, mám [aj iné vyživovacie povinnosti / žiadne]. Aktívne hľadám zamestnanie.';

// VZOR_C — Spoločník/konateľ obchodnej spoločnosti (status 'c').
const SAMPLE_44_VZOR_C_M = 'V súčasnosti som {{POSTAVENIE}} obchodnej spoločnosti {{OBCHODNE_MENO}}. Môj priemerný čistý mesačný príjem (vrátane podielu na zisku/odmeny konateľa) za posledných 12 mesiacov predstavuje {{PRIJEM}} eur. Okrem toho [poberám / nepoberám] iné príjmy. Vlastním nehnuteľnosť [adresa / žiadnu], motorové vozidlo [značka / žiadne], finančné prostriedky vo výške [suma] eur. Mám tieto záväzky: [úver / leasing / žiadne]. Okrem maloletých detí, ktoré sú predmetom tohto konania, mám [aj iné vyživovacie povinnosti / žiadne iné vyživovacie povinnosti].';
const SAMPLE_44_VZOR_C_Z = 'V súčasnosti som {{POSTAVENIE}} obchodnej spoločnosti {{OBCHODNE_MENO}}. Môj priemerný čistý mesačný príjem (vrátane podielu na zisku/odmeny konateľky) za posledných 12 mesiacov predstavuje {{PRIJEM}} eur. Okrem toho [poberám / nepoberám] iné príjmy. Vlastním nehnuteľnosť [adresa / žiadnu], motorové vozidlo [značka / žiadne], finančné prostriedky vo výške [suma] eur. Mám tieto záväzky: [úver / leasing / žiadne]. Okrem maloletých detí, ktoré sú predmetom tohto konania, mám [aj iné vyživovacie povinnosti / žiadne iné vyživovacie povinnosti].';

// VZOR_E — Dôchodca (status 'e').
const SAMPLE_44_VZOR_E_M = 'V súčasnosti som dôchodca. Poberám [starobný / invalidný / výsluhový] dôchodok vo výške {{PRIJEM}} eur mesačne. Okrem toho [poberám / nepoberám] iné príjmy. Vlastním nehnuteľnosť [adresa / žiadnu], motorové vozidlo [značka / žiadne], finančné prostriedky vo výške [suma] eur. Mám tieto záväzky: [úver / žiadne]. Okrem maloletých detí, ktoré sú predmetom tohto konania, mám [aj iné vyživovacie povinnosti / žiadne].';
const SAMPLE_44_VZOR_E_Z = 'V súčasnosti som dôchodkyňa. Poberám [starobný / invalidný / výsluhový] dôchodok vo výške {{PRIJEM}} eur mesačne. Okrem toho [poberám / nepoberám] iné príjmy. Vlastním nehnuteľnosť [adresa / žiadnu], motorové vozidlo [značka / žiadne], finančné prostriedky vo výške [suma] eur. Mám tieto záväzky: [úver / žiadne]. Okrem maloletých detí, ktoré sú predmetom tohto konania, mám [aj iné vyživovacie povinnosti / žiadne].';

// VZOR_F — Materská/rodičovská dovolenka (status 'f').
const SAMPLE_44_VZOR_F_M = 'V súčasnosti čerpám rodičovskú dovolenku. Poberám rodičovský príspevok vo výške {{PRIJEM}} eur mesačne. Okrem toho [poberám / nepoberám] iné príjmy. Vlastním nehnuteľnosť [adresa / žiadnu], motorové vozidlo [značka / žiadne], finančné prostriedky vo výške [suma] eur. Mám tieto záväzky: [úver / žiadne]. Okrem maloletých detí, ktoré sú predmetom tohto konania, mám [aj iné vyživovacie povinnosti / žiadne].';
const SAMPLE_44_VZOR_F_Z = 'V súčasnosti čerpám materskú/rodičovskú dovolenku. Poberám [materské / rodičovský príspevok] vo výške {{PRIJEM}} eur mesačne. Okrem toho [poberám / nepoberám] iné príjmy. Vlastním nehnuteľnosť [adresa / žiadnu], motorové vozidlo [značka / žiadne], finančné prostriedky vo výške [suma] eur. Mám tieto záväzky: [úver / žiadne]. Okrem maloletých detí, ktoré sú predmetom tohto konania, mám [aj iné vyživovacie povinnosti / žiadne].';

// HTML escape pre hodnoty polí, ktoré dosádzame do sample44 cez innerHTML
// (variant C — bold pre vyplnené polia). Bez tohto by ampersand alebo lomené
// zátvorky v hodnote rozbili HTML alebo otvorili XSS.
const escapeHtml = (s) => String(s)
  .replace(/&/g, '&amp;')
  .replace(/</g, '&lt;')
  .replace(/>/g, '&gt;');

// Mapa: ktoré polia 4.4 sú viditeľné pri ktorom statuse.
// 'prijem' je vždy viditeľné, ostatné podľa statusu.
const STATUS_FIELDS_44 = {
  a: { zamestnavatel: true, pozicia: true, prijem: true },
  b: { predmet: true, prijem: true },
  c: { obchodneMeno: true, postavenie: true, prijem: true },
  d: { prijem: true },
  e: { prijem: true },
  f: { prijem: true },
  g: { prijem: true },
};

const sample44 = (status, pNav, fields = {}) => {
  const z = pNav === 'zena';
  let tpl;
  if (status === 'a') tpl = z ? SAMPLE_44_VZOR1_Z : SAMPLE_44_VZOR1_M;
  else if (status === 'b') tpl = z ? SAMPLE_44_VZOR2_Z : SAMPLE_44_VZOR2_M;
  else if (status === 'c') tpl = z ? SAMPLE_44_VZOR_C_Z : SAMPLE_44_VZOR_C_M;
  else if (status === 'd') tpl = z ? SAMPLE_44_VZOR3_Z : SAMPLE_44_VZOR3_M;
  else if (status === 'e') tpl = z ? SAMPLE_44_VZOR_E_Z : SAMPLE_44_VZOR_E_M;
  else if (status === 'f') tpl = z ? SAMPLE_44_VZOR_F_Z : SAMPLE_44_VZOR_F_M;
  else if (status === 'g') return null;
  else tpl = z ? SAMPLE_44_VZOR1_Z : SAMPLE_44_VZOR1_M;
  // Vyplnené pole → <strong>{escaped}</strong>. Prázdne → fallback v hranatých
  // zátvorkách bez bold (signalizuje používateľovi, že hodnotu má doplniť).
  const get = (k, fallback) => {
    const v = fields[k] && String(fields[k]).trim();
    return v ? `<strong>${escapeHtml(v)}</strong>` : fallback;
  };
  return tpl
    .replace('{{ZAMESTNAVATEL}}',  get('zamestnavatel', '[názov a sídlo zamestnávateľa]'))
    .replace('{{POZICIA}}',        get('pozicia',       '[pozícia]'))
    .replace('{{PREDMET}}',        get('predmet',       '[predmet podnikania]'))
    .replace('{{OBCHODNE_MENO}}',  get('obchodneMeno',  '[obchodné meno spoločnosti]'))
    .replace('{{POSTAVENIE}}',     get('postavenie',    '[postavenie — spoločník / konateľ]'))
    .replace('{{PRIJEM}}',         get('prijem',        '[suma]'));
};

// Čl. III state — radio/select/checkbox voľby pre formu starostlivosti,
// zverenie, výživné a styk. Mapy výživného sú indexované cez kid.id
// (synchronizované so zoznamom detí).
const CL3_STORAGE_KEY = 'vyzivnenadieta.cl3-zmena.v1';
// Splatnosť výživného sa v praxi určuje fixne na 15. deň v mesiaci vopred —
// neukladáme to ako voľbu (FÁZA B simplification).
const DEFAULT_VYZIVNE_ROW = { suma: '' };
const DEFAULT_CL3 = {
  formaStarostlivosti: 'a',           // 'a' (jeden rodič) | 'b' (striedavá) | 'c' (spoločná)
  zvereniePri_a: 'navrhovatel',       // 'navrhovatel' | 'odporca'
  typStriedania: '1tyz',              // '1tyz' (predvyplnený vzor) | 'vlastne' (4 Ed bloky)
  rezimVyzivnehoPri_b: 'i',           // 'i' (od druhého) | 'ii' (nežiadame)
  rezimVyzivnehoPri_c: 'i',           // 'i' | 'ii'
  vyzivne: {},                        // { [kidId]: { suma } }
  styk: 'i',                          // 'i' (súdom) | 'ii' (mimosúdne)
  // Zastupovanie a správa majetku — § 28 ods. 1, § 31 ods. 1 ZoR.
  // Default sa odvodí z formy/zverenia/pohlavia, ale userTouchedZastupovanie
  // uzamkne ďalšie auto-zmeny po prvom explicit prepnutí radio-u.
  zastupovanie: 'obaja',              // 'obaja' | 'matka' | 'otec'
  userTouchedZastupovanie: false,
};

const PaperZmena = ({ doctype, navrhovatel, setNavrhovatel, odporca, setOdporca, setActiveArticle, setActiveTipKey, onTipClick, activeTipKey }) => {
  const [menoNavrhovatela, setMenoNavrhovatela] = React.useState('');
  const [menoOdporcu, setMenoOdporcu] = React.useState('');
  const [rodnePriezvisko, setRodnePriezvisko] = React.useState('');
  const [dalsieDokazy, setDalsieDokazy] = React.useState('');
  // Hydrácia kids zo storage pri prvom rendere — vždy aspoň jedno dieťa.
  const [kids, setKids] = React.useState(() => {
    try {
      const raw = localStorage.getItem(KIDS_STORAGE_KEY);
      if (raw) {
        const parsed = JSON.parse(raw);
        if (Array.isArray(parsed) && parsed.length > 0) {
          return parsed.map(k => (k && typeof k === 'object' && k.id)
            ? { id: k.id, meno: k.meno || '', datumNarodenia: k.datumNarodenia || '', bytom: k.bytom || '' }
            : newKid());
        }
      }
    } catch (e) {}
    return [newKid()];
  });
  React.useEffect(() => {
    try { localStorage.setItem(KIDS_STORAGE_KEY, JSON.stringify(kids)); } catch (e) {}
  }, [kids]);
  const addKid = () => setKids(prev => [...prev, newKid()]);
  const removeKid = (id) => setKids(prev => prev.length > 1 ? prev.filter(k => k.id !== id) : prev);
  const updateKid = (id, field, value) => setKids(prev => prev.map(k => k.id === id ? { ...k, [field]: value } : k));
  // Derivovaný pohľad: dieťa sa považuje za "vyplnené" ak má aspoň jeden
  // non-empty údaj. Prázdne defaultné dieťa (zo state inicializácie alebo
  // čerstvo pridané, ale needitované) sa do textu Čl. I 1.1 neprenesie.
  const filledKids = kids.filter(k =>
    k.meno.trim() !== '' || k.datumNarodenia.trim() !== '' || k.bytom.trim() !== ''
  );

  // Pohlavie navrhovateľa (jediný vstup; pohlavie odporcu = opak, § 1 ZoR).
  // Hydrácia + perzistencia v META_STORAGE_KEY; userTouchedGender uzamkne
  // autodetekciu z priezviska potom, čo používateľ explicitne prepol radio.
  const [navrhovatelPohlavie, setNavrhovatelPohlavieRaw] = React.useState(() => {
    try {
      const raw = localStorage.getItem(META_STORAGE_KEY);
      if (raw) {
        const m = JSON.parse(raw);
        if (m && (m.navrhovatelPohlavie === 'muz' || m.navrhovatelPohlavie === 'zena')) {
          return m.navrhovatelPohlavie;
        }
      }
    } catch (e) {}
    return 'zena';
  });
  const [userTouchedGender, setUserTouchedGender] = React.useState(() => {
    try {
      const raw = localStorage.getItem(META_STORAGE_KEY);
      if (raw) {
        const m = JSON.parse(raw);
        return !!(m && m.userTouchedGender);
      }
    } catch (e) {}
    return false;
  });
  React.useEffect(() => {
    try {
      localStorage.setItem(META_STORAGE_KEY, JSON.stringify({ navrhovatelPohlavie, userTouchedGender }));
    } catch (e) {}
  }, [navrhovatelPohlavie, userTouchedGender]);

  // User-facing setter (UI radio) — uzamkne autodetekciu.
  const setNavrhovatelPohlavie = (g) => {
    setNavrhovatelPohlavieRaw(g);
    setUserTouchedGender(true);
  };

  // Autodetekcia z priezviska — beží iba kým user nestlačí radio. Po explicit
  // prepnutí ostáva flag userTouchedGender = true, autodetekcia ďalej nebeží.
  React.useEffect(() => {
    if (userTouchedGender) return;
    const detected = detectGenderFromName(menoNavrhovatela);
    if (detected && detected !== navrhovatelPohlavie) {
      setNavrhovatelPohlavieRaw(detected);
    }
  }, [menoNavrhovatela, userTouchedGender]);

  // Pohlavie odporcu = opak navrhovateľa. Manželstvo = zväzok muža a ženy
  // (§ 1 ods. 1 ZoR), takže pri zmene pohlavia navrhovateľa sa odporca
  // automaticky prepne. Žiadny samostatný vstup pre odporcu.
  const odporcaPohlavie = navrhovatelPohlavie === 'muz' ? 'zena' : 'muz';

  // ----------------------------------------------------------------
  // Čl. II — Doterajšia úprava pomerov rozhodnutím súdu.
  // Prvý súd (povinný) + voliteľný druhý súd (krajský v odvolaní).
  // Každý: { nazov, druh: 'rozsudok'|'uznesenie', sznacka, datum, popis }.
  // ----------------------------------------------------------------
  const [sud1, setSud1] = React.useState(() => {
    try {
      const raw = localStorage.getItem(CL2_SUD_KEY);
      if (raw) {
        const p = JSON.parse(raw);
        if (p && typeof p === 'object') return {
          nazov: p.nazov || '', druh: p.druh === 'rozsudok' ? 'rozsudok' : 'uznesenie',
          sznacka: p.sznacka || '', datum: p.datum || '', popis: p.popis || '',
        };
      }
    } catch (e) {}
    return { nazov: '', druh: 'uznesenie', sznacka: '', datum: '', popis: '' };
  });
  React.useEffect(() => {
    try { localStorage.setItem(CL2_SUD_KEY, JSON.stringify(sud1)); } catch (e) {}
  }, [sud1]);

  const [sud2, setSud2] = React.useState(() => {
    try {
      const raw = localStorage.getItem(CL2_SUD2_KEY);
      if (raw) {
        const p = JSON.parse(raw);
        if (p && typeof p === 'object' && p.aktivny) return {
          aktivny: true,
          nazov: p.nazov || '', druh: p.druh === 'rozsudok' ? 'rozsudok' : 'uznesenie',
          sznacka: p.sznacka || '', datum: p.datum || '', popis: p.popis || '',
        };
      }
    } catch (e) {}
    return { aktivny: false, nazov: '', druh: 'uznesenie', sznacka: '', datum: '', popis: '' };
  });
  React.useEffect(() => {
    try { localStorage.setItem(CL2_SUD2_KEY, JSON.stringify(sud2)); } catch (e) {}
  }, [sud2]);

  const updateSud1 = (field, value) => setSud1(s => ({ ...s, [field]: value }));
  const updateSud2 = (field, value) => setSud2(s => ({ ...s, [field]: value }));
  const aktivovatSud2 = () => setSud2(s => ({ ...s, aktivny: true }));
  const odstranitSud2 = () => setSud2(s => ({ ...s, aktivny: false, nazov: '', sznacka: '', datum: '', popis: '' }));

  // ----------------------------------------------------------------
  // Čl. III — Zmena pomerov a návrh úpravy.
  // 3.1 výber 4 checkboxov, 3.2 popis zmeny pomerov, 3.3 zverenie,
  // 3.4 výživné, 3.5 zastupovanie, 3.6 styk. Každá podsekcia má vlastný
  // storage key, podmienečne sa zobrazuje podľa zaškrtnutých 3.1 boxov.
  // ----------------------------------------------------------------
  const [zmenaVyber, setZmenaVyber] = React.useState(() => {
    try {
      const raw = localStorage.getItem(CL3Z_VYBER_KEY);
      if (raw) {
        const p = JSON.parse(raw);
        if (p && typeof p === 'object') return {
          zverenie: !!p.zverenie, vyzivne: !!p.vyzivne,
          zastupovanie: !!p.zastupovanie, styk: !!p.styk,
        };
      }
    } catch (e) {}
    return { zverenie: false, vyzivne: false, zastupovanie: false, styk: false };
  });
  React.useEffect(() => {
    try { localStorage.setItem(CL3Z_VYBER_KEY, JSON.stringify(zmenaVyber)); } catch (e) {}
  }, [zmenaVyber]);
  const toggleZmena = (kluc) => setZmenaVyber(v => ({ ...v, [kluc]: !v[kluc] }));

  // 3.2 popis zmeny pomerov — Ed block s vlastným ref + storage.
  const cl3z2_Ref = React.useRef(null);
  const [cl3z2Content, setCl3z2Content] = React.useState(() => {
    try { return localStorage.getItem(CL3Z_POPIS_KEY) || ''; } catch (e) { return ''; }
  });
  React.useEffect(() => {
    try { localStorage.setItem(CL3Z_POPIS_KEY, cl3z2Content); } catch (e) {}
  }, [cl3z2Content]);
  React.useEffect(() => {
    if (cl3z2_Ref.current && cl3z2Content && !cl3z2_Ref.current.textContent) {
      cl3z2_Ref.current.textContent = cl3z2Content;
      cl3z2_Ref.current.dispatchEvent(new Event('input', { bubbles: true }));
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // 3.3 zverenie — radio + odôvodnenie textarea.
  const [cl3z3, setCl3z3] = React.useState(() => {
    try {
      const raw = localStorage.getItem(CL3Z_3_KEY);
      if (raw) { const p = JSON.parse(raw); if (p && typeof p === 'object') return { novaForma: p.novaForma || '', odovodnenie: p.odovodnenie || '' }; }
    } catch (e) {}
    return { novaForma: '', odovodnenie: '' };
  });
  React.useEffect(() => {
    try { localStorage.setItem(CL3Z_3_KEY, JSON.stringify(cl3z3)); } catch (e) {}
  }, [cl3z3]);
  const cl3z3_Ref = React.useRef(null);
  React.useEffect(() => {
    if (cl3z3_Ref.current && cl3z3.odovodnenie && !cl3z3_Ref.current.textContent) {
      cl3z3_Ref.current.textContent = cl3z3.odovodnenie;
      cl3z3_Ref.current.dispatchEvent(new Event('input', { bubbles: true }));
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // 3.4 výživné — per-dieťa štruktúra. Stará plochá štruktúra (staraVyska/novaVyska
  // na top-level) sa pri hydratácii zahodí (migrácia). Splatnosť odstránená.
  const [cl3z4, setCl3z4] = React.useState(() => {
    try {
      const raw = localStorage.getItem(CL3Z_4_KEY);
      if (raw) {
        const p = JSON.parse(raw);
        if (p && typeof p === 'object') {
          // Nový formát — perDieta mapa.
          if (p.perDieta && typeof p.perDieta === 'object') {
            return { perDieta: p.perDieta, odovodnenie: p.odovodnenie || '' };
          }
          // Starý formát (plochý) — zahoď, vráť default. Odôvodnenie zachovaj.
          return { perDieta: {}, odovodnenie: p.odovodnenie || '' };
        }
      }
    } catch (e) {}
    return { perDieta: {}, odovodnenie: '' };
  });
  React.useEffect(() => {
    try { localStorage.setItem(CL3Z_4_KEY, JSON.stringify(cl3z4)); } catch (e) {}
  }, [cl3z4]);
  const updateCl3z4Odovodnenie = (value) => setCl3z4(s => ({ ...s, odovodnenie: value }));
  const updateCl3z4PerDieta = (kidId, field, value) => setCl3z4(s => ({
    ...s,
    perDieta: {
      ...(s.perDieta || {}),
      [kidId]: { ...((s.perDieta || {})[kidId] || { typZmeny: '', staraVyska: '', novaVyska: '' }), [field]: value },
    },
  }));
  const getCl3z4PerDieta = (kidId) => {
    const r = (cl3z4.perDieta || {})[kidId] || {};
    return { typZmeny: r.typZmeny || '', staraVyska: r.staraVyska || '', novaVyska: r.novaVyska || '' };
  };
  const cl3z4_Ref = React.useRef(null);
  React.useEffect(() => {
    if (cl3z4_Ref.current && cl3z4.odovodnenie && !cl3z4_Ref.current.textContent) {
      cl3z4_Ref.current.textContent = cl3z4.odovodnenie;
      cl3z4_Ref.current.dispatchEvent(new Event('input', { bubbles: true }));
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // 3.5 zastupovanie.
  const [cl3z5, setCl3z5] = React.useState(() => {
    try {
      const raw = localStorage.getItem(CL3Z_5_KEY);
      if (raw) { const p = JSON.parse(raw); if (p && typeof p === 'object') return { noveZastupovanie: p.noveZastupovanie || '', odovodnenie: p.odovodnenie || '' }; }
    } catch (e) {}
    return { noveZastupovanie: '', odovodnenie: '' };
  });
  React.useEffect(() => {
    try { localStorage.setItem(CL3Z_5_KEY, JSON.stringify(cl3z5)); } catch (e) {}
  }, [cl3z5]);
  const cl3z5_Ref = React.useRef(null);
  React.useEffect(() => {
    if (cl3z5_Ref.current && cl3z5.odovodnenie && !cl3z5_Ref.current.textContent) {
      cl3z5_Ref.current.textContent = cl3z5.odovodnenie;
      cl3z5_Ref.current.dispatchEvent(new Event('input', { bubbles: true }));
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // 3.6 styk — aktuálna úprava + nová úprava + odôvodnenie.
  const [cl3z6, setCl3z6] = React.useState(() => {
    try {
      const raw = localStorage.getItem(CL3Z_6_KEY);
      if (raw) { const p = JSON.parse(raw); if (p && typeof p === 'object') return {
        aktualnyStyk: p.aktualnyStyk || '', novyStyk: p.novyStyk || '', odovodnenie: p.odovodnenie || '',
      }; }
    } catch (e) {}
    return { aktualnyStyk: '', novyStyk: '', odovodnenie: '' };
  });
  React.useEffect(() => {
    try { localStorage.setItem(CL3Z_6_KEY, JSON.stringify(cl3z6)); } catch (e) {}
  }, [cl3z6]);
  const updateCl3z6 = (field, value) => setCl3z6(s => ({ ...s, [field]: value }));
  const cl3z6_Aktualny_Ref = React.useRef(null);
  const cl3z6_Novy_Ref = React.useRef(null);
  const cl3z6_Odov_Ref = React.useRef(null);
  React.useEffect(() => {
    if (cl3z6_Aktualny_Ref.current && cl3z6.aktualnyStyk && !cl3z6_Aktualny_Ref.current.textContent) {
      cl3z6_Aktualny_Ref.current.textContent = cl3z6.aktualnyStyk;
      cl3z6_Aktualny_Ref.current.dispatchEvent(new Event('input', { bubbles: true }));
    }
    if (cl3z6_Novy_Ref.current && cl3z6.novyStyk && !cl3z6_Novy_Ref.current.textContent) {
      cl3z6_Novy_Ref.current.textContent = cl3z6.novyStyk;
      cl3z6_Novy_Ref.current.dispatchEvent(new Event('input', { bubbles: true }));
    }
    if (cl3z6_Odov_Ref.current && cl3z6.odovodnenie && !cl3z6_Odov_Ref.current.textContent) {
      cl3z6_Odov_Ref.current.textContent = cl3z6.odovodnenie;
      cl3z6_Odov_Ref.current.dispatchEvent(new Event('input', { bubbles: true }));
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Helper na vloženie sample textu do daného Ed bloku (s placeholderov).
  const fillSampleZmena = (refEl, sampleTemplate, vars, trackingMeta) => {
    if (!refEl || !refEl.current) return;
    const text = fillTemplateZmena(sampleTemplate, vars);
    refEl.current.textContent = text;
    refEl.current.dispatchEvent(new Event('input', { bubbles: true }));
    if (trackingMeta && typeof window.trackEvent === 'function') {
      window.trackEvent('use_sample', trackingMeta);
    }
  };

  // ----------------------------------------------------------------
  // Čl. III (Maloleté deti) — refs pre Ed bloky, state radio/select/checkbox
  // volieb, toggles pre sample panely, helpers pre tabuľky výživného.
  // ----------------------------------------------------------------
  const cl3_311_Ref = React.useRef(null);
  const cl3_312_Ref = React.useRef(null);
  const cl3_32_Ref = React.useRef(null);
  const cl3_33c_Ref = React.useRef(null);   // opis fungovania spoločnej starostlivosti
  // 3.3(b) striedavá — JEDEN Ed block. Sample obsah (4 sekcie) sa generuje
  // dynamicky a vkladá cez "Použiť tento text" (rovnaký pattern ako 2.1–2.4).
  const cl3_33b_Ref = React.useRef(null);
  // Auto-clear pri prepnutí radio typStriedania — predošlú hodnotu držíme
  // v useRef. POZOR: ref sa inicializuje na `undefined` sentinel, NIE na
  // `cl3.typStriedania` — `cl3` je definované cez useState NIŽŠIE v komponente
  // (TDZ by inak hodil ReferenceError a celý komponent by sa zrútil).
  // Prvý beh useEffectu sentinel vymení za aktuálnu hodnotu a skipne čistenie.
  const cl3_33b_typPrev = React.useRef();
  const cl3_35_Ref = React.useRef(null);    // opis styku (3.5(i))
  // Obsah Ed blokov 3.3(b) striedavky-vlastné a 3.5 styk — uncontrolled
  // .ed[contentEditable] elementy ich nedržia v React state (Persist.jsx
  // ich ukladá na input event). Pre petit potrebujeme ich obsah, takže
  // držíme zrkadlový state cez document-level input listener (matching
  // podľa unikátneho data-placeholder atribútu).
  const [ed33bContent, setEd33bContent] = React.useState('');
  const [ed33cContent, setEd33cContent] = React.useState('');
  const [ed35Content, setEd35Content] = React.useState('');
  const [ed4DokazyContent, setEd4DokazyContent] = React.useState('');
  React.useEffect(() => {
    const PH_33B = "Sem vložte text striedavej osobnej starostlivosti — kliknite na 'Použiť vzorový text' alebo napíšte vlastný text.";
    const PH_33C = "Sem vložte opis dohodnutého fungovania spoločnej osobnej starostlivosti — kliknite na 'Použiť vzorový text' alebo napíšte vlastný text.";
    const PH_35 = 'Opis navrhovaného styku (3.5) — váš text alebo použite vzor vyššie...';
    const PH_4DOKAZY = 'Sem napíšte zoznam dôkazov, každý dôkaz na samostatný riadok. Napríklad: potvrdenie o priemernom čistom mesačnom zárobku od zamestnávateľa, daňové priznanie za minulý rok, výpis z katastra nehnuteľností, potvrdenie z úradu práce o evidencii a výške dávky v nezamestnanosti.';
    const sync = (el) => {
      if (!el || !el.dataset) return;
      const ph = el.dataset.placeholder;
      if (ph === PH_33B) setEd33bContent(el.textContent || '');
      else if (ph === PH_33C) setEd33cContent(el.textContent || '');
      else if (ph === PH_35) setEd35Content(el.textContent || '');
      else if (ph === PH_4DOKAZY) setEd4DokazyContent(el.textContent || '');
    };
    const handler = (e) => sync(e.target);
    document.addEventListener('input', handler, true);
    // Initial sync — po Persist.jsx hydrácii (~150ms timeout interne)
    // prejdeme všetky .ed elementy a syncneme ich obsah do state-u.
    const tInit = setTimeout(() => {
      document.querySelectorAll('.ed[data-placeholder]').forEach(sync);
    }, 300);
    return () => {
      document.removeEventListener('input', handler, true);
      clearTimeout(tInit);
    };
  }, []);

  // Hydrácia + perzistencia cl3 state z vlastného localStorage kľúča
  // (Persist.jsx ukladá iba contentEditable; non-Ed state má vlastnú JSON
  // serializáciu, analogicky k META_STORAGE_KEY a KIDS_STORAGE_KEY).
  const [cl3, setCl3] = React.useState(() => {
    try {
      const raw = localStorage.getItem(CL3_STORAGE_KEY);
      if (raw) {
        const parsed = JSON.parse(raw);
        if (parsed && typeof parsed === 'object') {
          return { ...DEFAULT_CL3, ...parsed };
        }
      }
    } catch (e) {}
    return DEFAULT_CL3;
  });
  React.useEffect(() => {
    try { localStorage.setItem(CL3_STORAGE_KEY, JSON.stringify(cl3)); } catch (e) {}
  }, [cl3]);

  // Pri odstránení dieťaťa z parties-table sa zahodia jeho záznamy výživného.
  React.useEffect(() => {
    const validIds = new Set(kids.map(k => k.id));
    setCl3(prev => {
      const filterMap = (m) => Object.fromEntries(
        Object.entries(m || {}).filter(([k]) => validIds.has(k))
      );
      const nextVyzivne = filterMap(prev.vyzivne);
      // Pri rovnosti nemeníme referenciu — predíde infinite loopu.
      if (Object.keys(nextVyzivne).length === Object.keys(prev.vyzivne || {}).length) return prev;
      return { ...prev, vyzivne: nextVyzivne };
    });
  }, [kids]);

  // Helpers pre výživné mapu (suma per kid).
  const getVyzivne = (kidId) => ({ ...DEFAULT_VYZIVNE_ROW, ...((cl3.vyzivne || {})[kidId] || {}) });
  const setVyzivneSuma = (kidId, value) => {
    setCl3(prev => ({
      ...prev,
      vyzivne: {
        ...(prev.vyzivne || {}),
        [kidId]: { ...DEFAULT_VYZIVNE_ROW, ...((prev.vyzivne || {})[kidId] || {}), suma: value },
      },
    }));
  };
  const setCl3Field = (field, value) => setCl3(prev => ({ ...prev, [field]: value }));

  // Setter pre zastupovanie — uzamkne flag userTouchedZastupovanie, takže
  // ďalšie zmeny formy/zverenia/pohlavia už nepreklopia voľbu späť.
  const setZastupovanie = (val) =>
    setCl3(prev => ({ ...prev, zastupovanie: val, userTouchedZastupovanie: true }));

  // Default zastupovania sa updatuje pri zmene formaStarostlivosti / zverenia /
  // navrhovatelPohlavie — ALE iba kým userTouchedZastupovanie === false.
  React.useEffect(() => {
    if (cl3.userTouchedZastupovanie) return;
    const next = computeZastupovanieDefault(
      cl3.formaStarostlivosti,
      cl3.zvereniePri_a,
      navrhovatelPohlavie
    );
    if (cl3.zastupovanie !== next) {
      setCl3(prev => ({ ...prev, zastupovanie: next }));
    }
  }, [cl3.formaStarostlivosti, cl3.zvereniePri_a, navrhovatelPohlavie, cl3.userTouchedZastupovanie]);

  // ----------------------------------------------------------------
  // Čl. IV state — pomery rodičov a výdavky.
  // ----------------------------------------------------------------
  const [cl4, setCl4] = React.useState(() => {
    try {
      const raw = localStorage.getItem(CL4_STORAGE_KEY);
      if (raw) {
        const parsed = JSON.parse(raw);
        if (parsed && typeof parsed === 'object') {
          return {
            ...DEFAULT_CL4,
            ...parsed,
            // Hlboký spread máp výdavkov — predchádza strate pridaných položiek po DEFAULT spread.
            vydavkyMesacne: (parsed.vydavkyMesacne && Object.keys(parsed.vydavkyMesacne).length > 0)
              ? parsed.vydavkyMesacne : DEFAULT_VYDAVKY_MESACNE,
            vydavkyRocne: (parsed.vydavkyRocne && Object.keys(parsed.vydavkyRocne).length > 0)
              ? parsed.vydavkyRocne : DEFAULT_VYDAVKY_ROCNE,
          };
        }
      }
    } catch (e) {}
    return DEFAULT_CL4;
  });
  React.useEffect(() => {
    try { localStorage.setItem(CL4_STORAGE_KEY, JSON.stringify(cl4)); } catch (e) {}
  }, [cl4]);

  // Pri odstránení dieťaťa z parties-table cleanup .sumy[zaniknutyKidId]
  // vo všetkých položkách oboch máp (mesačné aj ročné).
  React.useEffect(() => {
    const validIds = new Set(kids.map(k => k.id));
    setCl4(prev => {
      let changed = false;
      const cleanMap = (mapa) => {
        const out = {};
        Object.entries(mapa || {}).forEach(([pid, polozka]) => {
          const oldSumy = polozka.sumy || {};
          const newSumy = Object.fromEntries(
            Object.entries(oldSumy).filter(([kid]) => validIds.has(kid))
          );
          if (Object.keys(newSumy).length !== Object.keys(oldSumy).length) changed = true;
          out[pid] = { ...polozka, sumy: newSumy };
        });
        return out;
      };
      const nextMes = cleanMap(prev.vydavkyMesacne);
      const nextRoc = cleanMap(prev.vydavkyRocne);
      if (!changed) return prev;
      return { ...prev, vydavkyMesacne: nextMes, vydavkyRocne: nextRoc };
    });
  }, [kids]);

  // Helpers pre Čl. IV.
  const setCl4Field = (field, value) => setCl4(prev => ({ ...prev, [field]: value }));
  const setVydavokSuma = (typ, polozkaId, kidId, sumaStr) => {
    const mapKey = typ === 'mesacne' ? 'vydavkyMesacne' : 'vydavkyRocne';
    setCl4(prev => ({
      ...prev,
      [mapKey]: {
        ...(prev[mapKey] || {}),
        [polozkaId]: {
          ...((prev[mapKey] || {})[polozkaId] || { nazov: '', sumy: {} }),
          sumy: {
            ...(((prev[mapKey] || {})[polozkaId] || {}).sumy || {}),
            [kidId]: sumaStr,
          },
        },
      },
    }));
  };
  const setVydavokNazov = (typ, polozkaId, nazov) => {
    const mapKey = typ === 'mesacne' ? 'vydavkyMesacne' : 'vydavkyRocne';
    setCl4(prev => ({
      ...prev,
      [mapKey]: {
        ...(prev[mapKey] || {}),
        [polozkaId]: {
          ...((prev[mapKey] || {})[polozkaId] || { sumy: {} }),
          nazov,
        },
      },
    }));
  };
  const addPolozka = (typ) => {
    const mapKey = typ === 'mesacne' ? 'vydavkyMesacne' : 'vydavkyRocne';
    const prefix = typ === 'mesacne' ? 'mes-custom-' : 'roc-custom-';
    const id = prefix + Math.random().toString(36).slice(2, 8);
    setCl4(prev => ({
      ...prev,
      [mapKey]: { ...(prev[mapKey] || {}), [id]: { nazov: '', sumy: {} } },
    }));
  };
  const removePolozka = (typ, polozkaId) => {
    const mapKey = typ === 'mesacne' ? 'vydavkyMesacne' : 'vydavkyRocne';
    setCl4(prev => {
      const next = { ...(prev[mapKey] || {}) };
      delete next[polozkaId];
      return { ...prev, [mapKey]: next };
    });
  };

  // Čl. IV refs + Ed-content listener pre 4.4 a 4.5.
  const cl4_44_Ref = React.useRef(null);
  const cl4_45_Ref = React.useRef(null);
  const cl4_dokazy_Ref = React.useRef(null);

  // 4.4 — sledovanie polí (zamestnávateľ, pozícia, príjem) pre smart vzor.
  // Ed komponenty dispatchujú onValueChange aj po Persist hydratácii (Persist
  // nastaví textContent + dispatchne 'input'), takže state sa po reload-e
  // synchronizuje s uloženými hodnotami.
  const [fields44, setFields44] = React.useState({
    zamestnavatel: '', pozicia: '', predmet: '', obchodneMeno: '', postavenie: '', prijem: '',
  });
  const [lastSampleFields44, setLastSampleFields44] = React.useState(null);
  const fields44Changed = lastSampleFields44 !== null && (
    fields44.zamestnavatel !== lastSampleFields44.zamestnavatel ||
    fields44.pozicia !== lastSampleFields44.pozicia ||
    fields44.predmet !== lastSampleFields44.predmet ||
    fields44.obchodneMeno !== lastSampleFields44.obchodneMeno ||
    fields44.postavenie !== lastSampleFields44.postavenie ||
    fields44.prijem !== lastSampleFields44.prijem
  );

  // Auto-clear Ed bloku 3.3(b) pri prepnutí typStriedania (1tyz ↔ vlastne).
  // Prvý beh: typPrev.current === undefined → zapíšeme aktuálnu hodnotu
  // a skipneme (Persist medzitým obnoví obsah, nesmieme ho prepísať).
  // Reálne prepnutie: typPrev drží starú, cl3.typStriedania má novú →
  // mismatch → vyčistíme Ed a aktualizujeme typPrev.
  React.useEffect(() => {
    if (cl3_33b_typPrev.current === undefined) {
      cl3_33b_typPrev.current = cl3.typStriedania;
      return;
    }
    if (cl3_33b_typPrev.current === cl3.typStriedania) return;
    cl3_33b_typPrev.current = cl3.typStriedania;
    if (cl3_33b_Ref.current) {
      cl3_33b_Ref.current.textContent = '';
      cl3_33b_Ref.current.dispatchEvent(new Event('input', { bubbles: true }));
    }
  }, [cl3.typStriedania]);

  const [q1, setQ1] = React.useState(null); // null | 'ano' | 'nie'
  const [q2, setQ2] = React.useState(null); // null | 'ano' | 'nie'
  const [q3, setQ3] = React.useState(null); // null | 'ano' | 'nie'
  const [sudQuery, setSudQuery] = React.useState('');
  const [sudVybrany, setSudVybrany] = React.useState(null);
  const [sudDropdown, setSudDropdown] = React.useState(false);
  const fillSampleText = (refName, text, trackingMeta) => {
    const refMap = {
      cl3_311_Ref, cl3_312_Ref, cl3_32_Ref, cl3_33b_Ref, cl3_33c_Ref, cl3_35_Ref,
      cl4_44_Ref, cl4_45_Ref, cl4_dokazy_Ref,
    };
    const ref = refMap[refName];
    if (ref?.current) {
      ref.current.textContent = text;
      ref.current.dispatchEvent(new Event('input', { bubbles: true }));
    }
    if (trackingMeta && typeof window.trackEvent === 'function') {
      window.trackEvent('use_sample', trackingMeta);
    }
  };
  // Variant C: HTML zápis pre 4.4 sample (bold v hodnotách polí). Persist.jsx
  // pri uložení použije textContent — po reloade sa bold stratí, používateľ
  // ho obnoví znova kliknutím "Použiť vzorový text".
  const fillSampleHtml = (refName, html, trackingMeta) => {
    const refMap = {
      cl3_311_Ref, cl3_312_Ref, cl3_32_Ref, cl3_33b_Ref, cl3_33c_Ref, cl3_35_Ref,
      cl4_44_Ref, cl4_45_Ref, cl4_dokazy_Ref,
    };
    const ref = refMap[refName];
    if (ref?.current) {
      ref.current.innerHTML = html;
      ref.current.dispatchEvent(new Event('input', { bubbles: true }));
    }
    if (trackingMeta && typeof window.trackEvent === 'function') {
      window.trackEvent('use_sample', trackingMeta);
    }
  };
  const sudFiltered = sudQuery.length > 0
    ? window.SUDY.filter(s => removeDiacritics(s.nazov).includes(removeDiacritics(sudQuery)))
    : [];

  // Pre prehľadnosť — props pre <SudAutocomplete {...sudProps} /> obalíme do jedného objektu.
  const sudProps = { sudQuery, setSudQuery, sudVybrany, setSudVybrany, sudDropdown, setSudDropdown, sudFiltered };

  // Dynamické číslovanie Čl. V — keď je Čl. IV (pomery rodičov) skrytý
  // (zmenaVyber.vyzivne === false), Čl. V sa preznačí na Čl. IV a body 5.x na 4.x.
  const cl5Num = zmenaVyber.vyzivne ? 'V' : 'IV';
  const cl5Bod = (n) => `${zmenaVyber.vyzivne ? 5 : 4}.${n}`;

  // TipBtn je definovaný na module-leveli (viď vyššie). Tu len obalíme paper
  // do TipContext.Provider-a, aby všetky <TipBtn> dostali aktuálny activeTipKey
  // + onTipClick. Memoize-ujeme value, aby sa Provider re-rendery zbytočne
  // netriggerovali pri identických hodnotách.
  const tipCtx = React.useMemo(() => ({ activeTipKey, onTipClick }), [activeTipKey, onTipClick]);

  // Scroll-spy: activeArticle sleduje článok v čítacej zóne viewport-u;
  // activeTipKey sleduje top-most TipBtn v užšej zóne (20–40% viewport-u).
  // Pozorujeme PRIAMO tlačidlá s [data-tip-key] (všetky tipy, nielen tie
  // v p.has-tip) — po refaktoringu má každé tlačidlo position: absolute
  // s top podľa offsetTop rodiča, takže jeho pozícia v viewport-e verne
  // odráža miesto kde tip patrí v dokumente.
  // Deps obsahujú q1/q2/q3 — keď user prepne wizard, conditional q3 tip
  // mountne a treba ho re-observovať.
  React.useEffect(() => {
    const articles = document.querySelectorAll('.paper .article[id]');
    const obs = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) setActiveArticle(e.target.id); });
    }, { rootMargin: '-35% 0px -55% 0px' });
    articles.forEach(a => obs.observe(a));

    const tipButtons = document.querySelectorAll('.paper [data-tip-key]');
    let currentKey = null;
    const pObs = new IntersectionObserver((entries) => {
      const hits = entries
        .filter(e => e.isIntersecting)
        .map(e => ({ key: e.target.dataset.tipKey, top: e.boundingClientRect.top }))
        .sort((a, b) => a.top - b.top);
      if (hits.length && hits[0].key !== currentKey) {
        currentKey = hits[0].key;
        setActiveTipKey && setActiveTipKey(currentKey);
      }
    }, { rootMargin: '-20% 0px -60% 0px' });
    tipButtons.forEach(btn => pObs.observe(btn));

    return () => { obs.disconnect(); pObs.disconnect(); };
  }, [doctype, q1, q2, q3]);

  return (
    <TipContext.Provider value={tipCtx}>
    <div className="paper-stage">
      <article className="paper" aria-label="Návrh na zmenu rozhodnutia o úprave rodičovských práv — editovateľný dokument">

        <div className="paper-doc-name no-copy no-print">
          {filledKids.length > 1 ? 'Návrh na zmenu rozhodnutia o úprave výkonu rodičovských práv a povinností k maloletým deťom' : 'Návrh na zmenu rozhodnutia o úprave výkonu rodičovských práv a povinností k maloletému dieťaťu'}
          <TipBtn pointKey="doc-name-info" />
        </div>

        {/* Hlavička dokumentu — ľavý stĺpec prázdny (miesto pre podpis advokáta), pravý: adresát súdu + dátum */}
        <header className="paper-header" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 48 }}>
          <div className="paper-header-left"></div>
          <div className="paper-header-right">
            <div style={{ borderBottom: '1px solid var(--ink)', width: '100%', marginBottom: 16 }}></div>
            <div className="no-copy no-print" style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <SudAutocomplete {...sudProps} />
              <TipBtn pointKey="header-sud" />
            </div>
            {sudVybrany && (
              <>
                {/* Zarovnanie pod text v inpute — input má padding-left 8px + border 1px,
                    takže adresa zarovnaná na 9px. */}
                <div className="no-print" style={{ fontSize: '0.95em', fontStyle: 'italic', paddingLeft: 9, marginTop: 2 }}>{sudVybrany.ulica}</div>
                <div className="no-print" style={{ fontSize: '0.95em', fontStyle: 'italic', paddingLeft: 9 }}>{sudVybrany.mesto}</div>
              </>
            )}
            <div className="ed-select-print-block">{sudVybrany ? sudVybrany.nazov : ''}</div>
            <div className="ed-select-print-block">{sudVybrany ? sudVybrany.ulica : ''}</div>
            <div className="ed-select-print-block">{sudVybrany ? sudVybrany.mesto : ''}</div>
            <div style={{ borderBottom: '1px solid var(--ink)', width: '100%', margin: '16px 0 8px' }}></div>
            <p style={{ margin: 0, textAlign: 'right' }}>
              V{' '}
              <Ed defaultValue="" placeholder="miesto" />
              , dňa{' '}
              <Ed defaultValue="" placeholder="DD. MM. RRRR" />
            </p>
          </div>
        </header>

        {/* Účastníci konania */}
        <div className="parties-table" style={{ display: 'flex', flexDirection: 'column', gap: 20, padding: '24px 0', borderTop: '1px solid var(--rule)', borderBottom: '1px solid var(--rule)', margin: '64px 0 32px' }}>
          {/* Voľba pohlavia navrhovateľa — UI control mimo PDF/Word.
              Pohlavie odporcu sa odvodí automaticky (§ 1 ZoR). */}
          <div className="no-copy no-print" style={{ display: 'flex', gap: 16, alignItems: 'center', fontSize: '0.85em', color: 'var(--ink-3)' }}>
            <span style={{ fontFamily: 'var(--mono)', letterSpacing: '0.04em', textTransform: 'uppercase' }}>Navrhovateľ je:</span>
            <label style={{ display: 'inline-flex', alignItems: 'center', gap: 4, cursor: 'pointer' }}>
              <input
                type="radio"
                name="navrhovatel-pohlavie"
                value="muz"
                checked={navrhovatelPohlavie === 'muz'}
                onChange={() => setNavrhovatelPohlavie('muz')}
              />
              <span>muž</span>
            </label>
            <label style={{ display: 'inline-flex', alignItems: 'center', gap: 4, cursor: 'pointer' }}>
              <input
                type="radio"
                name="navrhovatel-pohlavie"
                value="zena"
                checked={navrhovatelPohlavie === 'zena'}
                onChange={() => setNavrhovatelPohlavie('zena')}
              />
              <span>žena</span>
            </label>
          </div>

          <div style={{ marginBottom: 20 }}>
            <div style={{ fontWeight: 'bold', marginBottom: 8 }}>{oznacenieCap('navrhovatel', navrhovatelPohlavie)}:</div>
            <table className="party-table">
              <tbody>
                <tr>
                  <td className="party-label">Meno a priezvisko:</td>
                  <td className="party-value">
                    <div style={{ display: 'flex', gap: 8, alignItems: 'baseline', flexWrap: 'wrap' }}>
                      <SyncedEd value={menoNavrhovatela} onChange={setMenoNavrhovatela} placeholder="meno a priezvisko" />
                      <span style={{ whiteSpace: 'nowrap' }}>rod.:</span>
                      <SyncedEd value={rodnePriezvisko} onChange={setRodnePriezvisko} placeholder="rodné priezvisko" />
                    </div>
                  </td>
                </tr>
                <tr>
                  <td className="party-label">Dátum narodenia:</td>
                  <td className="party-value"><Ed defaultValue="" placeholder="DD. MM. RRRR" /></td>
                </tr>
                <tr>
                  <td className="party-label">Trvalý pobyt:</td>
                  <td className="party-value"><Ed defaultValue="" placeholder="ulica, PSČ mesto" /></td>
                </tr>
                <tr>
                  <td className="party-label">Občianstvo:</td>
                  <td className="party-value"><Ed defaultValue="" placeholder="uveďte občianstvo" /></td>
                </tr>
              </tbody>
            </table>
            <div style={{ fontStyle: 'italic', marginTop: 6 }}>(ďalej len „{oznacenie('navrhovatel', navrhovatelPohlavie)}")</div>
          </div>

          <div>
            <div style={{ fontWeight: 'bold', marginBottom: 8 }}>{oznacenieCap('odporca', odporcaPohlavie)}:</div>
            <table className="party-table">
              <tbody>
                <tr>
                  <td className="party-label">Meno a priezvisko:</td>
                  <td className="party-value">
                    <div style={{ display: 'flex', gap: 8, alignItems: 'baseline', flexWrap: 'wrap' }}>
                      <SyncedEd value={menoOdporcu} onChange={setMenoOdporcu} placeholder="meno a priezvisko" />
                      <span style={{ whiteSpace: 'nowrap' }}>rod.:</span>
                      <Ed defaultValue="" placeholder="rodné priezvisko" />
                    </div>
                  </td>
                </tr>
                <tr>
                  <td className="party-label">Dátum narodenia:</td>
                  <td className="party-value"><Ed defaultValue="" placeholder="DD. MM. RRRR" /></td>
                </tr>
                <tr>
                  <td className="party-label">Trvalý pobyt:</td>
                  <td className="party-value"><Ed defaultValue="" placeholder="ulica, PSČ mesto" /></td>
                </tr>
                <tr>
                  <td className="party-label">Občianstvo:</td>
                  <td className="party-value"><Ed defaultValue="" placeholder="uveďte občianstvo" /></td>
                </tr>
              </tbody>
            </table>
            <div style={{ fontStyle: 'italic', marginTop: 6 }}>(ďalej len „{oznacenie('odporca', odporcaPohlavie)}")</div>
          </div>
        </div>

        {/* Maloleté deti — placeholder sekcia. V tomto kroku iba state + UI;
            žiadna synchronizácia s textom Čl. I ani petitom (pridá sa neskôr).
            Persist.jsx preskakuje tieto polia (noPersist) — celý array kids
            serializujeme do KIDS_STORAGE_KEY ako JSON. */}
        {/* TipBtn pre kids-section — bez position:relative na wrapperi, aby
            TipBtn pozicoval voči .paper (jediný pozicovaný predok). useLayoutEffect
            v TipBtn počíta top cez offsetTop chain anchor → .paper, takže tip
            sa vertikálne zarovná s kids-table a horizontálne ostáva v pravom
            gutteri papiera (right: 18px voči .paper). */}
        <div className="kids-table has-tip" style={{ display: 'flex', flexDirection: 'column', gap: 24, padding: '0 0 24px 0', borderBottom: '1px solid var(--rule)', margin: '0 0 32px' }}>
          <TipBtn pointKey="kids-section" />
          {kids.map((kid) => (
            <div key={kid.id} className="kid-row" style={{ position: 'relative', paddingRight: 24 }}>
              <div className="kid-row-label" style={{ fontWeight: 'bold', marginBottom: 4 }}>za účasti mal. dieťaťa:</div>
              <div className="kid-row-fields" style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'baseline', gap: 6 }}>
                <SyncedEd
                  value={kid.meno}
                  onChange={(v) => updateKid(kid.id, 'meno', v)}
                  placeholder="meno a priezvisko"
                  noPersist
                />
                <span>, nar.</span>
                <SyncedEd
                  value={kid.datumNarodenia}
                  onChange={(v) => updateKid(kid.id, 'datumNarodenia', v)}
                  placeholder="DD. MM. RRRR"
                  noPersist
                />
                <span>, bytom</span>
                <SyncedEd
                  value={kid.bytom}
                  onChange={(v) => updateKid(kid.id, 'bytom', v)}
                  placeholder="ulica, PSČ obec"
                  noPersist
                />
              </div>
              {kids.length > 1 && (
                <button
                  type="button"
                  className="kid-remove no-print no-copy"
                  onClick={() => removeKid(kid.id)}
                  aria-label="Odstrániť dieťa"
                  title="Odstrániť dieťa"
                  style={{
                    position: 'absolute',
                    right: 0,
                    top: 0,
                    background: 'transparent',
                    border: 0,
                    cursor: 'pointer',
                    color: 'var(--ink-4)',
                    fontSize: 14,
                    lineHeight: 1,
                    padding: '2px 6px',
                  }}
                >✕</button>
              )}
            </div>
          ))}
          <button
            type="button"
            className="party-add no-print no-copy"
            onClick={addKid}
            style={{ alignSelf: 'flex-start' }}
          >+ Pridať maloleté dieťa</button>
        </div>

        {/* Názov dokumentu — dlhá variant pre s-deti návrh.
            .doc-title--long zmenšuje font/letter-spacing a povoluje viacriadkové
            zalomenie (definované v generator.css pre web aj print). */}
        <h1 className="doc-title doc-title--long" style={{ marginTop: 48 }}>{filledKids.length > 1 ? 'Návrh na zmenu rozhodnutia o úprave výkonu rodičovských práv a povinností k maloletým deťom' : 'Návrh na zmenu rozhodnutia o úprave výkonu rodičovských práv a povinností k maloletému dieťaťu'}</h1>
        <div className="doc-sub">podľa § 26 a § 78 zákona č. 36/2005 Z. z. o rodine</div>
        <p className="small" style={{ textAlign: 'left' }}>
          Konanie je oslobodené od súdneho poplatku podľa § 4 ods. 1 písm. a) zákona č. 71/1992 Zb. o súdnych poplatkoch.
          <TipBtn pointKey="header-poplatok" />
        </p>

        {/* Čl. I — Účastníci a maloleté dieťa */}
        <section className="article" id="art-1">
          <div className="article-intro">
          <div className="article-head">
            <div className="article-num">Článok I</div>
            <span className="article-title">{filledKids.length > 1 ? 'Účastníci a maloleté deti' : 'Účastníci a maloleté dieťa'}</span>
          </div>

          <p className="has-tip">
            <strong>1.1</strong>&nbsp;&nbsp;{oznacenieCap('navrhovatel', navrhovatelPohlavie)} a {oznacenie('odporca', odporcaPohlavie)} sú rodičmi {filledKids.length === 1 ? 'maloletého dieťaťa' : 'maloletých detí'}:
          </p>
          </div>{/* /article-intro */}

          {filledKids.length === 0 ? (
            <p className="no-copy no-print" style={{ fontStyle: 'italic', color: 'var(--ink-3)', margin: '8px 0' }}>
              [Doplňte aspoň jedno maloleté dieťa v sekcii účastníkov vyššie]
            </p>
          ) : (
            <>
              <p style={{ margin: '8px 0 4px' }}>
                Maloleté {filledKids.length === 1 ? 'dieťa' : 'deti'}:
              </p>
              {filledKids.map((kid) => {
                const parts = [];
                if (kid.meno.trim()) parts.push(kid.meno.trim());
                if (kid.datumNarodenia.trim()) parts.push('nar. ' + kid.datumNarodenia.trim());
                if (kid.bytom.trim()) parts.push('bytom ' + kid.bytom.trim());
                return (
                  <p key={kid.id} style={{ margin: '0 0 4px', paddingLeft: 16 }}>
                    – {parts.join(', ')}
                  </p>
                );
              })}
            </>
          )}

          {/* Dôkaz: rodný list / rodné listy — agregátny riadok pod bodom 1.1.
              Singulár pre 1 dieťa, plurál pre 2+ detí; všetky deti za sebou
              v jednom riadku oddelené čiarkami. Dátum vo formáte d.m.rrrr. */}
          {(() => {
            const validKids = filledKids.filter(k => k.meno.trim() !== '' && k.datumNarodenia.trim() !== '');
            if (validKids.length === 0) return null;
            const list = validKids.map(k => `${k.meno.trim()}, nar. ${formatDatumDmRRRR(k.datumNarodenia)}`).join(', ');
            const label = validKids.length === 1 ? 'Rodný list mal. dieťaťa' : 'Rodné listy mal. detí';
            return (
              <p className="evidence">
                <em>Dôkaz:</em> {label} {list}
              </p>
            );
          })()}

          <p style={{ margin: '16px 0 8px' }}>
            <strong>1.2 Miestna príslušnosť súdu</strong>
          </p>

          <p style={{ margin: '8px 0' }}>
            Podľa § 112 ods. 1 zákona č. 161/2015 Z. z. (Civilný mimosporový poriadok) je miestne príslušným súd, v obvode ktorého má {filledKids.length === 1 ? 'maloleté dieťa' : 'maloleté dieťa (alebo deti)'} bydlisko na základe dohody rodičov alebo rozhodnutia súdu, prípadne iných rozhodujúcich skutočností.
          </p>

          <p className="autocomplete-host" style={{ margin: '8px 0 6px' }}>
            Miestne príslušným súdom je{'  '}
            <span className="no-copy no-print">
              <SudAutocomplete {...sudProps} />
            </span>
            <span className="ed-select-print">{sudVybrany ? sudVybrany.nazov : ''}</span>
          </p>
        </section>

        {/* Čl. II — Doterajšia úprava pomerov rozhodnutím súdu.
            Prvý súd (povinný) + voliteľný druhý (krajský v odvolaní). */}
        <section className="article" id="art-2">
          <div className="article-intro">
            <div className="article-head">
              <div className="article-num">Článok II</div>
              <span className="article-title">Doterajšia úprava pomerov rozhodnutím súdu</span>
            </div>

            <p className="no-copy no-print has-tip" style={{ fontStyle: 'italic', fontSize: '0.85em', color: 'var(--ink-3)', margin: '0 0 8px' }}>
              <TipBtn pointKey="zmena-cl2-povodne-rozhodnutie" />
              Názov súdu uveďte v genitíve, napr. „Okresného súdu Bratislava I" alebo „Krajského súdu v Bratislave". Tento tvar sa použije v dokumente za slovo „rozsudkom"/„uznesením".
            </p>
          </div>{/* /article-intro */}

          {/* Bod 2.1 — prvý súd (povinný). */}
          <div className="no-copy no-print form-grid-cols" style={{ display: 'grid', gridTemplateColumns: '180px 1fr', rowGap: 8, columnGap: 12, alignItems: 'baseline', margin: '12px 0 8px' }}>
            <strong style={{ gridColumn: '1 / -1', marginBottom: 4 }}>2.1 Predchádzajúce rozhodnutie</strong>
            <span>Názov súdu (genitív):</span>
            <SyncedEd value={sud1.nazov} onChange={(v) => updateSud1('nazov', v)} placeholder="Okresného súdu Bratislava I" noPersist />
            <span>Druh rozhodnutia:</span>
            <span>
              <select
                value={sud1.druh}
                onChange={(e) => updateSud1('druh', e.target.value)}
                className="ed-select"
                aria-label="Druh rozhodnutia"
                style={{ minWidth: 160 }}
              >
                <option value="uznesenie">Uznesenie</option>
                <option value="rozsudok">Rozsudok</option>
              </select>
            </span>
            <span>Spisová značka:</span>
            <SyncedEd value={sud1.sznacka} onChange={(v) => updateSud1('sznacka', v)} placeholder="23P/45/2023" noPersist />
            <span>Dátum rozhodnutia:</span>
            <SyncedEd value={sud1.datum} onChange={(v) => updateSud1('datum', v)} placeholder="15.3.2023" noPersist />
            <span style={{ gridColumn: '1 / -1', marginTop: 8 }}>Popis ako súd rozhodol:</span>
            <span style={{ gridColumn: '1 / -1' }}>
              <Ed
                block xl noPersist
                placeholder="Stručne popíšte, čo súd rozhodol — komu bolo dieťa zverené, aká bola výška výživného, ako bol upravený styk."
                onValueChange={(v) => updateSud1('popis', v)}
                defaultValue={sud1.popis}
              />
            </span>
          </div>

          {/* Bod 2.2 — voliteľný druhý súd (krajský). */}
          {!sud2.aktivny ? (
            <div className="no-copy no-print" style={{ margin: '12px 0' }}>
              <button
                type="button"
                className="party-add"
                onClick={aktivovatSud2}
                style={{ alignSelf: 'flex-start' }}
              >+ Pridať ďalší súd (Krajský súd v odvolaní)</button>
              <p className="no-copy no-print" style={{ fontStyle: 'italic', fontSize: '0.82em', color: 'var(--ink-3)', margin: '8px 0 0' }}>
                Ďalší súd pridajte len v prípade, ak posledné rozhodnutie vydal Krajský súd v rámci odvolacieho konania — v takom prípade uveďte ako prvé rozhodnutie Okresného súdu (prvostupňové) a ako druhé rozhodnutie Krajského súdu (odvolacie). Uveďte len posledné platné rozhodnutie, ak ich bolo viac.
              </p>
            </div>
          ) : (
            <div className="no-copy no-print form-grid-cols" style={{ display: 'grid', gridTemplateColumns: '180px 1fr', rowGap: 8, columnGap: 12, alignItems: 'baseline', margin: '20px 0 8px', position: 'relative' }}>
              <strong style={{ gridColumn: '1 / -1', marginBottom: 4 }}>2.2 Rozhodnutie krajského súdu (v odvolaní)</strong>
              <span>Názov súdu (genitív):</span>
              <SyncedEd value={sud2.nazov} onChange={(v) => updateSud2('nazov', v)} placeholder="Krajského súdu v Bratislave" noPersist />
              <span>Druh rozhodnutia:</span>
              <span>
                <select
                  value={sud2.druh}
                  onChange={(e) => updateSud2('druh', e.target.value)}
                  className="ed-select"
                  aria-label="Druh rozhodnutia"
                  style={{ minWidth: 160 }}
                >
                  <option value="uznesenie">Uznesenie</option>
                  <option value="rozsudok">Rozsudok</option>
                </select>
              </span>
              <span>Spisová značka:</span>
              <SyncedEd value={sud2.sznacka} onChange={(v) => updateSud2('sznacka', v)} placeholder="11CoP/123/2024" noPersist />
              <span>Dátum rozhodnutia:</span>
              <SyncedEd value={sud2.datum} onChange={(v) => updateSud2('datum', v)} placeholder="10.10.2024" noPersist />
              <span style={{ gridColumn: '1 / -1', marginTop: 8 }}>Popis ako súd rozhodol:</span>
              <span style={{ gridColumn: '1 / -1' }}>
                <Ed
                  block xl noPersist
                  placeholder="Stručne popíšte, čo krajský súd rozhodol v odvolacom konaní."
                  onValueChange={(v) => updateSud2('popis', v)}
                  defaultValue={sud2.popis}
                />
              </span>
              <button
                type="button"
                onClick={odstranitSud2}
                className="no-print no-copy"
                style={{ gridColumn: '1 / -1', justifySelf: 'flex-start', marginTop: 8, background: 'transparent', border: '1px solid var(--rule)', borderRadius: 'var(--r-sm)', padding: '4px 10px', cursor: 'pointer', color: 'var(--ink-3)', fontSize: '0.85em' }}
              >− Odstrániť druhý súd</button>
            </div>
          )}

          {/* Renderovaná veta v dokumente. */}
          {sud1.nazov && sud1.nazov.trim() && (
            <p style={{ margin: '16px 0 8px', textAlign: 'justify' }}>
              Pomery účastníkov a {filledKids.length === 1 ? 'maloletého dieťaťa' : 'maloletých detí'} boli upravené {buildSudRef(sud1, sud2.aktivny ? sud2 : null)}.
            </p>
          )}

          {/* Popisy ako súd rozhodol. */}
          {sud1.nazov && sud1.nazov.trim() && sud1.popis && sud1.popis.trim() && (
            <div style={{ margin: '12px 0' }}>
              <p style={{ margin: '8px 0 4px', fontStyle: 'italic' }}>
                {sud2.aktivny && sud2.nazov && sud2.nazov.trim() ? 'Okresný súd v predchádzajúcom konaní rozhodol takto:' : 'Súd v predchádzajúcom konaní rozhodol takto:'}
              </p>
              <p style={{ margin: '0 0 8px', whiteSpace: 'pre-wrap', paddingLeft: 16 }}>
                {sud1.popis}
              </p>
            </div>
          )}
          {sud2.aktivny && sud2.nazov && sud2.nazov.trim() && sud2.popis && sud2.popis.trim() && (
            <div style={{ margin: '12px 0' }}>
              <p style={{ margin: '8px 0 4px', fontStyle: 'italic' }}>Krajský súd v odvolacom konaní rozhodol takto:</p>
              <p style={{ margin: '0 0 8px', whiteSpace: 'pre-wrap', paddingLeft: 16 }}>
                {sud2.popis}
              </p>
            </div>
          )}

          {/* Dôkazový riadok — formát ako rodný list v Čl. I. */}
          {sud1.nazov && sud1.nazov.trim() && (() => {
            const druhCap1 = sud1.druh === 'rozsudok' ? 'Rozsudok' : 'Uznesenie';
            const part1 = `${druhCap1} ${sud1.nazov.trim()}` +
              (sud1.sznacka && sud1.sznacka.trim() ? ` sp. zn. ${sud1.sznacka.trim()}` : '') +
              (sud1.datum   && sud1.datum.trim()   ? ` zo dňa ${formatDatumDmRRRR(sud1.datum)}` : '');
            let combined = part1;
            if (sud2.aktivny && sud2.nazov && sud2.nazov.trim()) {
              const druhCap2 = sud2.druh === 'rozsudok' ? 'Rozsudok' : 'Uznesenie';
              const part2 = `${druhCap2} ${sud2.nazov.trim()}` +
                (sud2.sznacka && sud2.sznacka.trim() ? ` sp. zn. ${sud2.sznacka.trim()}` : '') +
                (sud2.datum   && sud2.datum.trim()   ? ` zo dňa ${formatDatumDmRRRR(sud2.datum)}` : '');
              combined = `${part1}, ${part2}`;
            }
            return (
              <p className="evidence">
                <em>Dôkaz:</em> {combined}
              </p>
            );
          })()}
        </section>


        {/* Čl. III — Zmena pomerov a návrh úpravy.
            3.1 výber 4 oblastí, 3.2 popis zmeny pomerov, 3.3 zverenie,
            3.4 výživné, 3.5 zastupovanie, 3.6 styk. Podmienečné rendrovanie. */}
        <section className="article" id="art-3">
          <div className="article-intro">
            <div className="article-head">
              <div className="article-num">Článok III</div>
              <span className="article-title">Zmena pomerov a návrh úpravy</span>
            </div>
          </div>{/* /article-intro */}

          {/* 3.1 — výber, ktoré časti rozhodnutia sa žiadajú zmeniť */}
          <p style={{ margin: '12px 0 6px' }}><strong>3.1 Časti rozhodnutia, ktoré sa žiadajú zmeniť</strong>
            <TipBtn pointKey="3.1-vyber" />
          </p>
          <p className="no-copy no-print" style={{ fontStyle: 'italic', fontSize: '0.85em', color: 'var(--ink-3)', margin: '0 0 8px' }}>
            Vyberte len tie časti predchádzajúceho rozhodnutia, ktoré chcete zmeniť. Časti, ktoré sa nemenia, zostávajú v platnosti podľa pôvodného rozhodnutia. Ak nezaškrtnete nič, petit nebude obsahovať žiadne výroky a návrh nemôže byť úspešný.
          </p>
          <div className="no-copy no-print" style={{ display: 'flex', flexDirection: 'column', gap: 6, margin: '8px 0 16px' }}>
            <label style={{ display: 'inline-flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
              <input type="checkbox" checked={zmenaVyber.zverenie} onChange={() => toggleZmena('zverenie')} />
              <span>zverenie do osobnej starostlivosti</span>
            </label>
            <label style={{ display: 'inline-flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
              <input type="checkbox" checked={zmenaVyber.vyzivne} onChange={() => toggleZmena('vyzivne')} />
              <span>výživné</span>
            </label>
            <label style={{ display: 'inline-flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
              <input type="checkbox" checked={zmenaVyber.zastupovanie} onChange={() => toggleZmena('zastupovanie')} />
              <span>zastupovanie a správa majetku</span>
            </label>
            <label style={{ display: 'inline-flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
              <input type="checkbox" checked={zmenaVyber.styk} onChange={() => toggleZmena('styk')} />
              <span>styk s maloletým dieťaťom</span>
            </label>
          </div>

          {/* 3.2 — popis zmeny pomerov, 4 vzory A/B/C/D */}
          <p style={{ margin: '20px 0 6px' }}><strong>3.2 Popis zmeny pomerov</strong>
            <TipBtn pointKey="3.2-zmena-pomerov" />
          </p>
          <p className="no-copy no-print" style={{ fontStyle: 'italic', fontSize: '0.85em', color: 'var(--ink-3)', margin: '0 0 8px' }}>
            Vyberte vzor, ktorý vystihuje vašu situáciu, a doplňte konkrétne údaje v hranatých zátvorkách.
          </p>
          <div className="no-copy no-print" style={{ display: 'flex', flexWrap: 'wrap', gap: 8, margin: '0 0 8px' }}>
            {[
              { label: 'Variant A — Zmena na strane povinného', tpl: SAMPLE_CL3Z_2_A, variant: 'zmena_povinneho' },
              { label: 'Variant B — Zmena na strane dieťaťa', tpl: SAMPLE_CL3Z_2_B, variant: 'zmena_dietata' },
              { label: 'Variant C — Zdravotný stav', tpl: SAMPLE_CL3Z_2_C, variant: 'zdravotny_stav' },
              { label: 'Variant D — Iná zmena', tpl: SAMPLE_CL3Z_2_D, variant: 'ina_zmena' },
            ].map(({ label, tpl, variant }) => (
              <button
                key={label}
                type="button"
                onClick={() => fillSampleZmena(cl3z2_Ref, tpl, cl3zVars(navrhovatelPohlavie, filledKids.length, buildSudRef(sud1, sud2.aktivny ? sud2 : null)), { section: '3.2', variant })}
                style={{ fontSize: '0.82em', padding: '4px 10px', border: '1px solid var(--rule)', borderRadius: 'var(--r-sm)', background: 'var(--paper)', cursor: 'pointer', color: 'var(--ink-2)' }}
              >{label}</button>
            ))}
          </div>
          <Ed
            block xl noPersist
            ref={cl3z2_Ref}
            placeholder="Popis zmeny pomerov (3.2) — váš text alebo použite jeden zo vzorov vyššie..."
            onValueChange={setCl3z2Content}
          />

          {/* 3.3 — navrhovaná úprava zverenia (zobrazí sa LEN ak zmenaVyber.zverenie) */}
          {zmenaVyber.zverenie && (() => {
            const navrhKey = rolaRodicaKey('navrhovatel', navrhovatelPohlavie);
            const druhyKey = rolaRodicaKey('odporca', navrhovatelPohlavie);
            const navrhGen = rolaRodicaPad(navrhKey, 'gen'); // matky / otca
            const druhyGen = rolaRodicaPad(druhyKey, 'gen');
            const navrhDat = rolaRodicaPad(navrhKey, 'dat'); // matke / otcovi
            const druhyDat = rolaRodicaPad(druhyKey, 'dat');
            return (
            <div style={{ marginTop: 24 }}>
              <p style={{ margin: '12px 0 6px' }}><strong>3.3 Navrhovaná úprava zverenia</strong>
                <TipBtn pointKey="zmena-3.3-forma" />
              </p>
              <div className="no-copy no-print" style={{ display: 'flex', flexDirection: 'column', gap: 6, margin: '0 0 12px' }}>
                {[
                  { v: 'osobna-navrhovatel', label: `do osobnej starostlivosti ${navrhGen}` },
                  { v: 'osobna-odporca', label: `do osobnej starostlivosti ${druhyGen}` },
                  { v: 'striedava', label: 'do striedavej osobnej starostlivosti oboch rodičov' },
                  { v: 'spolocna', label: 'do spoločnej osobnej starostlivosti oboch rodičov' },
                ].map(({ v, label }) => (
                  <label key={v} style={{ display: 'inline-flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
                    <input type="radio" name="zmena-novaForma" value={v} checked={cl3z3.novaForma === v} onChange={() => setCl3z3(s => ({ ...s, novaForma: v }))} />
                    <span>{label}</span>
                  </label>
                ))}
              </div>
              <div className="no-copy no-print" style={{ display: 'flex', flexWrap: 'wrap', gap: 8, margin: '0 0 8px' }}>
                {[
                  { label: `Vzor 1 — Zverenie ${navrhDat}`, tpl: SAMPLE_CL3Z_3_1, variant: 'zverenie_navrhovatel' },
                  { label: `Vzor 2 — Zverenie ${druhyDat}`, tpl: SAMPLE_CL3Z_3_1B, variant: 'zverenie_odporca' },
                  { label: 'Vzor 3 — Striedavá', tpl: SAMPLE_CL3Z_3_2, variant: 'striedava' },
                  { label: 'Vzor 4 — Spoločná', tpl: SAMPLE_CL3Z_3_3, variant: 'spolocna' },
                ].map(({ label, tpl, variant }) => (
                  <button
                    key={label}
                    type="button"
                    onClick={() => fillSampleZmena(cl3z3_Ref, tpl, cl3zVars(navrhovatelPohlavie, filledKids.length, buildSudRef(sud1, sud2.aktivny ? sud2 : null)), { section: '3.3', variant })}
                    style={{ fontSize: '0.82em', padding: '4px 10px', border: '1px solid var(--rule)', borderRadius: 'var(--r-sm)', background: 'var(--paper)', cursor: 'pointer', color: 'var(--ink-2)' }}
                  >{label}</button>
                ))}
              </div>
              <Ed
                block xl noPersist
                ref={cl3z3_Ref}
                placeholder="Odôvodnenie navrhovanej úpravy zverenia (3.3) — váš text..."
                onValueChange={(v) => setCl3z3(s => ({ ...s, odovodnenie: v }))}
              />
            </div>
            );
          })()}

          {/* 3.4 — navrhovaná úprava výživného (per-dieťa štruktúra) */}
          {zmenaVyber.vyzivne && (
            <div style={{ marginTop: 24 }}>
              <p style={{ margin: '12px 0 6px' }}><strong>3.4 Navrhovaná úprava výživného</strong>
                <TipBtn pointKey="zmena-3.4-vyzivne" />
              </p>
              <div className="no-copy no-print kalkulacka-row" style={{ display: 'flex', justifyContent: 'flex-end', margin: '0 0 12px' }}>
                <a
                  href="https://vyzivnenadieta.sk/tabulkove-vyzivne"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="btn btn-oxblood btn-sm no-copy no-print"
                >Kalkulačka výživného</a>
              </div>
              {filledKids.length === 0 ? (
                <p className="no-copy no-print" style={{ fontStyle: 'italic', color: 'var(--ink-3)', margin: '8px 0' }}>
                  [Doplňte aspoň jedno maloleté dieťa v Čl. I, aby ste mohli zadať údaje výživného.]
                </p>
              ) : (
                filledKids.map((kid, idx) => {
                  const row = getCl3z4PerDieta(kid.id);
                  const meno = (kid.meno || '').trim();
                  const dat = (kid.datumNarodenia || '').trim();
                  const headerLabel = meno
                    ? `${meno}${dat ? ', nar. ' + dat : ''}`
                    : `Dieťa #${idx + 1}`;
                  return (
                    <div key={kid.id} className="no-copy no-print" style={{ marginBottom: 12, padding: '10px 12px', background: 'var(--ivory-2)', borderRadius: 'var(--r-sm)', border: '1px solid var(--rule)' }}>
                      <div style={{ fontWeight: 600, marginBottom: 8 }}>{headerLabel}</div>
                      <div className="form-grid-cols" style={{ display: 'grid', gridTemplateColumns: '280px 1fr', rowGap: 8, columnGap: 12, alignItems: 'baseline', marginBottom: 8 }}>
                        <span>Aktuálna výška výživného (EUR/mesiac):</span>
                        <SyncedEd value={row.staraVyska} onChange={(v) => updateCl3z4PerDieta(kid.id, 'staraVyska', v)} placeholder="180" num noPersist />
                        <span>Navrhovaná nová výška (EUR/mesiac):</span>
                        <SyncedEd value={row.novaVyska} onChange={(v) => updateCl3z4PerDieta(kid.id, 'novaVyska', v)} placeholder="300" num noPersist />
                      </div>
                      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                        {[
                          { v: 'zvysenie', label: 'zvýšenie výživného' },
                          { v: 'znizenie', label: 'zníženie výživného' },
                          { v: 'zrusenie', label: 'zrušenie výživného' },
                        ].map(({ v, label }) => (
                          <label key={v} style={{ display: 'inline-flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
                            <input
                              type="radio"
                              name={`zmena-typVyzivne-${kid.id}`}
                              value={v}
                              checked={row.typZmeny === v}
                              onChange={() => updateCl3z4PerDieta(kid.id, 'typZmeny', v)}
                            />
                            <span>{label}</span>
                          </label>
                        ))}
                      </div>
                    </div>
                  );
                })
              )}
              <div className="no-copy no-print" style={{ display: 'flex', flexWrap: 'wrap', gap: 8, margin: '8px 0' }}>
                {[
                  { label: 'Vzor 1 — Zvýšenie (všetky deti)', typ: 'zvysenie' },
                  { label: 'Vzor 2 — Zníženie (všetky deti)', typ: 'znizenie' },
                  { label: 'Vzor 3 — Zrušenie (všetky deti)', typ: 'zrusenie' },
                ].map(({ label, typ }) => (
                  <button
                    key={label}
                    type="button"
                    onClick={() => {
                      const text = sampleVyzivneZmena(typ, cl3z4.perDieta, filledKids, navrhovatelPohlavie);
                      fillSampleZmena(cl3z4_Ref, text, {}, { section: '3.4', variant: typ });
                    }}
                    style={{ fontSize: '0.82em', padding: '4px 10px', border: '1px solid var(--rule)', borderRadius: 'var(--r-sm)', background: 'var(--paper)', cursor: 'pointer', color: 'var(--ink-2)' }}
                  >{label}</button>
                ))}
              </div>
              <Ed
                block xl noPersist
                ref={cl3z4_Ref}
                placeholder="Odôvodnenie navrhovanej úpravy výživného (3.4) — váš text alebo použite jeden zo vzorov vyššie..."
                onValueChange={(v) => updateCl3z4Odovodnenie(v)}
              />
            </div>
          )}

          {/* 3.5 — navrhovaná úprava zastupovania */}
          {zmenaVyber.zastupovanie && (() => {
            const navrhKey35 = rolaRodicaKey('navrhovatel', navrhovatelPohlavie);
            const druhyKey35 = rolaRodicaKey('odporca', navrhovatelPohlavie);
            const navrhNom = rolaRodicaPad(navrhKey35, 'nom'); // matka / otec
            const druhyNom = rolaRodicaPad(druhyKey35, 'nom');
            return (
            <div style={{ marginTop: 24 }}>
              <p style={{ margin: '12px 0 6px' }}><strong>3.5 Navrhovaná úprava zastupovania a správy majetku</strong>
                <TipBtn pointKey="zmena-3.5-zastupovanie" />
              </p>
              <div className="no-copy no-print" style={{ display: 'flex', flexDirection: 'column', gap: 6, margin: '0 0 12px' }}>
                {[
                  { v: 'samostatne-navrhovatel', label: `samostatne ${navrhNom}` },
                  { v: 'samostatne-odporca', label: `samostatne ${druhyNom}` },
                  { v: 'spolocne', label: 'spoločne obaja rodičia' },
                ].map(({ v, label }) => (
                  <label key={v} style={{ display: 'inline-flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
                    <input type="radio" name="zmena-zastupovanie" value={v} checked={cl3z5.noveZastupovanie === v} onChange={() => setCl3z5(s => ({ ...s, noveZastupovanie: v }))} />
                    <span>{label}</span>
                  </label>
                ))}
              </div>
              <Ed
                block xl noPersist
                ref={cl3z5_Ref}
                placeholder="Popíšte, prečo žiadate zmenu zastupovania alebo správy majetku — napríklad neschopnosť druhého rodiča spolupracovať pri konkrétnom právnom úkone, dlhodobá neprítomnosť druhého rodiča, špecifická potreba samostatného rozhodovania."
                onValueChange={(v) => setCl3z5(s => ({ ...s, odovodnenie: v }))}
              />
            </div>
            );
          })()}

          {/* 3.6 — navrhovaná úprava styku.
              Štruktúra: aktuálny styk (zachované) → vzor pre nový styk (skopírované
              z PaperDeti.jsx 3.5: bežný styk + letné/zimné/Veľkonočné prázdniny +
              veta o odovzdávaní). Pri striedavej/spoločnej forme starostlivosti
              styk samostatne neupravujeme — italic poznámka, vzor sa neponúkne.
              Resolve nezvereného rodiča podľa novaForma; pri prázdnom string-u
              default nezverený = odporca. */}
          {zmenaVyber.styk && (() => {
            const novaForma = cl3z3.novaForma;
            const stykNeAplikovatelny = (novaForma === 'striedava' || novaForma === 'spolocna');
            let nezverenyKey;
            if (novaForma === 'osobna-navrhovatel') {
              nezverenyKey = rolaRodicaKey('odporca', navrhovatelPohlavie);
            } else if (novaForma === 'osobna-odporca') {
              nezverenyKey = rolaRodicaKey('navrhovatel', navrhovatelPohlavie);
            } else {
              // 'striedava' | 'spolocna' | '' (nedefinované) — default = odporca, ale pri striedavej/spoločnej beztak nezobrazujeme vzor
              nezverenyKey = rolaRodicaKey('odporca', navrhovatelPohlavie);
            }
            const pCount = Math.max(1, filledKids.length);
            return (
            <div style={{ marginTop: 24 }}>
              <p style={{ margin: '12px 0 6px' }}><strong>3.6 Navrhovaná úprava styku</strong>
                <TipBtn pointKey="zmena-3.6-styk" />
              </p>
              <p className="no-copy no-print" style={{ fontSize: '0.85em', color: 'var(--ink-3)', margin: '0 0 4px' }}>Aktuálna úprava styku podľa pôvodného rozhodnutia:</p>
              <Ed
                block xl noPersist
                ref={cl3z6_Aktualny_Ref}
                placeholder="Popis aktuálnej úpravy styku..."
                onValueChange={(v) => updateCl3z6('aktualnyStyk', v)}
              />

              {stykNeAplikovatelny ? (
                <p className="no-copy no-print" style={{ margin: '12px 0', fontStyle: 'italic', color: 'var(--ink-2)' }}>
                  Pri striedavej alebo spoločnej osobnej starostlivosti sa styk samostatne neupravuje — určuje ho zvolená forma starostlivosti.
                </p>
              ) : (
                <>
                  <p className="no-copy no-print" style={{ fontSize: '0.85em', color: 'var(--ink-3)', margin: '12px 0 4px' }}>Navrhovaná nová úprava styku:</p>
                  <div className="no-copy no-print" style={{ display: 'flex', flexWrap: 'wrap', gap: 8, margin: '0 0 8px' }}>
                    <button
                      type="button"
                      onClick={() => fillSampleZmena(cl3z6_Novy_Ref, sampleStyk_Joined(nezverenyKey, pCount), {}, { section: '3.6', variant: 'styk_kompletny' })}
                      style={{ fontSize: '0.82em', padding: '4px 10px', border: '1px solid var(--rule)', borderRadius: 'var(--r-sm)', background: 'var(--paper)', cursor: 'pointer', color: 'var(--ink-2)' }}
                    >Použiť vzorový text</button>
                  </div>
                  <Ed
                    block xl noPersist
                    ref={cl3z6_Novy_Ref}
                    placeholder="Opis navrhovaného styku — napr. víkendy, prázdniny, sviatky. Použite vzorový text vyššie alebo napíšte vlastný."
                    onValueChange={(v) => updateCl3z6('novyStyk', v)}
                  />
                </>
              )}

              <p className="no-copy no-print" style={{ fontSize: '0.85em', color: 'var(--ink-3)', margin: '12px 0 4px' }}>Odôvodnenie zmeny styku:</p>
              <div className="no-copy no-print" style={{ display: 'flex', flexWrap: 'wrap', gap: 8, margin: '0 0 8px' }}>
                {[
                  { label: 'Vzor 1 — Rozšírenie styku', tpl: SAMPLE_CL3Z_6_1, variant: 'styk_rozsirenie' },
                  { label: 'Vzor 2 — Obmedzenie styku', tpl: SAMPLE_CL3Z_6_2, variant: 'styk_obmedzenie' },
                ].map(({ label, tpl, variant }) => (
                  <button
                    key={label}
                    type="button"
                    onClick={() => fillSampleZmena(cl3z6_Odov_Ref, tpl, cl3zVars(navrhovatelPohlavie, filledKids.length, buildSudRef(sud1, sud2.aktivny ? sud2 : null)), { section: '3.6_odovodnenie', variant })}
                    style={{ fontSize: '0.82em', padding: '4px 10px', border: '1px solid var(--rule)', borderRadius: 'var(--r-sm)', background: 'var(--paper)', cursor: 'pointer', color: 'var(--ink-2)' }}
                  >{label}</button>
                ))}
              </div>
              <Ed
                block xl noPersist
                ref={cl3z6_Odov_Ref}
                placeholder="Odôvodnenie zmeny styku (3.6) — váš text..."
                onValueChange={(v) => updateCl3z6('odovodnenie', v)}
              />
            </div>
            );
          })()}
        </section>



        {/* Čl. IV — Pomery rodičov a výdavky na maloleté deti.
            § 62 ods. 2 ZoR (potreby/možnosti), § 117 CMP (vyšetrovacia zásada).
            Renderuje sa LEN ak je v 3.1 zaškrtnuté výživné. Inak sa Čl. V
            (Právny základ) preznačí na Čl. IV. Dáta v cl4 storage zostávajú. */}
        {zmenaVyber.vyzivne && (
        <section className="article" id="art-4">
          <div className="article-intro">
            <div className="article-head">
              <div className="article-num">Článok IV</div>
              <span className="article-title">Pomery rodičov a výdavky na maloleté deti</span>
            </div>

            <p className="has-tip">
              <TipBtn pointKey="art-4-pomery" />
              Na účely posúdenia odôvodnených potrieb maloletých detí podľa § 62 ods. 2 zákona č. 36/2005 Z. z. o rodine a v súlade s článkom 6 základných princípov zákona č. 161/2015 Z. z. (Civilný mimosporový poriadok) uvádzam priemerné mesačné a mimoriadne ročné výdavky vynakladané na maloleté {filledKids.length === 1 ? 'dieťa' : 'deti'}, ako aj svoje majetkové pomery.
            </p>
          </div>{/* /article-intro */}

          {/* 4.1 — Mesačné výdavky tabuľka */}
          <div className="has-tip" style={{ marginBottom: 24 }}>
            <TipBtn pointKey="4.1-vydavky-mesacne" />
            <p style={{ margin: '12px 0 6px' }}><strong>4.1 Mesačné výdavky na maloleté {filledKids.length === 1 ? 'dieťa' : 'deti'}</strong></p>
            <p className="no-copy no-print" style={{ fontStyle: 'italic', fontSize: '0.85em', color: 'var(--ink-3)', margin: '0 0 8px' }}>
              Uvádzam priemerné mesačné výdavky na každé maloleté dieťa samostatne. Sumy zahŕňajú alikvotnú časť spoločných výdavkov domácnosti pripadajúcu na dieťa.
            </p>
            {filledKids.length === 0 ? (
              <p className="no-copy no-print" style={{ fontStyle: 'italic', color: 'var(--ink-3)', margin: '8px 0' }}>
                [doplňte aspoň jedno maloleté dieťa v sekcii účastníkov vyššie]
              </p>
            ) : (
              <>
                <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.92em', marginBottom: 8 }}>
                  <thead>
                    <tr>
                      <th style={{ textAlign: 'left', padding: '6px', borderBottom: '1px solid var(--rule)', fontWeight: 600 }}>Položka</th>
                      {filledKids.map(kid => (
                        <th key={kid.id} style={{ textAlign: 'right', padding: '6px', borderBottom: '1px solid var(--rule)', fontWeight: 600 }}>
                          {kid.meno || '(meno?)'}
                        </th>
                      ))}
                      <th className="no-copy no-print" style={{ width: '32px', borderBottom: '1px solid var(--rule)' }}></th>
                    </tr>
                  </thead>
                  <tbody>
                    {Object.entries(cl4.vydavkyMesacne).map(([polozkaId, polozka]) => (
                      <tr key={polozkaId} style={{ borderBottom: '1px solid var(--rule-soft, #eee)' }}>
                        <td style={{ padding: '4px 6px', verticalAlign: 'top' }}>
                          <input
                            type="text"
                            className="no-copy no-print"
                            value={polozka.nazov}
                            onChange={(e) => setVydavokNazov('mesacne', polozkaId, e.target.value)}
                            style={{ width: '100%', padding: '4px 0', border: 'none', borderBottom: '1px dotted var(--rule)', background: 'transparent', fontFamily: 'var(--serif)', fontSize: '0.95em' }}
                          />
                          <span className="ed-select-print">{polozka.nazov}</span>
                        </td>
                        {filledKids.map(kid => {
                          const suma = (polozka.sumy || {})[kid.id] || '';
                          return (
                            <td key={kid.id} style={{ padding: '4px 6px', textAlign: 'right', verticalAlign: 'top' }}>
                              <input
                                type="text"
                                inputMode="decimal"
                                className="no-copy no-print"
                                value={suma}
                                onChange={(e) => setVydavokSuma('mesacne', polozkaId, kid.id, e.target.value)}
                                placeholder="—"
                                style={{ width: 70, padding: '4px 6px', border: '1px solid var(--rule)', borderRadius: 'var(--r-sm)', fontFamily: 'var(--serif)', fontSize: '0.95em', textAlign: 'right' }}
                              />
                              <span className="ed-select-print">{suma ? suma + ' €' : '—'}</span>
                            </td>
                          );
                        })}
                        <td className="no-copy no-print" style={{ verticalAlign: 'top', padding: '4px 0' }}>
                          <button
                            type="button"
                            onClick={() => removePolozka('mesacne', polozkaId)}
                            aria-label="Odstrániť položku"
                            title="Odstrániť položku"
                            style={{ background: 'transparent', border: 0, cursor: 'pointer', color: 'var(--ink-4)', fontSize: 14, padding: '0 6px' }}
                          >✕</button>
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
                <button
                  type="button"
                  className="party-add no-copy no-print"
                  onClick={() => addPolozka('mesacne')}
                  style={{ alignSelf: 'flex-start' }}
                >+ Pridať položku</button>
              </>
            )}
          </div>

          {/* 4.2 — Ročné/mimoriadne výdavky tabuľka s prepočtom 1/12 */}
          <div className="has-tip" style={{ marginBottom: 24 }}>
            <TipBtn pointKey="4.2-vydavky-rocne" />
            <p style={{ margin: '12px 0 6px' }}><strong>4.2 Mimoriadne a ročné výdavky na maloleté {filledKids.length === 1 ? 'dieťa' : 'deti'}</strong></p>
            <p className="no-copy no-print" style={{ fontStyle: 'italic', fontSize: '0.85em', color: 'var(--ink-3)', margin: '0 0 8px' }}>
              Okrem mesačných výdavkov vznikajú aj výdavky, ktoré sa neopakujú každý mesiac, ale počítajú sa za celý kalendárny rok. Sumy uvádzam za rok.
            </p>
            {filledKids.length === 0 ? (
              <p className="no-copy no-print" style={{ fontStyle: 'italic', color: 'var(--ink-3)', margin: '8px 0' }}>
                [doplňte aspoň jedno maloleté dieťa v sekcii účastníkov vyššie]
              </p>
            ) : (
              <>
                <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.92em', marginBottom: 8 }}>
                  <thead>
                    <tr>
                      <th style={{ textAlign: 'left', padding: '6px', borderBottom: '1px solid var(--rule)', fontWeight: 600 }}>Položka</th>
                      {filledKids.map(kid => (
                        <th key={kid.id} style={{ textAlign: 'right', padding: '6px', borderBottom: '1px solid var(--rule)', fontWeight: 600 }}>
                          {kid.meno || '(meno?)'}
                        </th>
                      ))}
                      <th className="no-copy no-print" style={{ width: '32px', borderBottom: '1px solid var(--rule)' }}></th>
                    </tr>
                  </thead>
                  <tbody>
                    {Object.entries(cl4.vydavkyRocne).map(([polozkaId, polozka]) => (
                      <tr key={polozkaId} style={{ borderBottom: '1px solid var(--rule-soft, #eee)' }}>
                        <td style={{ padding: '4px 6px', verticalAlign: 'top' }}>
                          <input
                            type="text"
                            className="no-copy no-print"
                            value={polozka.nazov}
                            onChange={(e) => setVydavokNazov('rocne', polozkaId, e.target.value)}
                            style={{ width: '100%', padding: '4px 0', border: 'none', borderBottom: '1px dotted var(--rule)', background: 'transparent', fontFamily: 'var(--serif)', fontSize: '0.95em' }}
                          />
                          <span className="ed-select-print">{polozka.nazov}</span>
                        </td>
                        {filledKids.map(kid => {
                          const suma = (polozka.sumy || {})[kid.id] || '';
                          const sumaNum = parseFloat(suma) || 0;
                          return (
                            <td key={kid.id} style={{ padding: '4px 6px', textAlign: 'right', verticalAlign: 'top' }}>
                              <input
                                type="text"
                                inputMode="decimal"
                                className="no-copy no-print"
                                value={suma}
                                onChange={(e) => setVydavokSuma('rocne', polozkaId, kid.id, e.target.value)}
                                placeholder="—"
                                style={{ width: 70, padding: '4px 6px', border: '1px solid var(--rule)', borderRadius: 'var(--r-sm)', fontFamily: 'var(--serif)', fontSize: '0.95em', textAlign: 'right' }}
                              />
                              {sumaNum > 0 && (
                                <div className="no-copy no-print" style={{ fontSize: '0.72em', color: 'var(--ink-3)', textAlign: 'right', marginTop: 2 }}>
                                  = {(sumaNum / 12).toFixed(2)} €/mes.
                                </div>
                              )}
                              <span className="ed-select-print">
                                {suma ? suma + ' € / rok = ' + (sumaNum / 12).toFixed(2) + ' € / mes.' : '—'}
                              </span>
                            </td>
                          );
                        })}
                        <td className="no-copy no-print" style={{ verticalAlign: 'top', padding: '4px 0' }}>
                          <button
                            type="button"
                            onClick={() => removePolozka('rocne', polozkaId)}
                            aria-label="Odstrániť položku"
                            title="Odstrániť položku"
                            style={{ background: 'transparent', border: 0, cursor: 'pointer', color: 'var(--ink-4)', fontSize: 14, padding: '0 6px' }}
                          >✕</button>
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
                <button
                  type="button"
                  className="party-add no-copy no-print"
                  onClick={() => addPolozka('rocne')}
                  style={{ alignSelf: 'flex-start' }}
                >+ Pridať položku</button>
              </>
            )}
          </div>

          {/* 4.3 — Súčty a priemery */}
          {filledKids.length > 0 && (
            <div className="has-tip" style={{ marginBottom: 24 }}>
              <TipBtn pointKey="4.3-sucty" />
              <p style={{ margin: '12px 0 6px' }}><strong>4.3 Súčty výdavkov</strong></p>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
                {filledKids.map(kid => {
                  const v = spocitajVydavky(cl4.vydavkyMesacne, cl4.vydavkyRocne, kid.id);
                  return (
                    <div key={kid.id} style={{ padding: '10px 14px', background: 'var(--ivory-2)', borderRadius: 'var(--r-sm)', border: '1px solid var(--rule)' }}>
                      <div style={{ fontWeight: 600, marginBottom: 6 }}>
                        {kid.meno || '(meno?)'}{kid.datumNarodenia ? ', nar. ' + kid.datumNarodenia : ''}
                      </div>
                      <div style={{ fontSize: '0.92em', lineHeight: 1.6 }}>
                        Mesačné výdavky spolu: <strong>{v.mesacne.toFixed(2)} €</strong><br />
                        Ročné výdavky spolu: <strong>{v.rocne.toFixed(2)} €</strong><br />
                        Ročné prepočítané mesačne (1/12): <strong>{v.rocnePrepocitane.toFixed(2)} €</strong><br />
                        <span style={{ fontWeight: 600, color: 'var(--oxblood)' }}>
                          Priemerné mesačné výdavky na dieťa: {v.priemernaSumaMesacne.toFixed(2)} €
                        </span>
                      </div>
                    </div>
                  );
                })}
                {filledKids.length > 1 && (() => {
                  const total = filledKids.reduce((acc, kid) => {
                    const v = spocitajVydavky(cl4.vydavkyMesacne, cl4.vydavkyRocne, kid.id);
                    return acc + v.priemernaSumaMesacne;
                  }, 0);
                  return (
                    <div style={{ padding: '10px 14px', background: 'var(--paper)', borderRadius: 'var(--r-sm)', border: '1px solid var(--oxblood)', fontWeight: 600 }}>
                      Priemerné mesačné výdavky na všetky maloleté deti spolu: <span style={{ color: 'var(--oxblood)' }}>{total.toFixed(2)} €</span>
                    </div>
                  );
                })()}
              </div>
            </div>
          )}

          {/* 4.4 — Majetkové pomery navrhovateľa */}
          <div className="has-tip" style={{ marginBottom: 24 }}>
            <TipBtn pointKey="4.4-pomery-navrh" />
            <p style={{ margin: '12px 0 6px' }}><strong>4.4 Majetkové pomery {oznacenie('navrhovatel', navrhovatelPohlavie, 'gen')}</strong></p>
            <p className="no-copy no-print" style={{ fontStyle: 'italic', fontSize: '0.85em', color: 'var(--ink-3)', margin: '0 0 8px' }}>
              Uvádzam svoje aktuálne majetkové pomery na účel posúdenia určenia výšky vyživovacej povinnosti podľa § 62 ods. 2 zákona č. 36/2005 Z. z. o rodine.
            </p>

            {/* Status radio */}
            <div className="no-copy no-print" style={{ display: 'flex', flexDirection: 'column', gap: 6, fontSize: '0.92em', padding: '10px 12px', background: 'var(--ivory-2)', borderRadius: 'var(--r-sm)', border: '1px solid var(--rule)', marginBottom: 8 }}>
              <div style={{ fontFamily: 'var(--mono)', fontSize: '0.78em', letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--ink-3)', marginBottom: 4 }}>Aktuálny pracovný a ekonomický status:</div>
              {Object.entries(STATUS_LABELS).map(([v, label]) => (
                <label key={v} style={{ display: 'flex', gap: 8, alignItems: 'baseline', cursor: 'pointer' }}>
                  <input
                    type="radio"
                    name="cl4-pomer-status"
                    value={v}
                    checked={cl4.navrhPomerStatus === v}
                    onChange={() => setCl4Field('navrhPomerStatus', v)}
                  />
                  <span>{label}</span>
                </label>
              ))}
              {cl4.navrhPomerStatus === 'g' && (
                <div style={{ marginTop: 6, display: 'flex', gap: 8, alignItems: 'baseline' }}>
                  <span>Vlastný popis:</span>
                  <input
                    type="text"
                    value={cl4.navrhPomerInecaste}
                    onChange={(e) => setCl4Field('navrhPomerInecaste', e.target.value)}
                    style={{ flex: 1, padding: '4px 8px', border: '1px solid var(--rule)', borderRadius: 'var(--r-sm)', fontFamily: 'var(--serif)', fontSize: '0.95em' }}
                  />
                </div>
              )}
            </div>

            {/* Materializovaný status pre PDF/Word. Pri statuse 'g' (Iné) sa zobrazí
                len obsah Ed poľa navrhPomerInecaste, bez prefixu "Iné — ". Ak je
                Ed prázdny, inline placeholder no-print upozorní na chýbajúci údaj. */}
            <p style={{ margin: '8px 0' }}>
              <strong>Pracovný a ekonomický status:</strong>{' '}
              {cl4.navrhPomerStatus === 'g'
                ? (cl4.navrhPomerInecaste.trim()
                    ? cl4.navrhPomerInecaste
                    : <PetitPh>[doplňte status v Čl. IV bod 4.4]</PetitPh>)
                : statusLabel(cl4.navrhPomerStatus)}.
            </p>

            {/* Štruktúrované polia — viditeľné podľa zvoleného statusu cez STATUS_FIELDS_44.
                Hodnoty ostatných polí v state ostávajú (prepínanie statusu nestratí dáta). */}
            {(STATUS_FIELDS_44[cl4.navrhPomerStatus] || STATUS_FIELDS_44.a).zamestnavatel && (
              <p style={{ margin: '8px 0' }}>
                Zamestnávateľ / firma / inštitúcia: <Ed defaultValue="" placeholder="názov a sídlo zamestnávateľa, firmy alebo inštitúcie" lg onValueChange={(v) => setFields44(f => ({ ...f, zamestnavatel: v }))} />
              </p>
            )}
            {(STATUS_FIELDS_44[cl4.navrhPomerStatus] || STATUS_FIELDS_44.a).pozicia && (
              <p style={{ margin: '8px 0' }}>
                Pozícia: <Ed defaultValue="" placeholder="pracovná pozícia" lg onValueChange={(v) => setFields44(f => ({ ...f, pozicia: v }))} />
              </p>
            )}
            {(STATUS_FIELDS_44[cl4.navrhPomerStatus] || STATUS_FIELDS_44.a).predmet && (
              <p style={{ margin: '8px 0' }}>
                Predmet podnikania: <Ed defaultValue="" placeholder="hlavný predmet podnikania" lg onValueChange={(v) => setFields44(f => ({ ...f, predmet: v }))} />
              </p>
            )}
            {(STATUS_FIELDS_44[cl4.navrhPomerStatus] || STATUS_FIELDS_44.a).obchodneMeno && (
              <p style={{ margin: '8px 0' }}>
                Obchodné meno spoločnosti: <Ed defaultValue="" placeholder="napr. ABC, s.r.o." lg onValueChange={(v) => setFields44(f => ({ ...f, obchodneMeno: v }))} />
              </p>
            )}
            {(STATUS_FIELDS_44[cl4.navrhPomerStatus] || STATUS_FIELDS_44.a).postavenie && (
              <p style={{ margin: '8px 0' }}>
                Postavenie: <Ed defaultValue="" placeholder="spoločník / konateľ / spoločník a konateľ" lg onValueChange={(v) => setFields44(f => ({ ...f, postavenie: v }))} />
              </p>
            )}
            <p style={{ margin: '8px 0' }}>
              Mesačný čistý príjem (priemer za posledných 12 mesiacov): <Ed defaultValue="" placeholder="priemerný mesačný čistý príjem" num onValueChange={(v) => setFields44(f => ({ ...f, prijem: v }))} /> €
            </p>

            {/* Súhrnný opis — Ed block + direct-insert button (skryté pri statuse 'g'). */}
            <div style={{ marginTop: 12 }}>
              <p style={{ margin: '0 0 6px' }}>
                <strong>Súhrnný opis pomerov {oznacenie('navrhovatel', navrhovatelPohlavie, 'gen')}</strong>
              </p>
              {cl4.navrhPomerStatus === 'g' ? (
                <p className="no-copy no-print" style={{ fontStyle: 'italic', fontSize: '0.85em', color: 'var(--ink-3)', margin: '6px 0 8px' }}>
                  Pri statuse „Iné" vzor nie je k dispozícii — vyplňte vlastnými slovami.
                </p>
              ) : (
                <>
                  <div className="no-copy no-print" style={{ display: 'flex', flexWrap: 'wrap', gap: 8, margin: '6px 0 8px' }}>
                    <button
                      type="button"
                      onClick={() => {
                        fillSampleHtml('cl4_44_Ref', sample44(cl4.navrhPomerStatus, navrhovatelPohlavie, fields44) || '', { section: '4.4', variant: cl4.navrhPomerStatus, action: 'use' });
                        setLastSampleFields44({ ...fields44 });
                      }}
                      style={{ fontSize: '0.82em', padding: '4px 10px', border: '1px solid var(--rule)', borderRadius: 'var(--r-sm)', background: 'var(--paper)', cursor: 'pointer', color: 'var(--ink-2)' }}
                    >Použiť vzorový text</button>
                    {fields44Changed && (
                      <button
                        type="button"
                        onClick={() => {
                          if (!window.confirm('Vzorový text bude prepísaný novou verziou. Manuálne úpravy, ktoré ste v tomto texte urobili sa stratia. Ostatné vyplnené polia zostanú zachované. Pokračovať?')) {
                            return;
                          }
                          fillSampleHtml('cl4_44_Ref', sample44(cl4.navrhPomerStatus, navrhovatelPohlavie, fields44) || '', { section: '4.4', variant: cl4.navrhPomerStatus, action: 'update' });
                          setLastSampleFields44({ ...fields44 });
                        }}
                        style={{ fontSize: '0.82em', padding: '4px 10px', border: '1px solid var(--rule)', borderRadius: 'var(--r-sm)', background: 'var(--paper)', cursor: 'pointer', color: 'var(--ink-2)' }}
                      >Aktualizovať vzorový text</button>
                    )}
                  </div>
                  {fields44Changed && (
                    <p className="no-copy no-print" style={{ margin: '0 0 8px', fontSize: '0.85em', color: 'var(--ink-3)', fontStyle: 'italic' }}>
                      Polia o zamestnaní/príjme sa zmenili — vzorový text neodráža aktuálne hodnoty.
                    </p>
                  )}
                </>
              )}
              <Ed block ref={cl4_44_Ref} placeholder="Sem vložte podrobnejší opis svojich majetkových pomerov — kliknite na 'Použiť vzorový text' alebo napíšte vlastný text." />
            </div>
          </div>

          {/* 4.5 — Majetkové pomery odporcu (voliteľné) */}
          <div className="has-tip" style={{ marginBottom: 24 }}>
            <TipBtn pointKey="4.5-pomery-odp" />
            <p style={{ margin: '12px 0 6px' }}><strong>4.5 Majetkové pomery {oznacenie('odporca', odporcaPohlavie, 'gen')} (voliteľné)</strong></p>
            <p style={{ margin: '0 0 8px' }}>
              Údaje o majetkových pomeroch {oznacenie('odporca', odporcaPohlavie, 'gen')} sú navrhovateľovi známe len v obmedzenom rozsahu. Súd ich v zmysle zákona č. 161/2015 Z. z. (Civilný mimosporový poriadok) zistí samostatne, najmä výzvou {oznacenie('odporca', odporcaPohlavie, 'dat')} na predloženie dôkazov o príjmoch a majetkových pomeroch.
            </p>
            <div className="no-copy no-print" style={{ marginTop: 8 }}>
              <label style={{ display: 'flex', gap: 8, alignItems: 'baseline', cursor: 'pointer', fontSize: '0.92em' }}>
                <input
                  type="checkbox"
                  checked={cl4.uvadzamPomerOdporcu}
                  onChange={() => setCl4Field('uvadzamPomerOdporcu', !cl4.uvadzamPomerOdporcu)}
                />
                <span>Uvádzam aj približné majetkové pomery {oznacenie('odporca', odporcaPohlavie, 'gen')} (voliteľné)</span>
              </label>
            </div>
            {cl4.uvadzamPomerOdporcu && (
              <div style={{ marginTop: 8 }}>
                <p style={{ margin: '0 0 6px' }}>
                  <strong>Opis pomerov {oznacenie('odporca', odporcaPohlavie, 'gen')}</strong>
                </p>
                <Ed
                  block
                  ref={cl4_45_Ref}
                  placeholder="Uveďte, čo viete o pracovnej situácii, príjmoch a majetkových pomeroch druhého rodiča. Ak presné údaje nepoznáte, uveďte približne."
                />
              </div>
            )}
          </div>

          {/* Sub-blok Dôkazy — analogický k Dôkaz v Čl. I, ale ako voľné Ed
              pole. Riadky sa konsolidujú do prílohovej sekcie na konci dokumentu. */}
          <div className="has-tip" style={{ marginBottom: 24 }}>
            <TipBtn pointKey="4-dokazy" />
            <p style={{ margin: '12px 0 6px' }}><strong>Dôkazy</strong></p>
            <p style={{ margin: '0 0 8px' }}>
              Na preukázanie skutočností uvedených v tomto článku predkladám súdu tieto dôkazy:
            </p>
            {/* Wrapper s CSS var pre kratšie min-height (cca 2 riadky).
                Persist scope identifikácia ide cez data-placeholder text Ed
                elementu, ktorý je rovnaký ako PH_4DOKAZY constant v listenere. */}
            <div style={{ '--ed-block-min-height': '60px' }}>
              <Ed
                block
                ref={cl4_dokazy_Ref}
                placeholder="Sem napíšte zoznam dôkazov, každý dôkaz na samostatný riadok. Napríklad: potvrdenie o priemernom čistom mesačnom zárobku od zamestnávateľa, daňové priznanie za minulý rok, výpis z katastra nehnuteľností, potvrdenie z úradu práce o evidencii a výške dávky v nezamestnanosti."
              />
            </div>
          </div>
        </section>
        )}

        {/* Čl. V — Právny základ a návrh výroku.
            Page-break: žiadny forced break-before; .article-intro drží header
            a prvý odsek 5.1 (§ 24) pohromade cez page-break-inside: avoid. */}
        <section className="article" id="art-5">
          <div className="article-intro">
            <div className="article-head">
              <div className="article-num">Článok {cl5Num}</div>
              <span className="article-title">Právny základ a návrh výroku</span>
            </div>

            <p className="has-tip" style={{ textAlign: 'justify' }}>
              <TipBtn pointKey="5.1-pravny-zaklad" />
              <strong>{cl5Bod(1)}</strong>&nbsp;&nbsp;Návrh sa podáva podľa § 26 zákona č. 36/2005 Z. z. o rodine v platnom znení (ďalej len „zákon o rodine"), ktorý umožňuje zmenu rozhodnutia alebo dohody rodičov o výkone rodičovských práv a povinností pri zmene pomerov. Pri zmene výživného sa uplatňuje aj § 78 ods. 1 zákona o rodine. Procesne sa konanie vedie podľa § 111 a nasl. zákona č. 161/2015 Z. z. (Civilný mimosporový poriadok). Miestne príslušným je okresný súd, v obvode ktorého má maloleté dieťa bydlisko (§ 112 ods. 1 zákona č. 161/2015 Z. z.). Konanie je oslobodené od súdneho poplatku podľa § 4 ods. 1 písm. a) zákona č. 71/1992 Zb. o súdnych poplatkoch.
            </p>
          </div>

          <p className="has-tip" style={{ margin: '20px 0' }}>
            <TipBtn pointKey="5.2-petit" />
            <strong>{cl5Bod(2)}</strong>&nbsp;&nbsp;Vzhľadom na vyššie uvedené žiadam, aby súd po vykonaní dokazovania rozhodol takto:
          </p>
        </section>

        {/* Návrh výroku — dynamický petit pre zmenu rozhodnutia.
            Renderuje výroky podľa zaškrtnutých 4 boxov v 3.1; ak nič nie
            je zaškrtnuté, zobrazí varovanie. Záverečná veta s buildSudRefPetit
            a zoznam zaškrtnutých oblastí. */}
        <section className="proposed-verdict" id="art-verdict">
          {(() => {
            const pCount = filledKids.length;
            const sg = pCount === 1;
            const dietaVsDeti = sg ? 'dieťa' : 'deti';
            const dietatVsDetmiInstr = sg ? 'dieťaťom' : 'deťmi';
            const navrhKey = rolaRodicaKey('navrhovatel', navrhovatelPohlavie);
            const druhyKey = rolaRodicaKey('odporca', navrhovatelPohlavie);
            const navrhNomCap = navrhKey === 'matka' ? 'Matka' : 'Otec';
            const druhyNomCap = druhyKey === 'matka' ? 'Matka' : 'Otec';
            const navrhPovinny = navrhKey === 'matka' ? 'povinná' : 'povinný';
            const druhyPovinny = druhyKey === 'matka' ? 'povinná' : 'povinný';
            const navrhGen = ROLA_RODICA_FORMS[navrhKey].gen;
            const druhyGen = ROLA_RODICA_FORMS[druhyKey].gen;
            const druhyDat = ROLA_RODICA_FORMS[druhyKey].dat;
            // Zoznam mien detí oddelených čiarkami (pre petit, fallback ak vyživné má 1 dieťa).
            const menaDetiList = filledKids
              .filter(k => k.meno.trim())
              .map(k => k.meno.trim() + (k.datumNarodenia.trim() ? `, nar. ${formatDatumDmRRRR(k.datumNarodenia)}` : ''))
              .join(', ');
            const sudRefPetit = buildSudRefPetit(sud1, sud2.aktivny ? sud2 : null);

            // Styk pri striedavej/spoločnej forme starostlivosti sa samostatne neupravuje.
            // Vyhodíme ho z výrokov aj z oblastiSelected, aby výsledný petit bol konzistentný.
            const stykNeAplikovatelny = zmenaVyber.zverenie && (cl3z3.novaForma === 'striedava' || cl3z3.novaForma === 'spolocna');
            const stykEffective = zmenaVyber.styk && !stykNeAplikovatelny;

            const oblastiSelected = [];
            if (zmenaVyber.zverenie) oblastiSelected.push('zverenia');
            if (zmenaVyber.vyzivne) oblastiSelected.push('výživného');
            if (stykEffective) oblastiSelected.push('styku');
            if (zmenaVyber.zastupovanie) oblastiSelected.push('zastupovania a správy majetku');

            // Spojiť slová: 1 → "X", 2 → "X a Y", 3+ → "X, Y a Z".
            const joinAnd = (arr) => {
              if (arr.length === 0) return '';
              if (arr.length === 1) return arr[0];
              if (arr.length === 2) return `${arr[0]} a ${arr[1]}`;
              return `${arr.slice(0, -1).join(', ')} a ${arr[arr.length - 1]}`;
            };

            const ziadnaZmena = !zmenaVyber.zverenie && !zmenaVyber.vyzivne && !zmenaVyber.zastupovanie && !zmenaVyber.styk;

            if (ziadnaZmena) {
              return (
                <p style={{ fontStyle: 'italic', color: 'var(--oxblood)', margin: '12px 0', textAlign: 'center' }}>
                  ⚠ Pre vygenerovanie petitu vyberte v bode 3.1 aspoň jednu časť rozhodnutia, ktorú chcete zmeniť.
                </p>
              );
            }

            const vyroky = [];
            let romanIdx = 0;

            // Výrok ZVERENIE — dynamický rod (matka/otec), žiadne navrhovateľ/-ka.
            if (zmenaVyber.zverenie) {
              romanIdx++;
              const label = ROMAN_PETIT[romanIdx];
              let text;
              switch (cl3z3.novaForma) {
                case 'osobna-navrhovatel':
                  text = `Maloleté ${dietaVsDeti}${menaDetiList ? ' ' + menaDetiList : ''} sa ${sg ? 'zveruje' : 'zverujú'} do osobnej starostlivosti ${navrhGen}.`;
                  break;
                case 'osobna-odporca':
                  text = `Maloleté ${dietaVsDeti}${menaDetiList ? ' ' + menaDetiList : ''} sa ${sg ? 'zveruje' : 'zverujú'} do osobnej starostlivosti ${druhyGen}.`;
                  break;
                case 'striedava':
                  text = `Maloleté ${dietaVsDeti}${menaDetiList ? ' ' + menaDetiList : ''} sa ${sg ? 'zveruje' : 'zverujú'} do striedavej osobnej starostlivosti oboch rodičov v intervaloch [doplňte režim].`;
                  break;
                case 'spolocna':
                  text = `Maloleté ${dietaVsDeti}${menaDetiList ? ' ' + menaDetiList : ''} sa ${sg ? 'zveruje' : 'zverujú'} do spoločnej osobnej starostlivosti oboch rodičov.`;
                  break;
                default:
                  text = `[doplňte v bode 3.3 navrhovanú formu starostlivosti]`;
              }
              vyroky.push({ label, text });
            }

            // Výrok VYŽIVNÉ — per-dieťa štruktúra. Pri 2+ deťoch s rovnakým typom
            // zmeny → odrážky a) b) c). Pri zmiešaných typoch → zoskupíme podľa typu
            // a každú skupinu uvedieme samostatne v jednom výroku.
            if (zmenaVyber.vyzivne) {
              romanIdx++;
              const label = ROMAN_PETIT[romanIdx];
              const kidsWithName = filledKids.filter(k => k.meno && k.meno.trim());
              const formatKid = (kid) => {
                const meno = (kid.meno || '').trim();
                const dat = (kid.datumNarodenia || '').trim();
                return dat ? `${meno}, nar. ${formatDatumDmRRRR(dat)}` : meno;
              };
              const getRow = (kid) => {
                const r = (cl3z4.perDieta || {})[kid.id] || {};
                return {
                  typZmeny: r.typZmeny || '',
                  stara: (r.staraVyska || '').trim() || '[doterajšia suma]',
                  nova: (r.novaVyska || '').trim() || '[nová suma]',
                };
              };
              let text;
              if (kidsWithName.length === 0) {
                text = `[doplňte v Čl. I aspoň jedno maloleté dieťa s menom a v bode 3.4 zvoľte typ zmeny výživného]`;
              } else {
                // Zoskupiť podľa typZmeny.
                const groups = { zvysenie: [], znizenie: [], zrusenie: [], '': [] };
                kidsWithName.forEach(k => {
                  const r = getRow(k);
                  (groups[r.typZmeny] || groups['']).push({ kid: k, ...r });
                });
                const segments = [];
                const renderOdrazky = (items, formatter) => items
                  .map((it, i) => {
                    const letter = String.fromCharCode(97 + i);
                    const sep = i === items.length - 1 ? '.' : ';';
                    return `${letter}) ${formatter(it)}${sep}`;
                  })
                  .join(' ');

                if (groups.zvysenie.length > 0) {
                  if (groups.zvysenie.length === 1 && kidsWithName.length === 1) {
                    const it = groups.zvysenie[0];
                    segments.push(`${druhyNomCap} je ${druhyPovinny} prispievať na výživu maloletého ${formatKid(it.kid)} sumou ${it.nova} EUR mesačne, vždy do 15. dňa kalendárneho mesiaca vopred, k rukám ${navrhGen}, počnúc dňom podania tohto návrhu na súd, namiesto doteraz určenej sumy ${it.stara} EUR mesačne.`);
                  } else {
                    const odrazky = renderOdrazky(groups.zvysenie, (it) => `na maloletého ${formatKid(it.kid)} sumou ${it.nova} EUR mesačne namiesto doterajšej sumy ${it.stara} EUR mesačne`);
                    segments.push(`${druhyNomCap} je ${druhyPovinny} prispievať na výživu maloletých detí takto: ${odrazky} Výživné je splatné vždy do 15. dňa kalendárneho mesiaca vopred, k rukám ${navrhGen}, počnúc dňom podania tohto návrhu na súd.`);
                  }
                }
                if (groups.znizenie.length > 0) {
                  if (groups.znizenie.length === 1 && kidsWithName.length === 1) {
                    const it = groups.znizenie[0];
                    segments.push(`Výživné na maloleté ${formatKid(it.kid)} sa znižuje zo sumy ${it.stara} EUR mesačne na sumu ${it.nova} EUR mesačne, vždy do 15. dňa kalendárneho mesiaca vopred, k rukám ${navrhGen}, počnúc dňom podania tohto návrhu na súd.`);
                  } else {
                    const odrazky = renderOdrazky(groups.znizenie, (it) => `na maloletého ${formatKid(it.kid)} zo sumy ${it.stara} EUR mesačne na sumu ${it.nova} EUR mesačne`);
                    segments.push(`Výživné sa znižuje takto: ${odrazky} Zmena platí vždy do 15. dňa kalendárneho mesiaca vopred, k rukám ${navrhGen}, počnúc dňom podania tohto návrhu na súd.`);
                  }
                }
                if (groups.zrusenie.length > 0) {
                  if (groups.zrusenie.length === 1 && kidsWithName.length === 1) {
                    const it = groups.zrusenie[0];
                    segments.push(`Vyživovacia povinnosť ${druhyGen} voči maloletému ${formatKid(it.kid)} zaniká dňom [doplňte dátum].`);
                  } else {
                    const odrazky = renderOdrazky(groups.zrusenie, (it) => `voči maloletému ${formatKid(it.kid)} ku dňu [doplňte dátum]`);
                    segments.push(`Vyživovacia povinnosť ${druhyGen} sa ruší takto: ${odrazky}`);
                  }
                }
                if (groups[''].length > 0) {
                  // Deti, ktoré nemajú zvolený typ zmeny — placeholder upozornenie.
                  const odrazky = renderOdrazky(groups[''], (it) => `na maloletého ${formatKid(it.kid)} [doplňte v bode 3.4 typ zmeny]`);
                  segments.push(`[Pre nasledujúce deti vyberte v bode 3.4 typ zmeny výživného: ${odrazky}]`);
                }
                text = segments.join(' ');
              }
              vyroky.push({ label, text });
            }

            // Výrok ZASTUPOVANIE — dynamický rod (matka/otec), žiadne navrhovateľ/-ka.
            if (zmenaVyber.zastupovanie) {
              romanIdx++;
              const label = ROMAN_PETIT[romanIdx];
              let text;
              switch (cl3z5.noveZastupovanie) {
                case 'samostatne-navrhovatel':
                  text = `Maloleté ${dietaVsDeti}${menaDetiList ? ' ' + menaDetiList : ''} bude zastupovať a spravovať ${sg ? 'jeho' : 'ich'} majetok samostatne ${navrhNomCap.toLowerCase()}.`;
                  break;
                case 'samostatne-odporca':
                  text = `Maloleté ${dietaVsDeti}${menaDetiList ? ' ' + menaDetiList : ''} bude zastupovať a spravovať ${sg ? 'jeho' : 'ich'} majetok samostatne ${druhyNomCap.toLowerCase()}.`;
                  break;
                case 'spolocne':
                  text = `Maloleté ${dietaVsDeti}${menaDetiList ? ' ' + menaDetiList : ''} ${sg ? 'bude zastupovať' : 'budú zastupovať'} a spravovať ${sg ? 'jeho' : 'ich'} majetok spoločne obaja rodičia.`;
                  break;
                default:
                  text = `[doplňte v bode 3.5 navrhovaný spôsob zastupovania]`;
              }
              vyroky.push({ label, text });
            }

            // Výrok STYK — len ak je styk samostatne aplikovateľný (nie pri striedavej/spoločnej).
            if (stykEffective) {
              romanIdx++;
              const label = ROMAN_PETIT[romanIdx];
              const styk = (cl3z6.novyStyk || '').trim();
              const text = `Styk ${druhyGen} s maloletým ${dietatVsDetmiInstr}${menaDetiList ? ' ' + menaDetiList : ''} sa upravuje takto: ${styk || '[obsah z bodu 3.6 — Navrhovaná nová úprava styku]'}`;
              vyroky.push({ label, text });
            }

            // Záverečná veta + trovy konania majú vlastné rímske čísla v poradí.
            romanIdx++;
            const labelZav = ROMAN_PETIT[romanIdx];
            const textZav = `Týmto sa mení ${sudRefPetit || '[doplňte v Čl. II údaje o predchádzajúcom rozhodnutí]'} ${oblastiSelected.length === 1 ? 'v časti týkajúcej sa' : 'v častiach týkajúcich sa'} ${joinAnd(oblastiSelected)}.`;

            romanIdx++;
            const labelTrovy = ROMAN_PETIT[romanIdx];
            const textTrovy = 'O trovách konania súd rozhodne osobitným uznesením po právoplatnosti rozsudku vo veci samej.';

            return (
              <>
                {vyroky.map((v, i) => (
                  <p key={'vyrok-' + i} style={{ margin: '12px 0', textAlign: 'justify' }}>
                    <strong>{v.label}.</strong>&nbsp;&nbsp;{v.text}
                  </p>
                ))}

                {/* Záverečná veta */}
                <p style={{ margin: '16px 0', textAlign: 'justify' }}>
                  <strong>{labelZav}.</strong>&nbsp;&nbsp;{textZav}
                </p>

                {/* Trovy konania */}
                <p style={{ margin: '12px 0', textAlign: 'justify' }}>
                  <strong>{labelTrovy}.</strong>&nbsp;&nbsp;{textTrovy}
                </p>
              </>
            );
          })()}
        </section>

        {/* Záverečná časť — podpis + prílohy spolu, aby sa nezalomili na rôzne strany */}
        <div style={{ pageBreakInside: 'avoid', breakInside: 'avoid' }}>
          <div className="signature-row" style={{ marginTop: 24, display: 'flex', justifyContent: 'flex-end' }}>
            <div style={{ textAlign: 'center', minWidth: 240 }}>
              <div style={{ borderBottom: '1px solid var(--ink)', marginBottom: 6, height: 28 }}></div>
              <div className="no-print" style={{ fontFamily: 'var(--serif)' }}>{menoNavrhovatela}</div>
              <span className="ed-select-print">{menoNavrhovatela}</span>
            </div>
          </div>

          {/* Prílohy — pri zmene rozhodnutia: rodné listy + predchádzajúce
              rozhodnutie/-tia z Čl. II. */}
          <div className="prilohy" style={{ marginTop: 36 }}>
            <p>&nbsp;</p>
            <p>&nbsp;</p>
            <p><TipBtn pointKey="prilohy" /><strong>Prílohy:</strong></p>
            {filledKids
              .filter(k => k.meno.trim() !== '' && k.datumNarodenia.trim() !== '')
              .map(kid => (
                <p key={'rodlist-' + kid.id}>– rodný list maloletého dieťaťa - {kid.meno.trim()}, nar. {kid.datumNarodenia.trim()}</p>
              ))
            }
            {sud1.nazov && sud1.nazov.trim() && (() => {
              const druhCap = sud1.druh === 'rozsudok' ? 'Rozsudok' : 'Uznesenie';
              const ref = `${druhCap} ${sud1.nazov.trim()}` +
                (sud1.sznacka && sud1.sznacka.trim() ? ` sp. zn. ${sud1.sznacka.trim()}` : '') +
                (sud1.datum && sud1.datum.trim() ? ` zo dňa ${formatDatumDmRRRR(sud1.datum)}` : '');
              return <p key="sud1-priloha">– {ref}</p>;
            })()}
            {sud2.aktivny && sud2.nazov && sud2.nazov.trim() && (() => {
              const druhCap = sud2.druh === 'rozsudok' ? 'Rozsudok' : 'Uznesenie';
              const ref = `${druhCap} ${sud2.nazov.trim()}` +
                (sud2.sznacka && sud2.sznacka.trim() ? ` sp. zn. ${sud2.sznacka.trim()}` : '') +
                (sud2.datum && sud2.datum.trim() ? ` zo dňa ${formatDatumDmRRRR(sud2.datum)}` : '');
              return <p key="sud2-priloha">– {ref}</p>;
            })()}
            <p>
              {dalsieDokazy && (
                <span className="ed-select-print">– {dalsieDokazy}</span>
              )}
              <span className="no-print">– <SyncedEd value={dalsieDokazy} onChange={setDalsieDokazy} placeholder="ďalšie dôkazy" /></span>
            </p>
          </div>
        </div>

      </article>

      {/* Actions — obrazovka only, print/Word skrýva (CSS ich rieši cez @media print) */}
      <div className="paper-actions no-print" role="group" aria-label="Akcie s návrhom">
        <div className="paper-actions__row">
          <button type="button" className="btn-download" onClick={() => {
            if (typeof window.trackEvent === 'function') {
              window.trackEvent('download_pdf', { progress: typeof window.__CURRENT_PROGRESS === 'number' ? window.__CURRENT_PROGRESS : null });
            }
            const originalTitle = document.title;
            document.title = 'Vzor-z-www.vyzivnenadieta.sk-navrh-na-zmenu-vo-veci-maloletych';
            window.print();
            setTimeout(() => { document.title = originalTitle; }, 1000);
          }}>
            <span className="btn-download__glyph" aria-hidden="true">↓</span>
            <span className="btn-download__main">Stiahnuť ako PDF</span>
            <span className="btn-download__meta">A4</span>
          </button>
          <button type="button" className="btn-download btn-download--ghost" onClick={() => window.__downloadAsDocZmena && window.__downloadAsDocZmena()}>
            <span className="btn-download__glyph" aria-hidden="true">↓</span>
            <span className="btn-download__main">Stiahnuť ako Word</span>
            <span className="btn-download__meta">.doc</span>
          </button>
          <button type="button" className="btn-download btn-download--danger" onClick={() => window.__clearFormFields && window.__clearFormFields()}>
            <span className="btn-download__glyph" aria-hidden="true">✕</span>
            <span className="btn-download__main">Vymazať údaje</span>
            <span className="btn-download__meta">natrvalo</span>
          </button>
        </div>
        <p className="paper-actions__note">
          PDF sa otvorí v dialógu tlače prehliadača — v cieli zvoľte <em>Uložiť ako PDF</em>. Word (.doc) otvoríte v MS Word alebo LibreOffice a môžete návrh ďalej upraviť.
        </p>
      </div>
    </div>
    </TipContext.Provider>
  );
};

// ============================================================
// downloadAsDoc — export paper HTML to .doc (Word)
// Class names referenced: .paper, .article, .article-head, .article-num,
// .article-title, .doc-title, .doc-sub, .ed, .ed-select, .ed-select-print,
// .paper-actions, .signatures, .sig-block, .sig-person, .sig-cap, .sig-name,
// .sig-line, .doc-footer-meta, .party-alias, .party-alias-term, .tip-pin
// ============================================================
function downloadAsDoc() {
  const article = document.querySelector('article.paper');
  if (!article) return;
  const clone = article.cloneNode(true);

  // 1) Remove chrome that has no meaning on paper
  const killSelectors = [
    '.tip-pin', '.tip-pin-inline', '.tip-back',
    '.seg-toggle', '.seg-add',
    '.party-add', '.party-type-switch', '.party-type-switch-sub',
    '.party-type-switch-wrap', '.inflation-variant-picker',
    '.legal-hint',
    '.no-copy', '.no-print',
  ];
  clone.querySelectorAll(killSelectors.join(',')).forEach(el => el.remove());

  // 2) Word ignoruje flex layout — .kid-row má label v .kid-row-label
  // a vstupné polia v .kid-row-fields (inline reťazec meno + ", nar." +
  // datum + ", bytom" + adresa). Prepíšeme každý .kid-row na jediný <p>
  // s label tučným + text fieldov inline.
  clone.querySelectorAll('.kid-row').forEach(row => {
    const labelEl = row.querySelector(':scope > .kid-row-label');
    const fieldsEl = row.querySelector(':scope > .kid-row-fields');
    const labelText = labelEl ? (labelEl.textContent || '').trim() : '';
    const fieldsText = fieldsEl
      ? (fieldsEl.textContent || '').replace(/\s+/g, ' ').trim()
      : (row.textContent || '').replace(/\s+/g, ' ').trim();

    const p = document.createElement('p');
    p.style.margin = '0 0 6pt 0';
    if (labelText) {
      const b = document.createElement('strong');
      b.textContent = labelText + ' ';
      p.appendChild(b);
    }
    p.appendChild(document.createTextNode(fieldsText));
    row.replaceWith(p);
  });

  // 3) Replace <select.ed-select> with its selected option's label (plain text)
  clone.querySelectorAll('select.ed-select').forEach(sel => {
    const liveSel = findMatchingLiveElement(article, clone, sel);
    let label = '';
    if (liveSel && liveSel.options && liveSel.selectedIndex >= 0) {
      label = liveSel.options[liveSel.selectedIndex].textContent || '';
    } else {
      const first = sel.querySelector('option');
      label = first ? first.textContent : '';
    }
    const span = document.createElement('span');
    span.textContent = label;
    sel.parentNode.replaceChild(span, sel);
  });

  // 3b) Signature-row → align="right" tabuľka. MUSÍ bežať PRED step 4, ktorý unwrap-uje
  // .ed-select-print spany na text nody — inak by sme z signature-row už nevedeli prečítať
  // menoNavrhovatela (jediný element nesúci hodnotu po killovaní .no-print v step 2).
  // Word table layout: explicitné `width: 200pt` na <table> a `height: 36pt` na hornej
  // bunke — Word ignoruje `min-width` na <td>, takže bez tohto by sa bunka zmrštila na
  // šírku &nbsp; a podpisová čiara by vyzerala ako tenká pomlčka.
  clone.querySelectorAll('.signature-row').forEach(row => {
    const printSpan = row.querySelector('.ed-select-print');
    const meno = printSpan ? (printSpan.textContent || '').trim() : '';
    const wrap = document.createElement('div');
    wrap.setAttribute('align', 'right');
    wrap.style.cssText = 'margin-top:36pt;margin-bottom:18pt;';
    wrap.innerHTML =
      '<table align="right" cellpadding="0" cellspacing="0" border="0" style="border-collapse:collapse;width:200pt;">' +
        '<tr><td style="border-bottom:1px solid #000;height:36pt;line-height:36pt;padding:0;">&nbsp;</td></tr>' +
        '<tr><td style="text-align:center;padding-top:6pt;font-family:Georgia,serif;">' + meno + '</td></tr>' +
      '</table>';
    row.parentNode.replaceChild(wrap, row);
  });

  // 4) Mirror elements for selects (Ed komponent ich označuje aria-hidden="true")
  // — odstrániť úplne, lebo step 3 už nahradil <select> tým istým textom.
  // Ostatné .ed-select-print (autocomplete sud nazov, dalsie dokazy …) unwrap na text,
  // aby sa hodnota dostala do dokumentu (na obrazovke sú display:none).
  clone.querySelectorAll('.ed-select-print').forEach(el => {
    if (el.getAttribute('aria-hidden') === 'true') {
      el.remove();
      return;
    }
    const textNode = document.createTextNode(el.textContent || '');
    el.parentNode.replaceChild(textNode, el);
  });
  // Block-variant tej istej veci (adresa súdu v hlavičke) — unwrap so zachovaním
  // line-breaks (každý <div class="ed-select-print-block"> sa nahradí odsekom,
  // aby v Worde každý zostal na vlastnom riadku).
  clone.querySelectorAll('.ed-select-print-block').forEach(el => {
    const text = (el.textContent || '').trim();
    if (!text) { el.remove(); return; }
    const p = document.createElement('p');
    p.setAttribute('align', 'right');
    p.style.cssText = 'margin:0;line-height:1.5;text-align:right;';
    p.textContent = text;
    el.parentNode.replaceChild(p, el);
  });

  // 4d) Hlavička dokumentu — pravý stĺpec má byť zarovnaný vpravo a medzi
  // adresou súdu a riadkom „Bratislava, [dátum]" má byť prázdny odsek.
  const headerRight = clone.querySelector('.paper-header-right');
  if (headerRight) {
    headerRight.setAttribute('align', 'right');
    headerRight.style.textAlign = 'right';
    // Prázdny riadok pred odsekom obsahujúcim "Bratislava," (posledný <p> v stĺpci)
    const ps = headerRight.querySelectorAll(':scope > p');
    const dateP = ps[ps.length - 1];
    if (dateP) {
      dateP.setAttribute('align', 'right');
      dateP.style.textAlign = 'right';
      const spacer = document.createElement('p');
      spacer.style.cssText = 'margin:0;line-height:1.5;';
      spacer.innerHTML = '&nbsp;';
      dateP.parentNode.insertBefore(spacer, dateP);
    }
  }

  // 4c) .party-table je natívna HTML <table> v JSX (refactor z .party-grid) —
  // Word ju interpretuje korektne bez ďalšej transformácie. CSS pre .party-table
  // je v doc envelope (border-collapse, width, label width, padding). Krok 5
  // nižšie nahradí Ed contentEditable spans plain text-om v cell-och.

  // 4e) Page-break-before — pred každý element s touto triedou vlož Word-specific
  // <br> s mso-special-character, ktorý Word interpretuje ako tvrdé zalomenie strany.
  // CSS page-break-before sa v staršom HTML-Word renderingu spoľahlivo neuplatní.
  clone.querySelectorAll('.page-break-before').forEach(el => {
    const br = document.createElement('br');
    br.setAttribute('clear', 'all');
    br.style.cssText = 'mso-special-character:line-break;page-break-before:always;';
    el.parentNode.insertBefore(br, el);
    // Doplniť aj inline style, nech moderný Word/LibreOffice zachytí oba mechanizmy.
    el.style.pageBreakBefore = 'always';
  });

  // 5) Turn contentEditable .ed spans into plain text.
  // .ed-block (viacriadkový text) konvertujeme na <p>, nie na <span>,
  // aby Word korektne aplikoval text-align: justify (Word ho na inline
  // elementoch nehonoruje). white-space: pre-wrap zachová newliny.
  clone.querySelectorAll('.ed').forEach(ed => {
    const text = ed.textContent || '';
    if (ed.classList.contains('ed-block')) {
      const p = document.createElement('p');
      p.style.cssText = 'text-align:justify;white-space:pre-wrap;margin:0 0 10pt;';
      p.textContent = text;
      ed.parentNode.replaceChild(p, ed);
    } else {
      const span = document.createElement('span');
      span.textContent = text;
      ed.parentNode.replaceChild(span, ed);
    }
  });

  // 6) Remove download actions footer if it slipped in
  clone.querySelectorAll('.paper-actions').forEach(el => el.remove());

  // 6a) Convert signatures block into a 2-column TABLE — Word renders tables reliably
  //     (CSS grid & inline-block with fixed % are flaky in .doc HTML)
  const sigGrid = clone.querySelector('.signatures');
  if (sigGrid) {
    const blocks = Array.from(sigGrid.querySelectorAll(':scope > .sig-block'));
    const [left, right] = [blocks[0], blocks[1]];
    const table = document.createElement('table');
    table.setAttribute('width', '100%');
    table.setAttribute('cellpadding', '0');
    table.setAttribute('cellspacing', '0');
    table.setAttribute('border', '0');
    table.style.cssText = 'margin-top:48pt;width:100%;border-collapse:collapse;';
    const tr = document.createElement('tr');
    [left, right].forEach(b => {
      const td = document.createElement('td');
      td.setAttribute('width', '50%');
      td.style.cssText = 'width:50%;vertical-align:top;text-align:center;padding:0 12pt;';
      if (b) td.appendChild(b);
      tr.appendChild(td);
    });
    table.appendChild(tr);
    sigGrid.parentNode.replaceChild(table, sigGrid);
  }

  // 6b) Rebuild sig-block as a single table — Word respects table-cell padding
  // but applies automatic paragraph spacing to <div>s. Tables reliably stay tight.
  clone.querySelectorAll('.sig-block').forEach(block => {
    const outerCap = block.querySelector(':scope > .sig-cap');
    const persons = Array.from(block.querySelectorAll(':scope > .sig-person'));

    const tbl = document.createElement('table');
    tbl.setAttribute('width', '100%');
    tbl.setAttribute('cellpadding', '0');
    tbl.setAttribute('cellspacing', '0');
    tbl.setAttribute('border', '0');
    tbl.style.cssText = 'width:100%;border-collapse:collapse;';

    const mkRow = (html, css, innerCss) => {
      const tr = document.createElement('tr');
      const td = document.createElement('td');
      td.setAttribute('align', 'center');
      td.style.cssText = 'padding:0;text-align:center;line-height:1;' + (css || '');
      td.innerHTML =
        '<p align="center" style="margin:0;padding:0;text-align:center;' +
        'mso-margin-top-alt:0;mso-margin-bottom-alt:0;' +
        'mso-line-height-rule:exactly;line-height:115%;' + (innerCss || '') + '">' +
        html + '</p>';
      tr.appendChild(td);
      tbl.appendChild(tr);
    };

    if (outerCap) {
      mkRow(
        outerCap.textContent.trim().toUpperCase(),
        'padding:0 0 44pt;text-align:center;',
        "font-family:'IBM Plex Sans',Arial,sans-serif;font-size:9pt;letter-spacing:1.5pt;color:#555;text-align:center;"
      );
    }

    persons.forEach((person, idx) => {
      const cap  = person.querySelector('.sig-cap');
      const name = person.querySelector('.sig-name');
      if (idx > 0) {
        mkRow('&nbsp;', 'padding:28pt 0 0;', 'font-size:1pt;line-height:1pt;');
      }
      mkRow('&nbsp;', 'border-bottom:1px solid #0f1116;height:1pt;line-height:1pt;font-size:1pt;');
      mkRow(
        cap ? cap.textContent.trim().toUpperCase() : '',
        'padding-top:6pt;text-align:center;',
        "font-family:'IBM Plex Sans',Arial,sans-serif;font-size:9pt;letter-spacing:1.5pt;color:#555;text-align:center;"
      );
      mkRow(
        name ? name.textContent.trim() : '',
        'padding-top:3pt;text-align:center;',
        'font-size:10pt;font-style:italic;color:#666;text-align:center;'
      );
    });

    block.innerHTML = '';
    block.appendChild(tbl);
  });

  // 6c) Footer meta — Word doesn't flex; render as inline with dot separators
  const meta = clone.querySelector('.doc-footer-meta');
  if (meta) {
    const spans = Array.from(meta.querySelectorAll(':scope > span'));
    meta.innerHTML = spans.map(s => s.textContent.trim()).join(' &nbsp;·&nbsp; ');
  }

  // 7) Inline minimal styling — Word understands a subset of CSS
  const styles = `
    @page WordSection1 { size: A4; margin: 2cm 2cm 2.2cm 2cm; mso-footer: f1; mso-footer-margin: 1.2cm; }
    div.WordSection1 { page: WordSection1; }
    p.MsoFooter, li.MsoFooter, div.MsoFooter { margin: 0; padding: 0; mso-pagination: widow-orphan; text-align: center; font-family: "IBM Plex Mono", Consolas, monospace; font-size: 9pt; color: #888888; }
    body { font-family: "Libre Caslon Text", Georgia, serif; color: #0f1116; font-size: 12pt; line-height: 1.5; }
    .sig-block, .sig-block div, .sig-block p { mso-margin-top-alt: 0; mso-margin-bottom-alt: 0; }
    h1.doc-title { font-size: 16pt; text-align: center; letter-spacing: 2pt; margin: 0 0 6pt; text-transform: uppercase; font-weight: 700; }
    .doc-sub { text-align: center; font-family: "IBM Plex Mono", Consolas, monospace; font-size: 9pt; letter-spacing: 1.5pt; text-transform: uppercase; color: #555; margin: 0 0 18pt; }
    .doc-note { text-align: center; font-size: 9pt; color: #666; margin: 0 0 24pt; font-style: italic; }
    .article { margin: 0 0 22pt; }
    .article-head { text-align: center; margin: 22pt 0 10pt; }
    .article-num { font-family: "Libre Caslon Text", Georgia, serif; font-size: 13pt; font-weight: 700; letter-spacing: 3pt; text-transform: uppercase; }
    .article-title { display: block; font-style: italic; color: #333; font-size: 11pt; margin-top: 2pt; letter-spacing: 1pt; }
    p { margin: 0 0 10pt; text-align: justify; }
    strong { font-weight: 700; }
    em, i { font-style: italic; }
    .signatures { margin-top: 48pt; width: 100%; }
    .sig-block { display: inline-block; width: 48%; vertical-align: top; text-align: center; }
    .sig-block .sig-cap { margin: 0; padding: 0; }
    .sig-block .sig-cap + .sig-person .sig-line { margin-top: 36pt; }
    .sig-cap { font-family: "IBM Plex Sans", Arial, sans-serif; font-size: 9pt; letter-spacing: 1.5pt; text-transform: uppercase; color: #555; margin: 0; padding: 0; line-height: 1.3; }
    .sig-line { border-bottom: 1px solid #0f1116; margin: 36pt 0 4pt; height: 1pt; line-height: 1pt; font-size: 1pt; }
    .sig-name { font-size: 10pt; font-style: italic; color: #666; margin: 2pt 0 0; padding: 0; line-height: 1.3; }
    .sig-person { margin: 0; padding: 0; }
    .sig-person + .sig-person .sig-line { margin-top: 36pt; }
    .sig-person .sig-cap { margin-top: 2pt; }
    .doc-footer-meta { margin-top: 36pt; padding-top: 10pt; border-top: 1px solid #ccc; font-family: "IBM Plex Mono", Consolas, monospace; font-size: 8pt; letter-spacing: 1.5pt; text-transform: uppercase; color: #555; }
    .doc-footer-meta span { margin-right: 24pt; }
    .party-alias { font-style: italic; color: #555; margin-top: 6pt; font-size: 11pt; }
    .party-alias-term { font-style: normal; font-weight: 600; color: #0f1116; }
    .parties { margin: 18pt 0 24pt; }
    .party-line { margin: 0 0 4pt; }
    .party-table { border-collapse: collapse; width: 100%; margin: 0 0 8pt; }
    .party-table td { padding: 1pt 0; vertical-align: baseline; }
    .party-table .party-label { width: 160pt; padding-right: 12pt; }
    .paper-header { margin: 0 0 24pt; }
    .doc-date { margin-top: 24pt; }
    .proposed-verdict { margin: 24pt 0; padding: 18pt; border: 1pt solid #0f1116; background: #fafafa; }
    .verdict-heading { text-align: center; font-family: "Libre Caslon Text", Georgia, serif; font-size: 14pt; letter-spacing: 4pt; text-transform: uppercase; margin: 0 0 12pt; font-weight: 700; }
    .evidence { font-style: italic; color: #555; margin-top: 6pt; }
    .prilohy p { margin: 0 0 4pt; }
  `;

  // 8) Compose the Word HTML shell.
  // Footer cez @page mso-footer + <div mso-element:footer id="f1"> — Word renderuje
  // ako pravú pätičku na každej strane. Štýly riadi p.MsoFooter v <style> bloku
  // (center, mono 9pt, šedá). Footer div MUSÍ byť sibling .WordSection1, nie dieťa.
  // POZOR: bez `display:none` MS Word zobrazí footer DVAKRÁT — raz cez page footer
  // mechanizmus (@page mso-footer:f1 → správne, dole na strane), druhýkrát ako
  // bežný body div (chyba — inline za prílohami). `mso-element:footer` neimplikuje
  // skrytie z body. `display:none` zakáže body rendering, ale Word footer extractor
  // (OOXML metadata cez mso-element:footer) extrahuje obsah do page footer-a aj tak.
  const body = clone.outerHTML;
  const footer = `<div style='mso-element:footer' id="f1"><p class="MsoFooter">Vytvorené pomocou webovej stránky - vyzivnenadieta.sk</p></div>`;
  const html =
`<html xmlns:o="urn:schemas-microsoft-com:office:office"
       xmlns:w="urn:schemas-microsoft-com:office:word"
       xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta charset="utf-8" />
<title>Návrh na úpravu výkonu rodičovských práv a povinností k maloletému dieťaťu</title>
<!--[if gte mso 9]><xml><w:WordDocument><w:View>Print</w:View><w:Zoom>100</w:Zoom></w:WordDocument></xml><![endif]-->
<style>${styles}</style>
</head>
<body>
<div class="WordSection1">${body}</div>
${footer}
</body>
</html>`;

  // 9) Trigger download
  window.__lastDocHtml = html;
  const blob = new Blob(['﻿', html], { type: 'application/msword' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'Vzor-z-www.vyzivnenadieta.sk-navrh-na-zmenu-vo-veci-maloletych.doc';
  document.body.appendChild(a);
  if (typeof window.trackEvent === 'function') {
    window.trackEvent('download_doc', { progress: typeof window.__CURRENT_PROGRESS === 'number' ? window.__CURRENT_PROGRESS : null });
  }
  a.click();
  document.body.removeChild(a);
  setTimeout(() => URL.revokeObjectURL(url), 1000);
}

// Helper: given cloned node, find corresponding live node in source tree
// (same relative position in the DOM).
function findMatchingLiveElement(liveRoot, cloneRoot, cloneEl) {
  const path = [];
  let n = cloneEl;
  while (n && n !== cloneRoot) {
    const p = n.parentNode;
    if (!p) break;
    path.unshift(Array.prototype.indexOf.call(p.children, n));
    n = p;
  }
  let cur = liveRoot;
  for (const idx of path) {
    if (!cur || !cur.children || !cur.children[idx]) return null;
    cur = cur.children[idx];
  }
  return cur;
}

window.PaperZmena = PaperZmena;
window.__downloadAsDocZmena = downloadAsDoc;
