// pipi-landing.jsx — Landing page (browser mock) for the marketing site.
// Original Cloud design, extended with:
//   • LandingFounders section (Timur Cimerman + Juraj Zámborský polaroids)
//   • bilingual STRINGS (sk / en) threaded via a `lang` prop
//
// Designed at ~1320 px wide. landing-app.jsx scales it to the viewport.

const PIPI_STRINGS = {
  sk: {
    // UI chrome strings that used to be hardcoded in the components.
    ui_signin: 'Prihlásiť sa',
    ui_signout_full: 'Odhlásiť sa',
    ui_signout_short: 'odhlásiť',
    ui_parent: 'rodič',
    ui_menu: 'Menu',
    ui_close: 'Zavrieť',
    ui_prev: 'Predchádzajúce',
    ui_next: 'Ďalšie',
    // Newsletter band (was hardcoded SK)
    news_title: 'Občasné novinky bez spamu',
    news_body: 'Tipy pre rodičov + ohlásenia nových rozprávok. Žiadne reklamy. Odhlásiť sa dá jedným klikom.',
    news_email_ph: 'rodic@example.sk',
    news_cta: 'Prihlásiť',
    news_sending: 'Posielam…',
    news_ok: '✓ Ďakujeme, prihlásili sme ťa.',
    news_invalid: 'Zadaj platný email.',
    news_neterr: 'Sieť zlyhala.',
    nav: [
      { label: 'Príbehy',         href: '#stories'  },
      { label: 'Ako to funguje',  href: '#how'      },
      { label: 'Cenník',          href: '/cennik.html' },
      { label: 'Pre rodičov',     href: '#trust'    },
      { label: 'O nás',           href: '#founders' },
    ],
    nav_cta: 'Chcem ako prvý',
    nav_demo: 'Demo ↗',
    hero_kicker: 'tichý štart · slovensky · v1.0',
    hero_title_1: 'Rozprávky,',
    hero_title_2: 'kde rozhoduje',
    hero_title_3: 'tvoje dieťa.',
    hero_body: 'Pipi rozpráva príbeh a v dôležitých chvíľach sa pýta dieťaťa, čo má hrdina urobiť ďalej. Odpoveď môže povedať nahlas, alebo ťuknúť na obrazovku.',
    hero_cta_primary: 'Chcem byť na waitliste',
    hero_cta_secondary: 'Vypočuť ukážku 0:38',
    hero_subnote: 'Tichý štart · len pre prvých rodičov · bez reklám · nič nesledujeme',
    hero_tap: 'ťuk!',
    how_title: 'Ako to funguje',
    how_sub: 'Tri kroky. Žiadne inštrukcie pre dieťa.',
    how_1_t: 'Pipi začne príbeh',
    how_1_d: 'Slovenský hlas rozpráva. Žiadne titulky, len ucho a fantázia.',
    how_2_t: 'Príde otázka',
    how_2_d: '„Čo má hrdina urobiť?“ Dieťa povie odpoveď alebo ťukne.',
    how_3_t: 'Príbeh sa zmení',
    how_3_d: 'Každá voľba otvorí inú cestu. Žiadne dva príbehy nie sú rovnaké.',
    how_bubble_1: 'Bola raz jedna',
    how_bubble_2: 'malá víla…',
    how_voice: '„Otvor dvere!“',
    how_branch_left:      'les',
    how_branch_left_alt:  'alebo lúka',
    how_branch_mid:       'cirkus',
    how_branch_mid_alt:   'alebo trh',
    how_branch_right:     'more',
    how_branch_right_alt: 'alebo rieka',
    stories_title: 'Polica s príbehmi',
    stories_sub: 'Pribúdajú každý týždeň. Ten istý príbeh znie zakaždým inak — podľa toho, čo dieťa vyberie.',
    stories_count: '32 príbehov · 14 hodín · pripravené pred spustením',
    trust_title_1: 'Pre rodičov: pokoj.',
    trust_title_2: 'Pre deti: dobrodružstvo.',
    trust_body: 'Bez reklám. Bez nákupov v aplikácii. Žiadne videá, ktoré bojujú o pozornosť — len hlas a fantázia. Nastavenia chráni PIN rodiča.',
    trust_tags: ['žiadne reklamy', 'nič nesledujeme', 'časový limit', 'tichý režim 19:30', 'PIN rodiča'],
    quotes: [
      { name: 'Eva, mama Mii (5)', text: 'Mia si pýta ešte jeden príbeh — a pri ňom sa pýta: „A čo keď bude víla zlá?“ Naše najdlhšie večerné rozhovory.' },
      { name: 'Tomáš, ocko Adama (7)', text: 'Slovenský hlas. Bez reklám. Bez TikTokov. Plus má to debug režim, čo som ako vývojár ocenil viac, než som čakal.' },
      { name: 'Andrea, učiteľka MŠ', text: 'Používame v škôlke pri obednom kľude. Deti reagujú, hlasujú, smejú sa. Žiadny obrazovkový tranz.' },
      { name: 'Peter, ocko Líly (4)', text: 'Vyzerá to ako keď nakreslila Líla. To je presne dôvod, prečo sa s tým hrá tak rada.' },
    ],
    founders_eyebrow: 'kto za tým stojí',
    founders_title: 'Dvaja oteckovia, jedna myš.',
    founders_body: 'Ippy sme začali kresliť večer, keď deti zaspali. Ráno sme si všimli, že nás to baví viac než deti. Robíme produkt, ktorý by sme sami pustili svojim deťom: krátky, slovenský, bez agresívnych háčikov na pozornosť.',
    founders: [
      {
        img: '/founders/timur.png', name: 'Timur Cimerman',
        role: 'product · hlas · zvuk',
        note: '„Detský hlas je najťažší klient. Buď ho zaujme prvá veta, alebo si pýta tablet.“',
        link_label: 'timur@heyippy.com',
      },
      {
        img: '/founders/juraj.png', name: 'Juraj Zámborský',
        role: 'engineering · model · backend',
        note: '„Postavili sme to tak, aby AI bola lacná, predvídateľná a aby rodič vždy videl, čo dieťa povedalo.“',
        link_label: 'juraj@heyippy.com',
      },
    ],
    cta_title_1: 'Ippy otvárame',
    cta_title_2: 'čoskoro. Buď prvý.',
    cta_primary: 'Pridať ma na zoznam',
    cta_secondary: 'Vypočuť ukážku 0:38',
    cta_email_label: 'Email rodiča',
    cta_email_ph: 'rodic@example.sk',
    cta_subnote: 'Jeden email, jeden odkaz, žiadny newsletter. GDPR: ukladáme len email.',
    cta_sending: 'Posielam…',
    cta_invalid: 'Zadaj platný email, prosím.',
    cta_ok_title: 'Si na zozname.',
    cta_ok_body: 'Pošleme ti odkaz, hneď ako bude Ippy chodiť bez padania.',
    cta_listen_url: '/demo/audio/showcase/intro.mp3',
    cta_listening: 'Prehrávam…',
    footer_made_in: 'Bratislava · kreslené ručne, písané s diakritikou.',
    footer_col_1_t: 'Produkt',
    footer_col_1: [
      { label: 'Príbehy',        href: '#stories' },
      { label: 'Ako to funguje', href: '#how' },
      { label: 'Cenník',         href: '/cennik.html' },
      { label: 'Demo',           href: (window.IPPY_LINKS.app || '') + '/demo' },
    ],
    footer_col_2_t: 'Pre rodičov',
    footer_col_2: [
      { label: 'Pre rodičov',  href: '#trust' },
      { label: 'Bezpečnosť',   href: '/privacy.html' },
      { label: 'GDPR',         href: '/gdpr.html' },
      { label: 'Kontakt',      href: 'mailto:info@heyippy.com' },
    ],
    footer_col_3_t: 'Spoločnosť',
    footer_col_3: [
      { label: 'O nás',           href: '#founders' },
      { label: 'Podmienky',       href: '/terms.html' },
      { label: 'Ochrana údajov',  href: '/privacy.html' },
      { label: 'Tlačová správa',  href: 'mailto:info@heyippy.com?subject=Press' },
    ],
    footer_copy: '© Ippy · 2026 · Bratislava. Všetky práva vyhradené.',
    // Co-creation pillar — parent + child making the story together,
    // creativity, lessons. Sits between Stories and Trust on the
    // landing page.
    cocreate_eyebrow: 'spolu, nie spred obrazovky',
    cocreate_title_1: 'Tvoríte príbeh',
    cocreate_title_2: 'spoločne.',
    cocreate_body: 'Ippy nie je len pre dieťa. Ak chceš, sadni si k nemu. Otázky príbehu otvárajú rozhovor: prečo by mal hrdina otvoriť dvere? Čo by si urobil ty? Z 10-minútovej rozprávky vyrastie hodina, na ktorú si dieťa spomenie.',
    cocreate_pillars: [
      { t: 'Kreativita',    d: 'Dieťa si vymýšľa, vetví, mení smer. Ippy to bez moralizovania zaznamenáva.' },
      { t: 'Spoločný čas',  d: 'Rodič môže byť pri tom. Žiadne tablety pre osamelé dieťa, ale zdieľaný moment.' },
      { t: 'Ponaučenie',    d: 'Každá kapitola má malú lekciu vetkú dnu — bez prednášok.' },
    ],
    // Side-by-side comparison: Pipi vs. ordinary book vs. tablet game
    compare_title: 'Klasická kniha vs. tablet vs. Ippy',
    compare_sub: 'Krátke a férové.',
    compare_cols: [
      {
        t: 'Klasická kniha',
        rows: ['Rodič musí čítať', 'Cesta je vždy rovnaká', 'Žiadne preludy s technikou', 'Skvelá, ale večerná'],
        tone: 'paper',
      },
      {
        t: 'Tablet hra',
        rows: ['Bez rodiča', 'Vizuálny chaos', 'Reklamy, in-app', 'Závislosť na obrazovke'],
        tone: 'pink',
      },
      {
        t: 'Ippy',
        rows: ['Žiadny obrazovkový tranz', 'Cesta sa mení podľa dieťaťa', 'Bez reklám a bez in-app nákupov', 'Hlas, fantázia, voľba dieťaťa'],
        tone: 'yellow',
      },
    ],
  },
  en: {
    ui_signin: 'Sign in',
    ui_signout_full: 'Sign out',
    ui_signout_short: 'sign out',
    ui_parent: 'parent',
    ui_menu: 'Menu',
    ui_close: 'Close',
    ui_prev: 'Previous',
    ui_next: 'Next',
    news_title: 'Occasional updates, no spam',
    news_body: 'Tips for parents + new-story announcements. No ads. One click to unsubscribe.',
    news_email_ph: 'parent@example.com',
    news_cta: 'Subscribe',
    news_sending: 'Sending…',
    news_ok: '✓ Thanks, you’re subscribed.',
    news_invalid: 'Enter a valid email.',
    news_neterr: 'Network failed.',
    nav: [
      { label: 'Stories',       href: '#stories'  },
      { label: 'How it works',  href: '#how'      },
      { label: 'Pricing',       href: '/cennik.html' },
      { label: 'For parents',   href: '#trust'    },
      { label: 'About',         href: '#founders' },
    ],
    nav_cta: 'Join the waitlist',
    nav_demo: 'Demo ↗',
    hero_kicker: 'quiet launch · v1.0',
    hero_title_1: 'Stories,',
    hero_title_2: 'where',
    hero_title_3: 'your kid decides.',
    hero_body: 'Pipi tells the story, and at the important moments asks your child what the hero should do next. Your child can say the answer out loud, or tap the screen.',
    hero_cta_primary: 'Join the waitlist',
    hero_cta_secondary: 'Hear a 38-second sample',
    hero_subnote: 'First parents only · no ads · nothing tracked',
    hero_tap: 'tap!',
    how_title: 'How it works',
    how_sub: 'Three steps. No instructions for the child.',
    how_1_t: 'Pipi starts the story',
    how_1_d: 'A warm voice tells it. No captions, just ears and imagination.',
    how_2_t: 'A question comes',
    how_2_d: '"What should the hero do?" The kid answers, or taps.',
    how_3_t: 'The story changes',
    how_3_d: 'Every choice opens a different path. No two stories are the same.',
    how_bubble_1: 'Once upon a',
    how_bubble_2: 'tiny fairy…',
    how_voice: '"Open the door!"',
    how_branch_left:      'forest',
    how_branch_left_alt:  'or meadow',
    how_branch_mid:       'circus',
    how_branch_mid_alt:   'or market',
    how_branch_right:     'sea',
    how_branch_right_alt: 'or river',
    stories_title: 'Story shelf',
    stories_sub: 'The same story sounds different each time. It follows what your child picks.',
    stories_count: 'New stories added every week',
    trust_title_1: 'For parents: peace.',
    trust_title_2: 'For kids: adventure.',
    trust_body: 'No ads. No in-app purchases. No videos fighting for attention, just a voice and imagination. A parent PIN guards the settings.',
    trust_tags: ['no ads', 'nothing tracked', 'time limit', 'quiet mode 7:30 pm', 'parent PIN'],
    quotes: [
      { name: 'Eva, mom of Mia (5)', text: 'Mia asks for one more story, and in the middle of it: “What if the fairy is mean?” Our longest bedtime talks yet.' },
      { name: 'Tomáš, dad of Adam (7)', text: 'The voice. No ads. No TikToks.' },
      { name: 'Andrea, kindergarten teacher', text: 'We use it at nap time. Kids react, vote, laugh. No screen-trance mode.' },
      { name: 'Peter, dad of Lily (4)', text: 'It looks like Lily drew it. That’s exactly why she loves playing with it.' },
    ],
    founders_eyebrow: 'who is behind this',
    founders_title: 'Two dads, one chick, zero sleep.',
    founders_body: 'We started drawing Ippy in the evenings after the kids fell asleep. Then we noticed we were having more fun than the kids. We’re building the product we’d actually play to our own children: short, gentle, no aggressive attention hooks.',
    founders: [
      {
        img: '/founders/timur.png', name: 'Timur Cimerman',
        role: 'product · voice · sound',
        note: '"A child is the toughest critic. Either the first sentence catches them, or they ask for the tablet."',
        link_label: 'timur@heyippy.com',
      },
      {
        img: '/founders/juraj.png', name: 'Juraj Zámborský',
        role: 'engineering · model · backend',
        note: '"We built it so the AI is cheap, predictable, and the parent can always see what the child said."',
        link_label: 'juraj@heyippy.com',
      },
    ],
    cta_title_1: 'Ippy opens',
    cta_title_2: 'soon. Be first in.',
    cta_primary: 'Add me to the list',
    cta_secondary: 'Hear a 38-second sample',
    cta_email_label: 'Parent email',
    cta_email_ph: 'parent@example.com',
    cta_subnote: 'One email, one link. No newsletter. We only ever store your email.',
    cta_sending: 'Sending…',
    cta_invalid: 'Enter a valid email, please.',
    cta_ok_title: 'You’re on the list.',
    cta_ok_body: 'We’ll send you a link the moment Ippy can walk without wobbling.',
    cta_listen_url: '/demo/audio/showcase/intro.mp3',
    cta_listening: 'Playing…',
    footer_made_in: 'Bratislava · drawn by hand, wobbles included.',
    footer_col_1_t: 'Product',
    footer_col_1: [
      { label: 'Stories',       href: '#stories' },
      { label: 'How it works',  href: '#how' },
      { label: 'Pricing',       href: '/cennik.html' },
      { label: 'Demo',          href: (window.IPPY_LINKS.app || '') + '/demo' },
    ],
    footer_col_2_t: 'For parents',
    footer_col_2: [
      { label: 'For parents',  href: '#trust' },
      { label: 'Safety',       href: '/privacy.html' },
      { label: 'GDPR',         href: '/gdpr.html' },
      { label: 'Contact',      href: 'mailto:info@heyippy.com' },
    ],
    footer_col_3_t: 'Company',
    footer_col_3: [
      { label: 'About',        href: '#founders' },
      { label: 'Terms',        href: '/terms.html' },
      { label: 'Privacy',      href: '/privacy.html' },
      { label: 'Press',        href: 'mailto:info@heyippy.com?subject=Press' },
    ],
    footer_copy: '© Ippy · 2026 · Made in Bratislava, drawn by hand.',
    // Co-creation pillar (parity with SK)
    cocreate_eyebrow: 'together, not in front of a screen',
    cocreate_title_1: 'You build the story',
    cocreate_title_2: 'together.',
    cocreate_body: 'Ippy is not only for the child. If you want, sit down with them. The story’s questions open a conversation: why should the hero open the door? What would you do? A 10-minute tale grows into an hour your child will remember.',
    cocreate_pillars: [
      { t: 'Creativity',    d: 'The child invents, branches, changes direction. Ippy records it without moralizing.' },
      { t: 'Shared time',   d: 'A parent can be right there. Not a tablet for a lonely child, but a shared moment.' },
      { t: 'A little lesson', d: 'Every chapter has a small lesson woven in, no lectures.' },
    ],
    // Comparison table (parity with SK)
    compare_title: 'Classic book vs. tablet vs. Ippy',
    compare_sub: 'Short and fair.',
    compare_cols: [
      {
        t: 'Classic book',
        rows: ['A parent has to read', 'The path is always the same', 'No screen at all', 'Great, but a bedtime-only thing'],
        tone: 'paper',
      },
      {
        t: 'Tablet game',
        rows: ['No parent needed', 'Visual chaos', 'Ads, in-app purchases', 'Screen addiction'],
        tone: 'pink',
      },
      {
        t: 'Ippy',
        rows: ['No screen trance', 'The path changes with the child', 'No ads, no in-app purchases', 'Voice, imagination, the child’s choice'],
        tone: 'yellow',
      },
    ],
  },
  cz: {
    ui_signin: 'Přihlásit se',
    ui_signout_full: 'Odhlásit se',
    ui_signout_short: 'odhlásit',
    ui_parent: 'rodič',
    ui_menu: 'Menu',
    ui_close: 'Zavřít',
    ui_prev: 'Předchozí',
    ui_next: 'Další',
    news_title: 'Občasné novinky bez spamu',
    news_body: 'Tipy pro rodiče + oznámení nových pohádek. Žádné reklamy. Odhlásit se dá jedním kliknutím.',
    news_email_ph: 'rodic@example.cz',
    news_cta: 'Přihlásit',
    news_sending: 'Posílám…',
    news_ok: '✓ Děkujeme, přihlásili jsme tě.',
    news_invalid: 'Zadej platný e-mail.',
    news_neterr: 'Síť selhala.',
    nav: [
      { label: 'Pohádky',         href: '#stories'  },
      { label: 'Jak to funguje',  href: '#how'      },
      { label: 'Ceník',           href: '/cennik.html' },
      { label: 'Pro rodiče',      href: '#trust'    },
      { label: 'O nás',           href: '#founders' },
    ],
    nav_cta: 'Chci být první',
    nav_demo: 'Demo ↗',
    hero_kicker: 'tichý start · slovensky · v1.0', /* CZ: native check */
    hero_title_1: 'Pohádky,',
    hero_title_2: 'kde rozhoduje',
    hero_title_3: 'tvoje dítě.',
    hero_body: 'Pipi vypráví příběh a v důležitých chvílích se ptá dítěte, co má hrdina udělat dál. Odpověď může říct nahlas, nebo ťuknout na obrazovku.',
    hero_cta_primary: 'Chci být na waitlistu',
    hero_cta_secondary: 'Poslechnout ukázku 0:38',
    hero_subnote: 'Tichý start · jen pro první rodiče · bez reklam · nic nesledujeme',
    hero_tap: 'ťuk!',
    how_title: 'Jak to funguje',
    how_sub: 'Tři kroky. Žádné instrukce pro dítě.',
    how_1_t: 'Pipi začne příběh',
    how_1_d: 'Slovenský hlas vypráví. Žádné titulky, jen ucho a fantazie.', /* CZ: native check */
    how_2_t: 'Přijde otázka',
    how_2_d: '„Co má hrdina udělat?“ Dítě řekne odpověď nebo ťukne.',
    how_3_t: 'Příběh se změní',
    how_3_d: 'Každá volba otevře jinou cestu. Žádné dva příběhy nejsou stejné.',
    how_bubble_1: 'Byla jednou jedna',
    how_bubble_2: 'malá víla…',
    how_voice: '„Otevři dveře!“',
    how_branch_left:      'les',
    how_branch_left_alt:  'nebo louka',
    how_branch_mid:       'cirkus',
    how_branch_mid_alt:   'nebo trh',
    how_branch_right:     'moře',
    how_branch_right_alt: 'nebo řeka',
    stories_title: 'Police s pohádkami',
    stories_sub: 'Přibývají každý týden. Stejný příběh zní pokaždé jinak — podle toho, co si dítě vybere.',
    stories_count: '32 příběhů · 14 hodin · připraveno před spuštěním',
    trust_title_1: 'Pro rodiče: klid.',
    trust_title_2: 'Pro děti: dobrodružství.',
    trust_body: 'Bez reklam. Bez nákupů v aplikaci. Žádná videa, která bojují o pozornost — jen hlas a fantazie. Nastavení chrání rodičovský PIN.',
    trust_tags: ['žádné reklamy', 'nic nesledujeme', 'časový limit', 'tichý režim 19:30', 'rodičovský PIN'],
    quotes: [
      { name: 'Eva, máma Mii (5)', text: 'Mia si říká o ještě jeden příběh — a u něj se ptá: „A co když bude víla zlá?“ Naše nejdelší večerní povídání.' }, /* CZ: native check */
      { name: 'Tomáš, táta Adama (7)', text: 'Slovenský hlas. Bez reklam. Bez TikToků. Navíc to má debug režim, což jsem jako vývojář ocenil víc, než jsem čekal.' },
      { name: 'Andrea, učitelka v MŠ', text: 'Používáme ve školce při polední pauze. Děti reagují, hlasují, smějí se. Žádný obrazovkový trans.' }, /* CZ: native check */
      { name: 'Petr, táta Lily (4)', text: 'Vypadá to, jako by to nakreslila Lily. Přesně proto si s tím tak ráda hraje.' },
    ],
    founders_eyebrow: 'kdo za tím stojí',
    founders_title: 'Dva tátové, jedna myš.',
    founders_body: 'Ippy jsme začali kreslit večer, když děti usnuly. Ráno jsme zjistili, že nás to baví víc než děti. Děláme produkt, který bychom sami pustili svým dětem: krátký, slovenský, bez agresivních háčků na pozornost.',
    founders: [
      {
        img: '/founders/timur.png', name: 'Timur Cimerman',
        role: 'produkt · hlas · zvuk',
        note: '„Dětský hlas je nejtěžší klient. Buď ho zaujme první věta, nebo si říká o tablet.“',
        link_label: 'timur@heyippy.com',
      },
      {
        img: '/founders/juraj.png', name: 'Juraj Zámborský',
        role: 'engineering · model · backend',
        note: '„Postavili jsme to tak, aby AI byla levná, předvídatelná a aby rodič vždy viděl, co dítě řeklo.“',
        link_label: 'juraj@heyippy.com',
      },
    ],
    cta_title_1: 'Ippy otevíráme',
    cta_title_2: 'brzy. Buď první.',
    cta_primary: 'Přidej mě na seznam',
    cta_secondary: 'Poslechnout ukázku 0:38',
    cta_email_label: 'E-mail rodiče',
    cta_email_ph: 'rodic@example.cz',
    cta_subnote: 'Jeden e-mail, jeden odkaz, žádný newsletter. GDPR: ukládáme jen e-mail.',
    cta_sending: 'Posílám…',
    cta_invalid: 'Zadej platný e-mail, prosím.',
    cta_ok_title: 'Jsi na seznamu.',
    cta_ok_body: 'Pošleme ti odkaz, jakmile bude Ippy chodit bez padání.', /* CZ: native check */
    cta_listen_url: '/demo/audio/showcase/intro.mp3',
    cta_listening: 'Přehrávám…',
    footer_made_in: 'Bratislava · kresleno ručně, psáno s diakritikou.',
    footer_col_1_t: 'Produkt',
    footer_col_1: [
      { label: 'Pohádky',        href: '#stories' },
      { label: 'Jak to funguje', href: '#how' },
      { label: 'Ceník',          href: '/cennik.html' },
      { label: 'Demo',           href: (window.IPPY_LINKS.app || '') + '/demo' },
    ],
    footer_col_2_t: 'Pro rodiče',
    footer_col_2: [
      { label: 'Pro rodiče',   href: '#trust' },
      { label: 'Bezpečnost',   href: '/privacy.html' },
      { label: 'GDPR',         href: '/gdpr.html' },
      { label: 'Kontakt',      href: 'mailto:info@heyippy.com' },
    ],
    footer_col_3_t: 'Společnost',
    footer_col_3: [
      { label: 'O nás',           href: '#founders' },
      { label: 'Podmínky',        href: '/terms.html' },
      { label: 'Ochrana údajů',   href: '/privacy.html' },
      { label: 'Tisková zpráva',  href: 'mailto:info@heyippy.com?subject=Press' },
    ],
    footer_copy: '© Ippy · 2026 · Bratislava. Všechna práva vyhrazena.',
    cocreate_eyebrow: 'společně, ne před obrazovkou',
    cocreate_title_1: 'Tvoříte příběh',
    cocreate_title_2: 'společně.',
    cocreate_body: 'Ippy není jen pro dítě. Když chceš, sedni si k němu. Otázky příběhu otevírají rozhovor: proč by měl hrdina otevřít dveře? Co bys udělal ty? Z desetiminutové pohádky vyroste hodina, na kterou si dítě vzpomene.',
    cocreate_pillars: [
      { t: 'Kreativita',     d: 'Dítě si vymýšlí, větví, mění směr. Ippy to bez moralizování zaznamenává.' },
      { t: 'Společný čas',   d: 'Rodič může být u toho. Žádný tablet pro osamělé dítě, ale sdílený okamžik.' },
      { t: 'Ponaučení',      d: 'Každá kapitola má malou lekci vetkanou dovnitř — bez kázání.' }, /* CZ: native check */
    ],
    compare_title: 'Klasická kniha vs. tablet vs. Ippy',
    compare_sub: 'Krátké a férové.',
    compare_cols: [
      {
        t: 'Klasická kniha',
        rows: ['Rodič musí číst', 'Cesta je vždy stejná', 'Žádné hraní s technikou', 'Skvělá, ale jen večerní'], /* CZ: native check */
        tone: 'paper',
      },
      {
        t: 'Tabletová hra',
        rows: ['Bez rodiče', 'Vizuální chaos', 'Reklamy, in-app nákupy', 'Závislost na obrazovce'],
        tone: 'pink',
      },
      {
        t: 'Ippy',
        rows: ['Žádný obrazovkový trans', 'Cesta se mění podle dítěte', 'Bez reklam a bez in-app nákupů', 'Hlas, fantazie, volba dítěte'],
        tone: 'yellow',
      },
    ],
  },
};

// Supported UI languages, in switcher order.
const PIPI_LANGS = ['sk', 'cz', 'en'];

function pipiT(lang) {
  return PIPI_STRINGS[lang] || PIPI_STRINGS.sk;
}

// Responsive breakpoint hook. The landing now has two layouts:
// desktop (≥ 820 px) — the original 2-column / 3-column grids, and
// mobile (< 820 px) — single-column stacks, smaller fonts, hamburger
// menu in the header. No more transform-scale of the whole canvas.
function useIsMobile(breakpoint = 820) {
  const [isMobile, setIsMobile] = React.useState(() =>
    typeof window !== 'undefined' && window.matchMedia
      ? window.matchMedia(`(max-width: ${breakpoint}px)`).matches
      : false);
  React.useEffect(() => {
    if (typeof window === 'undefined' || !window.matchMedia) return;
    const mq = window.matchMedia(`(max-width: ${breakpoint}px)`);
    const handler = (e) => setIsMobile(e.matches);
    if (mq.addEventListener) mq.addEventListener('change', handler);
    else mq.addListener(handler);
    return () => {
      if (mq.removeEventListener) mq.removeEventListener('change', handler);
      else mq.removeListener(handler);
    };
  }, [breakpoint]);
  return isMobile;
}

// Paints a section's background and top/bottom dividers full-bleed to the
// viewport edges while the section's own content keeps the 1320 px design
// width. Use as the first child of a `position: relative; zIndex: 0`
// section so the band lands at z=-1 (behind content) without escaping the
// section's stacking context.
//
// `top`/`bottom` are pulled by the border width so the band's borders
// align EXACTLY with the section's own borderTop/borderBottom (which are
// kept so the line is also visible on mobile, where the band may not
// reach the viewport edges due to the parent transform). Without this
// offset the band's borders would paint 3 px inside the section's own
// borders and we'd see two parallel divider lines.
function FullBleedBg({ color, borderTop = null, borderBottom = null, borderWidth = 3 }) {
  return (
    <div aria-hidden="true" style={{
      position: 'absolute',
      top: borderTop ? -borderWidth : 0,
      bottom: borderBottom ? -borderWidth : 0,
      left: 'calc(50% - 50vw)', right: 'calc(50% - 50vw)',
      background: color,
      borderTop: borderTop || undefined,
      borderBottom: borderBottom || undefined,
      pointerEvents: 'none',
      zIndex: -1,
    }}/>
  );
}

function PipiLanding({ lang = 'sk', onLangChange = null, currentUser = null }) {
  const t = pipiT(lang);
  const m = useIsMobile();
  // Outer: full viewport width, paints the page background, clips any
  // horizontal overflow from rotated/scaled children.
  // Inner: capped at 1320 px and horizontally centered. This is what
  // got LOST when sections went "full-bleed" — the foreground content
  // was using 100% of the viewport, so on a 1920 px screen the cards
  // were stretching out way past the design's intended width. The
  // FullBleedBg bands inside each section still escape this constraint
  // via `left: calc(50% - 50vw)`, so the colored stripes still touch
  // the viewport edges — only the foreground content stays centered.
  return (
    <div style={{
      width: '100%', background: PIPI.paper,
      overflowX: 'hidden',
    }}>
      <div style={{
        maxWidth: 1320, margin: '0 auto', position: 'relative',
        fontFamily: '"Patrick Hand", cursive', color: PIPI.ink,
      }}>
        <LandingHeader t={t} lang={lang} onLangChange={onLangChange} m={m} currentUser={currentUser}/>
        <LandingHero t={t} m={m}/>
        <LandingHow t={t} m={m}/>
        <LandingCoCreate t={t} m={m}/>
        <LandingStories t={t} m={m}/>
        <LandingCompare t={t} m={m}/>
        <LandingTrust t={t} m={m}/>
        <LandingFounders t={t} m={m}/>
        <LandingCTA t={t} m={m}/>
        <LandingNewsletter t={t} m={m}/>
        <LandingFooter t={t} m={m}/>
      </div>
    </div>
  );
}

function LandingHeader({ t, lang, onLangChange, m, currentUser = null }) {
  const [menuOpen, setMenuOpen] = React.useState(false);
  const linkStyle = {
    color: PIPI.ink, textDecoration: 'none', fontFamily: '"Patrick Hand", cursive',
    fontSize: 20, padding: '6px 4px', borderBottom: '2px solid transparent',
    transition: 'border-color .15s',
  };

  if (m) {
    // Mobile header: wordmark + hamburger. Tapping hamburger opens a
    // full-width drop-down with the nav links + the two CTAs stacked.
    return (
      <div id="top" style={{
        position: 'relative', zIndex: 5, background: PIPI.paperLt,
        borderBottom: `3px solid ${PIPI.ink}`,
      }}>
        <FullBleedBg color={PIPI.paperLt} borderBottom={`3px solid ${PIPI.ink}`}/>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          padding: '14px 18px', position: 'relative', zIndex: 1 }}>
          <a href="#top" onClick={() => setMenuOpen(false)} style={{ display: 'flex', alignItems: 'center', gap: 6, textDecoration: 'none' }}>
            <PipiMini size={44}/>
            <PipiWordmark height={42}/>
          </a>
          <button onClick={() => setMenuOpen((v) => !v)} aria-label={t.ui_menu} style={{
            background: PIPI.yellow, border: `3px solid ${PIPI.ink}`, borderRadius: 12,
            width: 48, height: 48, cursor: 'pointer', padding: 0,
            display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 4,
            boxShadow: '3px 3px 0 rgba(0,0,0,0.16)',
          }}>
            {menuOpen ? (
              <svg width="22" height="22" viewBox="0 0 22 22">
                <path d="M4 4 L18 18 M18 4 L4 18" stroke={PIPI.ink} strokeWidth={3} strokeLinecap="round"/>
              </svg>
            ) : (
              <>
                <span style={{ width: 22, height: 3, background: PIPI.ink, borderRadius: 2 }}/>
                <span style={{ width: 22, height: 3, background: PIPI.ink, borderRadius: 2 }}/>
                <span style={{ width: 22, height: 3, background: PIPI.ink, borderRadius: 2 }}/>
              </>
            )}
          </button>
        </div>
        {menuOpen && (
          <div style={{
            position: 'relative', zIndex: 1, padding: '8px 18px 18px',
            display: 'flex', flexDirection: 'column', gap: 4,
          }}>
            {t.nav.map((n) => (
              <a key={n.href} href={n.href} onClick={() => setMenuOpen(false)}
                style={{
                  color: PIPI.ink, textDecoration: 'none',
                  fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: 26,
                  padding: '10px 4px', borderBottom: `2px dashed ${PIPI.inkSoft}`,
                }}>{n.label}</a>
            ))}
            <div style={{ display: 'flex', gap: 10, marginTop: 12, flexWrap: 'wrap' }}>
              <div data-action="open-demo" style={{ flex: '1 1 140px' }}>
                <ScribbleButton color={PIPI.paperLt} size="md" seed={511} fullWidth>{t.nav_demo}</ScribbleButton>
              </div>
              <div data-action="goto-signup" style={{ flex: '1 1 140px' }}>
                <ScribbleButton color={PIPI.yellow} size="md" seed={510} fullWidth>{t.nav_cta}</ScribbleButton>
              </div>
              {currentUser ? (
                <>
                  <a href={(window.IPPY_LINKS.app || "") + "/demo"} style={{ flex: '1 1 140px', textDecoration: 'none' }}>
                    <ScribbleButton color={PIPI.paperLt} size="md" seed={508} fullWidth>
                      {currentUser.email ? currentUser.email.split('@')[0] : t.ui_parent} ↗
                    </ScribbleButton>
                  </a>
                  <div data-action="sign-out" style={{ flex: '1 1 140px' }}>
                    <ScribbleButton color={PIPI.paperLt} size="md" seed={507} fullWidth>{t.ui_signout_full}</ScribbleButton>
                  </div>
                </>
              ) : (
                <div data-action="sign-in" style={{ flex: '1 1 140px' }}>
                  <ScribbleButton color={PIPI.paperLt} size="md" seed={509} fullWidth>{t.ui_signin}</ScribbleButton>
                </div>
              )}
            </div>
            {onLangChange && (
              <div style={{ marginTop: 14, display: 'flex', justifyContent: 'center' }}>
                <LangToggle lang={lang} onChange={onLangChange}/>
              </div>
            )}
          </div>
        )}
      </div>
    );
  }

  return (
    <div id="top" style={{
      display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      padding: '22px 56px', borderBottom: `3px solid ${PIPI.ink}`,
      background: PIPI.paperLt, position: 'relative', zIndex: 0,
    }}>
      <FullBleedBg color={PIPI.paperLt} borderBottom={`3px solid ${PIPI.ink}`}/>
      <a href="#top" style={{ display: 'flex', alignItems: 'center', gap: 8, textDecoration: 'none' }}>
        <PipiMini size={56}/>
        <PipiWordmark height={56}/>
      </a>
      <div style={{ display: 'flex', gap: 26 }}>
        {t.nav.map((n) => (
          <a key={n.href} href={n.href} style={linkStyle}
             onMouseEnter={(e) => e.currentTarget.style.borderBottomColor = PIPI.red}
             onMouseLeave={(e) => e.currentTarget.style.borderBottomColor = 'transparent'}>
            {n.label}
          </a>
        ))}
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <LangToggle lang={lang} onChange={onLangChange}/>
        <div style={{ display: 'inline-block', transform: 'translateY(2px)' }} data-action="open-demo">
          <ScribbleButton color={PIPI.paperLt} size="sm" seed={511}>
            {t.nav_demo}
          </ScribbleButton>
        </div>
        {/* Sign-in / user chip. When logged-in we show the email's
           first segment as a chip with a quick "Odhlásiť sa". When
           logged-out we show the "Prihlásiť sa" pill. */}
        {currentUser ? (
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <a href={(window.IPPY_LINKS.app || "") + "/demo"} style={{
              padding: '6px 14px', borderRadius: 999, background: PIPI.paperLt,
              border: `2.5px solid ${PIPI.ink}`, color: PIPI.ink, textDecoration: 'none',
              fontFamily: '"Patrick Hand", cursive', fontSize: 16,
            }}>
              {currentUser.email ? currentUser.email.split('@')[0] : t.ui_parent} ↗
            </a>
            <a href="#" data-action="sign-out" style={{
              fontFamily: '"Patrick Hand", cursive', fontSize: 14, color: PIPI.ink,
              opacity: 0.7, textDecoration: 'underline',
            }}>{t.ui_signout_short}</a>
          </div>
        ) : (
          <div style={{ display: 'inline-block', transform: 'translateY(2px)' }} data-action="sign-in">
            <ScribbleButton color={PIPI.paperLt} size="sm" seed={509}>
              {t.ui_signin}
            </ScribbleButton>
          </div>
        )}
        <div style={{ display: 'inline-block', transform: 'translateY(2px)' }} data-action="goto-signup">
          <ScribbleButton color={PIPI.yellow} size="sm" seed={510}>
            {t.nav_cta}
          </ScribbleButton>
        </div>
      </div>
    </div>
  );
}

function LangToggle({ lang, onChange }) {
  // Three-way SK · CZ · EN switcher. When no change handler is provided
  // we render nothing (e.g. embedded contexts that don't manage lang).
  if (!onChange) return null;
  const labels = { sk: 'SK', cz: 'CZ', en: 'EN' };
  const fullLabels = { sk: 'Slovenčina', cz: 'Čeština', en: 'English' };
  const btn = (code) => (
    <button key={code} onClick={() => onChange(code)}
      aria-pressed={lang === code} aria-label={fullLabels[code]}
      style={{
        background: lang === code ? PIPI.yellow : 'transparent',
        border: `2px solid ${PIPI.ink}`, padding: '2px 10px', borderRadius: 999,
        cursor: 'pointer', fontFamily: '"Patrick Hand", cursive',
        fontSize: 16, color: PIPI.ink, lineHeight: 1.2,
        fontWeight: lang === code ? 700 : 400,
      }}>{labels[code]}</button>
  );
  return (
    <div style={{ display: 'inline-flex', gap: 6, alignItems: 'center' }}>
      {PIPI_LANGS.map(btn)}
    </div>
  );
}

function LandingHero({ t, m }) {
  return (
    <div style={{
      display: m ? 'flex' : 'grid',
      flexDirection: 'column',
      gridTemplateColumns: m ? undefined : '1.05fr 1fr',
      gap: m ? 18 : 56,
      padding: m ? '24px 18px 28px' : '60px 56px 80px',
      alignItems: 'center',
      overflow: 'hidden', // belt-and-braces against any horizontal overflow from rotated/scaled children
    }}>
      <div style={{ width: '100%', maxWidth: m ? '100%' : undefined,
        textAlign: m ? 'center' : 'left' }}>
        <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8,
          padding: '6px 14px', background: PIPI.yellow,
          border: `3px solid ${PIPI.ink}`, borderRadius: 22, marginBottom: m ? 14 : 18 }}>
          <Sparkle size={m ? 16 : 20}/>
          <span style={{ fontSize: m ? 15 : 18 }}>{t.hero_kicker}</span>
        </div>
        <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700,
          fontSize: m ? 56 : 108, lineHeight: m ? 0.98 : 0.95, letterSpacing: -1 }}>
          {t.hero_title_1}<br/>
          {t.hero_title_2}<br/>
          <span style={{ background: PIPI.pink, padding: m ? '0 10px' : '0 14px', display: 'inline-block',
            transform: 'rotate(-1.5deg)', boxShadow: `0 0 0 4px ${PIPI.ink}` }}>{t.hero_title_3}</span>
        </div>
        <div style={{ fontSize: m ? 18 : 24, lineHeight: 1.35, marginTop: m ? 18 : 26, opacity: 0.82,
          maxWidth: 540, marginLeft: m ? 'auto' : undefined, marginRight: m ? 'auto' : undefined }}>
          {t.hero_body}
        </div>
        {/* Desktop: CTAs inside the text column. Mobile: CTAs render
           BELOW the phone, in their own block — the order the user
           asked for is headline → body → phone → CTAs. */}
        {!m && (
          <>
            <div style={{ display: 'flex', gap: 16, marginTop: 32, flexWrap: 'wrap' }}>
              <div data-action="goto-signup" style={{ display: 'inline-block' }}>
                <ScribbleButton color={PIPI.yellow} size="lg" seed={520}
                  icon={<svg width="22" height="22" viewBox="0 0 40 40"><path d={wobblyPath([[10,8],[10,32],[34,20]],{amp:1,seed:7})} fill={PIPI.ink}/></svg>}>
                  {t.hero_cta_primary}
                </ScribbleButton>
              </div>
              <div data-action="goto-signup" style={{ display: 'inline-block' }}>
                <ScribbleButton color={PIPI.paperLt} size="lg" seed={521}>
                  {t.hero_cta_secondary}
                </ScribbleButton>
              </div>
            </div>
            <div style={{ marginTop: 18, fontSize: 17, opacity: 0.65 }}>
              {t.hero_subnote}
            </div>
          </>
        )}
      </div>

      {/* phone showcase */}
      {m ? (
        // Mobile: scaled-down iPhone with the original lopsided rotate
        // so it keeps the same hand-drawn charm as desktop. Wrapped in
        // a fixed-size box so the empty 300+ px below the un-transformed
        // 874-tall layout is gone. Decorations stay hidden on mobile.
        <div style={{
          width: 282, height: 620,
          margin: '0 auto', position: 'relative',
        }}>
          <div style={{
            transform: 'scale(0.7) rotate(-3deg)',
            transformOrigin: 'top left',
          }}>
            <PhoneShell>
              <HomeScreen onOpen={() => {}} onTab={() => {}} showTabBar={false}/>
            </PhoneShell>
          </div>
        </div>
      ) : (
        <div style={{ position: 'relative', display: 'flex', justifyContent: 'center', width: '100%' }}>
          <svg width="600" height="600" style={{ position: 'absolute', top: -40, left: -20, zIndex: 0 }}>
            <path d={wobblyCirclePath(300, 300, 240, { amp: 5, seed: 660, segs: 28 })}
                  fill={PIPI.lilac} opacity={0.4}/>
            <path d={wobblyCirclePath(420, 180, 70, { amp: 3, seed: 661, segs: 18 })}
                  fill={PIPI.yellow} stroke={PIPI.ink} strokeWidth={3} opacity={0.95}/>
            <path d={wobblyCirclePath(140, 460, 50, { amp: 3, seed: 662, segs: 16 })}
                  fill={PIPI.pink} stroke={PIPI.ink} strokeWidth={3} opacity={0.95}/>
            {[[80,80],[510,440],[100,240]].map(([x,y],i) => (
              <path key={i} d={`M${x} ${y-12} L${x+4} ${y-3} L${x+12} ${y} L${x+4} ${y+3} L${x} ${y+12} L${x-4} ${y+3} L${x-12} ${y} L${x-4} ${y-3} Z`}
                fill={PIPI.yellow} stroke={PIPI.ink} strokeWidth={2.5}/>
            ))}
          </svg>

          <HeroPhoneHoverScroll>
            <div style={{ position: 'relative', zIndex: 1, transform: 'rotate(-3deg)' }}>
              <PhoneShell>
                <HomeScreen onOpen={() => {}} onTab={() => {}} showTabBar={false}/>
              </PhoneShell>
            </div>
          </HeroPhoneHoverScroll>
          <svg width="180" height="120" style={{ position: 'absolute', right: 0, top: '50%', zIndex: 2,
            transform: 'translate(0, -50%)' }}>
            <path d="M30 30 Q 100 10 150 60 Q 130 80 140 95" fill="none"
              stroke={PIPI.ink} strokeWidth={3} strokeDasharray="4 6"/>
            <path d="M135 100 L150 90 L150 105 Z" fill={PIPI.ink}/>
            <text x="6" y="22" fontFamily="Caveat" fontWeight="700" fontSize="26" fill={PIPI.ink}>
              {t.hero_tap}
            </text>
          </svg>
        </div>
      )}
      {/* Mobile order: CTAs sit AFTER the phone preview. */}
      {m && (
        <div style={{ width: '100%' }}>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            <div data-action="goto-signup">
              <ScribbleButton color={PIPI.yellow} size="md" seed={520} fullWidth
                icon={<svg width="22" height="22" viewBox="0 0 40 40"><path d={wobblyPath([[10,8],[10,32],[34,20]],{amp:1,seed:7})} fill={PIPI.ink}/></svg>}>
                {t.hero_cta_primary}
              </ScribbleButton>
            </div>
            <div data-action="goto-signup">
              <ScribbleButton color={PIPI.paperLt} size="md" seed={521} fullWidth>
                {t.hero_cta_secondary}
              </ScribbleButton>
            </div>
          </div>
          <div style={{ marginTop: 12, fontSize: 14, opacity: 0.65, textAlign: 'center' }}>
            {t.hero_subnote}
          </div>
        </div>
      )}
    </div>
  );
}

function LandingHow({ t, m }) {
  const steps = [
    { n: '01', t: t.how_1_t, d: t.how_1_d, Vis: () => <HowVis1 t={t} m={m}/> },
    { n: '02', t: t.how_2_t, d: t.how_2_d, Vis: () => <HowVis2 t={t} m={m}/> },
    { n: '03', t: t.how_3_t, d: t.how_3_d, Vis: () => <HowVis3 t={t} m={m}/> },
  ];
  return (
    <div id="how" style={{ background: PIPI.paperLt, borderTop: `3px solid ${PIPI.ink}`,
      borderBottom: `3px solid ${PIPI.ink}`,
      padding: m ? '40px 18px 44px' : '70px 56px',
      scrollMarginTop: 96, position: 'relative', zIndex: 0 }}>
      <FullBleedBg color={PIPI.paperLt} borderTop={`3px solid ${PIPI.ink}`} borderBottom={`3px solid ${PIPI.ink}`}/>
      <div style={{ textAlign: 'center', marginBottom: 8, position: 'relative' }}>
        <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: m ? 44 : 64, lineHeight: 1 }}>
          {t.how_title}
        </div>
        <div style={{ fontSize: m ? 17 : 22, opacity: 0.7, marginTop: 4 }}>
          {t.how_sub}
        </div>
      </div>
      <div style={{
        display: 'grid',
        gridTemplateColumns: m ? '1fr' : 'repeat(3, 1fr)',
        gap: m ? 18 : 28, marginTop: m ? 24 : 40,
      }}>
        {steps.map((s, i) => (
          <div key={s.n} style={{ position: 'relative' }}>
            <ScribbleCard style={{
              width: '100%', boxSizing: 'border-box',
              padding: m ? '16px 14px' : '24px 26px 24px',
              minHeight: m ? 'auto' : 380,
              overflow: 'hidden',
            }}>
              <div style={{
                display: 'flex', alignItems: 'baseline', gap: 10, flexWrap: 'wrap',
              }}>
                <span style={{ fontFamily: '"Caveat", cursive', fontWeight: 700,
                  fontSize: m ? 32 : 44, color: PIPI.red }}>{s.n}</span>
                <span style={{ fontFamily: '"Caveat", cursive', fontWeight: 700,
                  fontSize: m ? 24 : 36, lineHeight: 1.05,
                  overflowWrap: 'anywhere', wordBreak: 'normal',
                }}>{s.t}</span>
              </div>
              <div style={{
                fontSize: m ? 15 : 19, opacity: 0.8, lineHeight: 1.4,
                marginTop: 4, overflowWrap: 'break-word', wordBreak: 'normal',
                hyphens: 'auto',
              }}>{s.d}</div>
              <div style={{
                marginTop: m ? 12 : 18,
                display: 'flex', justifyContent: 'center',
                maxWidth: '100%', overflow: 'hidden',
              }}>
                <s.Vis/>
              </div>
            </ScribbleCard>
            {!m && i < 2 && (
              <svg width="60" height="40" style={{ position: 'absolute', right: -42, top: 60, zIndex: 2 }}>
                <path d={wobblyLinePath(0, 20, 50, 20, { amp: 1, seed: 700 + i, segs: 8 })}
                      fill="none" stroke={PIPI.ink} strokeWidth={3}/>
                <path d="M50 20 L40 13 L40 27 Z" fill={PIPI.ink}/>
              </svg>
            )}
          </div>
        ))}
      </div>
    </div>
  );
}

function HowVis1({ t, m }) {
  // Mobile: STACK vertically — chick above the speech bubble — so
  // neither one ever pokes past the card's right edge on a 360-wide
  // phone. The bubble shrinks via maxWidth:100% instead of a hardcoded
  // pixel width. Desktop keeps the original side-by-side composition.
  return (
    <div style={{
      display: 'flex',
      flexDirection: m ? 'column' : 'row',
      alignItems: 'center',
      gap: m ? 4 : 8,
      maxWidth: '100%',
    }}>
      <Pipi size={m ? 90 : 130}/>
      <svg viewBox="0 0 220 90"
        width={m ? 200 : 220}
        style={{ maxWidth: '100%', height: 'auto', marginBottom: m ? 0 : 8 }}
        preserveAspectRatio="xMidYMid meet">
        <path d={wobblyRectPath(6, 6, 208, 78, { r: 22, amp: 1.5, seed: 720 })}
              fill={PIPI.paperLt} stroke={PIPI.ink} strokeWidth={3}/>
        <path d="M20 80 L10 92 L34 80 Z" fill={PIPI.paperLt} stroke={PIPI.ink} strokeWidth={3} strokeLinejoin="round"/>
        <text x="20" y="36" fontFamily="Caveat" fontWeight="700" fontSize="22" fill={PIPI.ink}>{t.how_bubble_1}</text>
        <text x="20" y="62" fontFamily="Caveat" fontWeight="700" fontSize="22" fill={PIPI.ink}>{t.how_bubble_2}</text>
      </svg>
    </div>
  );
}

function HowVis2({ t, m }) {
  // Mobile: keep the circle full size — the listening visual is the
  // centerpiece of the card and shouldn't shrink. The pulse rings
  // already stay inside the card via overflow:hidden on the wrapper.
  const dia = m ? 130 : 140;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 }}>
      <style>{`
        @keyframes pipiListenPulse {
          0%   { transform: scale(0.85); opacity: 0.85; }
          70%  { opacity: 0.18; }
          100% { transform: scale(1.45); opacity: 0; }
        }
      `}</style>
      <div style={{ position: 'relative', width: dia, height: dia, marginTop: 6 }}>
        {[0, 1, 2].map(i => (
          <div key={i} style={{
            position: 'absolute', inset: 0, borderRadius: '50%',
            border: `3.5px dashed ${PIPI.blue}`,
            animation: `pipiListenPulse 1.8s cubic-bezier(.2,.7,.3,1) ${i * 0.45}s infinite`,
          }}/>
        ))}
        <div style={{ width: dia, height: dia, borderRadius: '50%', background: PIPI.blue,
          border: `4px solid ${PIPI.ink}`, display: 'flex', alignItems: 'center', justifyContent: 'center',
          position: 'relative', zIndex: 1 }}>
          <IconMic size={Math.round(dia * 0.46)}/>
        </div>
      </div>
      <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: m ? 22 : 26, color: PIPI.ink }}>
        {t.how_voice}
      </div>
    </div>
  );
}

function HowVis3({ t, m }) {
  // Tree of 3 branches. Scale to fit the card on mobile.
  const w = m ? 280 : 260;
  return (
    <svg viewBox="0 0 280 180" width={w} style={{ maxWidth: '100%', height: 'auto' }}>
      {/* The ? bubble at the top */}
      <path d={wobblyCirclePath(140, 30, 16, { amp: 1, seed: 730, segs: 14 })}
            fill={PIPI.yellow} stroke={PIPI.ink} strokeWidth={3}/>
      <text x="135" y="36" fontFamily="Caveat" fontWeight="700" fontSize="22" fill={PIPI.ink}>?</text>
      {/* Three diverging branches: left, middle-down, right */}
      <path d={wobblyLinePath(140, 46, 50,  90, { amp: 1, seed: 731, segs: 8 })}
            fill="none" stroke={PIPI.ink} strokeWidth={3}/>
      <path d={wobblyLinePath(140, 46, 140, 90, { amp: 1, seed: 739, segs: 8 })}
            fill="none" stroke={PIPI.ink} strokeWidth={3}/>
      <path d={wobblyLinePath(140, 46, 230, 90, { amp: 1, seed: 732, segs: 8 })}
            fill="none" stroke={PIPI.ink} strokeWidth={3}/>
      {/* Three destination dots */}
      <path d={wobblyCirclePath(50,  110, 18, { amp: 1, seed: 733, segs: 14 })}
            fill={PIPI.green} stroke={PIPI.ink} strokeWidth={3}/>
      <path d={wobblyCirclePath(140, 110, 18, { amp: 1, seed: 740, segs: 14 })}
            fill={PIPI.yellow} stroke={PIPI.ink} strokeWidth={3}/>
      <path d={wobblyCirclePath(230, 110, 18, { amp: 1, seed: 734, segs: 14 })}
            fill={PIPI.coral} stroke={PIPI.ink} strokeWidth={3}/>
      {/* Two thin sub-paths from each dot, just for texture */}
      <path d={wobblyLinePath(50,  130, 30,  152, { amp: 1, seed: 735, segs: 4 })}
            fill="none" stroke={PIPI.ink} strokeWidth={3}/>
      <path d={wobblyLinePath(50,  130, 75,  152, { amp: 1, seed: 736, segs: 4 })}
            fill="none" stroke={PIPI.ink} strokeWidth={3}/>
      <path d={wobblyLinePath(140, 130, 122, 152, { amp: 1, seed: 741, segs: 4 })}
            fill="none" stroke={PIPI.ink} strokeWidth={3}/>
      <path d={wobblyLinePath(140, 130, 158, 152, { amp: 1, seed: 742, segs: 4 })}
            fill="none" stroke={PIPI.ink} strokeWidth={3}/>
      <path d={wobblyLinePath(230, 130, 210, 152, { amp: 1, seed: 737, segs: 4 })}
            fill="none" stroke={PIPI.ink} strokeWidth={3}/>
      <path d={wobblyLinePath(230, 130, 255, 152, { amp: 1, seed: 738, segs: 4 })}
            fill="none" stroke={PIPI.ink} strokeWidth={3}/>
      {/* Labels: each branch gets the primary + an alternative under it,
          so the child sees that the choices are not fixed. */}
      <text x="50"  y="166" fontFamily="Caveat" fontWeight="700" fontSize="17" textAnchor="middle" fill={PIPI.ink}>{t.how_branch_left}</text>
      <text x="50"  y="178" fontFamily="Caveat" fontSize="13" textAnchor="middle" fill={PIPI.ink} opacity={0.65}>{t.how_branch_left_alt}</text>
      <text x="140" y="166" fontFamily="Caveat" fontWeight="700" fontSize="17" textAnchor="middle" fill={PIPI.ink}>{t.how_branch_mid}</text>
      <text x="140" y="178" fontFamily="Caveat" fontSize="13" textAnchor="middle" fill={PIPI.ink} opacity={0.65}>{t.how_branch_mid_alt}</text>
      <text x="230" y="166" fontFamily="Caveat" fontWeight="700" fontSize="17" textAnchor="middle" fill={PIPI.ink}>{t.how_branch_right}</text>
      <text x="230" y="178" fontFamily="Caveat" fontSize="13" textAnchor="middle" fill={PIPI.ink} opacity={0.65}>{t.how_branch_right_alt}</text>
    </svg>
  );
}

function LandingStories({ t, m }) {
  return (
    <div id="stories" style={{ padding: m ? '40px 18px 30px' : '70px 56px', scrollMarginTop: 96 }}>
      <div style={{
        display: 'flex', alignItems: m ? 'flex-start' : 'baseline',
        justifyContent: 'space-between', marginBottom: m ? 16 : 26,
        flexDirection: m ? 'column' : 'row', gap: m ? 4 : 0,
      }}>
        <div>
          <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: m ? 40 : 56, lineHeight: 1 }}>
            {t.stories_title}
          </div>
          <div style={{ fontSize: m ? 16 : 22, opacity: 0.7, marginTop: 4 }}>
            {t.stories_sub}
          </div>
        </div>
        <div style={{ fontSize: m ? 14 : 20, opacity: 0.75 }}>{t.stories_count}</div>
      </div>
      <StoriesCarousel t={t}/>
    </div>
  );
}

// Single-row carousel with scribble arrows. The right arrow shows
// initially; once the user scrolls the left arrow appears too. Hides
// the native scrollbar across Webkit / Firefox / IE.
function StoriesCarousel({ t }) {
  const scrollerRef = React.useRef(null);
  const [canScrollLeft, setCanScrollLeft] = React.useState(false);
  const [canScrollRight, setCanScrollRight] = React.useState(true);

  const updateArrows = React.useCallback(() => {
    const el = scrollerRef.current;
    if (!el) return;
    setCanScrollLeft(el.scrollLeft > 8);
    setCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 8);
  }, []);

  React.useEffect(() => {
    const el = scrollerRef.current;
    if (!el) return;
    updateArrows();
    el.addEventListener('scroll', updateArrows, { passive: true });
    window.addEventListener('resize', updateArrows);
    return () => {
      el.removeEventListener('scroll', updateArrows);
      window.removeEventListener('resize', updateArrows);
    };
  }, [updateArrows]);

  const scrollBy = (delta) => {
    if (scrollerRef.current) scrollerRef.current.scrollBy({ left: delta, behavior: 'smooth' });
  };

  return (
    <div style={{ position: 'relative' }}>
      <style>{`.pipi-shelf::-webkit-scrollbar { display: none; }`}</style>
      <div ref={scrollerRef} className="pipi-shelf" style={{
        display: 'flex', gap: 22, overflowX: 'auto', overflowY: 'hidden',
        scrollSnapType: 'x mandatory',
        padding: '6px 4px 18px',
        scrollbarWidth: 'none', msOverflowStyle: 'none',
      }}>
        {STORIES.map((s, i) => {
          const Art = s.art;
          return (
            <div key={s.id} style={{
              flex: '0 0 220px', scrollSnapAlign: 'start',
              transform: `rotate(${i % 2 === 0 ? -1.2 : 1.2}deg)`, position: 'relative',
            }}>
              <StoryBadge label={s.badge}/>
              <div style={{
                background: s.color, border: `3.5px solid ${PIPI.ink}`,
                borderRadius: 22, padding: 12,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                aspectRatio: '1',
              }}>
                <Art size={180}/>
              </div>
              <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700,
                fontSize: 26, lineHeight: 1.05, marginTop: 8 }}>
                {s.title}
              </div>
              <div style={{ fontSize: 16, opacity: 0.7 }}>{s.age} · {s.len} · {s.mood}</div>
            </div>
          );
        })}
      </div>
      <CarouselArrow direction="left"  visible={canScrollLeft}  onClick={() => scrollBy(-260)} labelPrev={t.ui_prev} labelNext={t.ui_next}/>
      <CarouselArrow direction="right" visible={canScrollRight} onClick={() => scrollBy(260)} labelPrev={t.ui_prev} labelNext={t.ui_next}/>
    </div>
  );
}

// Re-use the design's wobbly stroke vocabulary. The arrow is just a
// rounded button with a hand-drawn chevron — same scribble feel as
// the rest of the page.
function CarouselArrow({ direction, visible, onClick, labelPrev = 'Predchádzajúce', labelNext = 'Ďalšie' }) {
  const isLeft = direction === 'left';
  return (
    <button onClick={onClick}
      aria-label={isLeft ? labelPrev : labelNext}
      style={{
        position: 'absolute', top: '38%',
        [isLeft ? 'left' : 'right']: -14,
        transform: 'translateY(-50%)' + (isLeft ? ' rotate(-2deg)' : ' rotate(2deg)'),
        width: 60, height: 60, borderRadius: '50%',
        background: PIPI.yellow, border: `3.5px solid ${PIPI.ink}`,
        cursor: 'pointer', padding: 0, zIndex: 3,
        boxShadow: '4px 5px 0 rgba(0,0,0,0.20)',
        display: visible ? 'flex' : 'none',
        alignItems: 'center', justifyContent: 'center',
        opacity: visible ? 1 : 0,
        transition: 'opacity .15s, transform .15s',
      }}>
      <svg viewBox="0 0 40 40" width={26} height={26}
        style={{ transform: isLeft ? 'scaleX(-1)' : 'none' }}>
        <path d={wobblyPath([[12, 8], [28, 20], [12, 32]], { amp: 1.2, seed: isLeft ? 71 : 72 })}
          fill="none" stroke={PIPI.ink} strokeWidth={4}
          strokeLinecap="round" strokeLinejoin="round"/>
      </svg>
    </button>
  );
}

function LandingTrust({ t, m }) {
  return (
    <div id="trust" style={{ background: PIPI.blue, borderTop: `3px solid ${PIPI.ink}`,
      borderBottom: `3px solid ${PIPI.ink}`,
      padding: m ? '36px 18px 40px' : '70px 56px',
      display: m ? 'flex' : 'grid',
      flexDirection: 'column',
      gridTemplateColumns: m ? undefined : '1.1fr 1fr',
      gap: m ? 24 : 56,
      alignItems: m ? 'stretch' : 'center',
      scrollMarginTop: 96, position: 'relative', zIndex: 0 }}>
      <FullBleedBg color={PIPI.blue} borderTop={`3px solid ${PIPI.ink}`} borderBottom={`3px solid ${PIPI.ink}`}/>
      <div>
        <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: m ? 40 : 64, lineHeight: 1 }}>
          {t.trust_title_1}<br/>{t.trust_title_2}
        </div>
        <div style={{ fontSize: m ? 17 : 22, lineHeight: 1.4, marginTop: m ? 12 : 16, opacity: 0.85, maxWidth: 520 }}>
          {t.trust_body}
        </div>
        <div style={{ display: 'flex', gap: m ? 8 : 14, marginTop: m ? 16 : 22, flexWrap: 'wrap' }}>
          {t.trust_tags.map((tag) => <Tag key={tag} color={PIPI.paperLt}>{tag}</Tag>)}
        </div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: m ? '1fr' : '1fr 1fr', gap: m ? 12 : 16 }}>
        {t.quotes.map((q, i) => {
          const bgs = [PIPI.paperLt, PIPI.yellow, PIPI.pink, PIPI.paperLt];
          const rots = m ? [-0.6, 0.6, 0.6, -0.6] : [-1, 1.5, 2, -2];
          return <Quote key={i} name={q.name} text={q.text} rotate={rots[i]} bg={bgs[i]}/>;
        })}
      </div>
    </div>
  );
}

// Inlined from pipi-brand.jsx so the landing doesn't have to load the entire
// brand-canvas bundle just for a pill.
function Tag({ color = PIPI.yellow, children }) {
  const label = String(children || '');
  return (
    <div style={{ position: 'relative', display: 'inline-block' }}>
      <svg viewBox="0 0 160 36" width="100%" height="32" style={{ display: 'block' }} preserveAspectRatio="none">
        <path d={wobblyRectPath(2, 4, 156, 28, { r: 14, amp: 1.5, seed: color.length + label.length })}
              fill={color} stroke={PIPI.ink} strokeWidth={2.5}/>
      </svg>
      <div style={{
        position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center',
        fontFamily: '"Patrick Hand", cursive', fontSize: 17, color: PIPI.ink, paddingBottom: 2, padding: '0 14px',
        whiteSpace: 'nowrap',
      }}>{children}</div>
    </div>
  );
}

function Quote({ name, text, rotate = 0, bg = PIPI.paperLt }) {
  return (
    <div style={{
      background: bg, border: `3.5px solid ${PIPI.ink}`, borderRadius: 22,
      padding: '18px 20px', transform: `rotate(${rotate}deg)`,
      fontFamily: '"Patrick Hand", cursive',
    }}>
      <div style={{ fontFamily: '"Caveat", cursive', fontSize: 36, lineHeight: 0, color: PIPI.red }}>"</div>
      <div style={{ fontSize: 18, lineHeight: 1.35 }}>{text}</div>
      <div style={{ fontSize: 16, opacity: 0.65, marginTop: 10 }}>· {name}</div>
    </div>
  );
}

// New section: founders. Two scribble polaroids on a slightly tinted band.
function LandingFounders({ t, m }) {
  return (
    <div id="founders" style={{
      background: PIPI.paperLt, borderTop: `3px solid ${PIPI.ink}`,
      borderBottom: `3px solid ${PIPI.ink}`,
      padding: m ? '40px 18px 56px' : '78px 56px 96px',
      position: 'relative', scrollMarginTop: 96, zIndex: 0,
    }}>
      <FullBleedBg color={PIPI.paperLt} borderTop={`3px solid ${PIPI.ink}`} borderBottom={`3px solid ${PIPI.ink}`}/>
      <div style={{
        display: 'grid',
        gridTemplateColumns: m ? '1fr' : '0.95fr 1.2fr',
        gap: m ? 28 : 64,
        alignItems: m ? 'stretch' : 'center',
      }}>
        <div>
          <div style={{ fontSize: m ? 15 : 18, opacity: 0.65, marginBottom: 6, letterSpacing: 0.4 }}>
            {t.founders_eyebrow}
          </div>
          <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: m ? 44 : 72, lineHeight: 1 }}>
            {t.founders_title}
          </div>
          <div style={{ fontSize: m ? 17 : 22, lineHeight: 1.4, marginTop: m ? 12 : 18, opacity: 0.85, maxWidth: 480 }}>
            {t.founders_body}
          </div>
          {!m && (
            <svg width="170" height="40" style={{ marginTop: 18 }}>
              <path d={wobblyLinePath(4, 20, 160, 20, { amp: 3, seed: 901, segs: 14 })}
                    fill="none" stroke={PIPI.red} strokeWidth={3} strokeLinecap="round"/>
              <path d="M156 20 L146 14 L146 26 Z" fill={PIPI.red}/>
            </svg>
          )}
        </div>
        <div style={{
          display: 'grid',
          gridTemplateColumns: m ? '1fr' : '1fr 1fr',
          gap: m ? 22 : 28,
        }}>
          {t.founders.map((f, i) => (
            <FounderCard key={f.name} founder={f}
              rotate={m ? (i === 0 ? -1.2 : 1.2) : (i === 0 ? -2.4 : 2.1)}
              seed={910 + i}/>
          ))}
        </div>
      </div>
    </div>
  );
}

// Wraps the hero phone so that on hover the inner content scrolls top→bottom→top
// without touching the design. Pure programmatic scroll, no CSS animation.
// The IOSDevice component renders its content inside a div with `overflow: auto`
// — we find it by querySelector and animate its scrollTop with requestAnimationFrame.
function HeroPhoneHoverScroll({ children }) {
  const wrapRef = React.useRef(null);
  const rafRef = React.useRef(null);
  const findScroller = React.useCallback(() => {
    const wrap = wrapRef.current;
    if (!wrap) return null;
    // Match either "overflow: auto" or "overflow:auto" — React renders with a space.
    const candidates = wrap.querySelectorAll('div');
    for (let i = 0; i < candidates.length; i++) {
      const el = candidates[i];
      const style = el.getAttribute('style') || '';
      if (style.indexOf('overflow: auto') !== -1 || style.indexOf('overflow:auto') !== -1) {
        if (el.scrollHeight > el.clientHeight + 4) return el;
      }
    }
    return null;
  }, []);
  const stop = React.useCallback(() => {
    if (rafRef.current) cancelAnimationFrame(rafRef.current);
    rafRef.current = null;
  }, []);
  const start = React.useCallback(() => {
    stop();
    const scroller = findScroller();
    if (!scroller) return;
    const max = scroller.scrollHeight - scroller.clientHeight;
    if (max <= 0) return;
    const begin = performance.now();
    const duration = 5200; // 2.6s down, 2.6s back up
    const ease = (x) => -(Math.cos(Math.PI * x) - 1) / 2; // easeInOutSine
    const tick = (now) => {
      const t = ((now - begin) / duration) % 1;
      const tri = t < 0.5 ? t * 2 : (1 - t) * 2; // 0→1→0
      scroller.scrollTop = max * ease(tri);
      rafRef.current = requestAnimationFrame(tick);
    };
    rafRef.current = requestAnimationFrame(tick);
  }, [findScroller, stop]);
  const reset = React.useCallback(() => {
    stop();
    const scroller = findScroller();
    if (scroller) scroller.scrollTo({ top: 0, behavior: 'smooth' });
  }, [findScroller, stop]);
  React.useEffect(() => stop, [stop]);
  return (
    <div ref={wrapRef} onMouseEnter={start} onMouseLeave={reset} style={{ display: 'inline-block', cursor: 'ns-resize' }}>
      {children}
    </div>
  );
}

function FounderCard({ founder, rotate = 0, seed = 1 }) {
  return (
    <div style={{
      transform: `rotate(${rotate}deg)`,
      background: '#FFFCF2',
      border: `3.5px solid ${PIPI.ink}`, borderRadius: 22,
      padding: '14px 14px 18px',
      boxShadow: '8px 10px 0 rgba(0,0,0,0.16)',
      position: 'relative',
    }}>
      <div style={{
        position: 'absolute', top: -12, left: '50%', transform: 'translateX(-50%) rotate(-3deg)',
        width: 110, height: 22, background: 'rgba(255, 217, 61, 0.65)',
        border: `2px solid ${PIPI.ink}`,
      }}/>
      <div style={{
        background: PIPI.paper, border: `3px solid ${PIPI.ink}`,
        borderRadius: 14, overflow: 'hidden', aspectRatio: '1',
      }}>
        <img src={founder.img} alt={founder.name}
          loading="lazy" width={640} height={640}
          style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}/>
      </div>
      <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: 32, lineHeight: 1, marginTop: 14 }}>
        {founder.name}
      </div>
      <div style={{ fontSize: 16, opacity: 0.7, marginTop: 2 }}>
        {founder.role}
      </div>
      <div style={{ fontSize: 17, lineHeight: 1.35, marginTop: 10, opacity: 0.88 }}>
        {founder.note}
      </div>
      <div style={{ marginTop: 10, fontSize: 15, opacity: 0.7, fontFamily: '"JetBrains Mono", monospace' }}>
        {founder.link_label}
      </div>
    </div>
  );
}

function LandingCTA({ t, m }) {
  const [email, setEmail] = React.useState('');
  const [state, setState] = React.useState('idle'); // idle | sending | ok | err
  const [err, setErr] = React.useState('');
  const [audioState, setAudioState] = React.useState('stopped'); // stopped | playing
  const audioRef = React.useRef(null);

  const submit = async (e) => {
    e.preventDefault();
    if (!email || !email.includes('@')) {
      setState('err'); setErr(t.cta_invalid);
      return;
    }
    setState('sending'); setErr('');
    try {
      const res = await fetch('/api/waitlist', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: email.trim(), source: 'landing-cta-inline' }),
      });
      if (!res.ok) {
        const data = await res.json().catch(() => ({}));
        throw new Error(data.error || ('HTTP ' + res.status));
      }
      setState('ok');
    } catch (e) {
      setState('err'); setErr(e.message || t.cta_invalid);
    }
  };

  const toggleSample = () => {
    if (!audioRef.current) {
      audioRef.current = new Audio(t.cta_listen_url);
      audioRef.current.addEventListener('ended', () => setAudioState('stopped'));
    }
    if (audioState === 'playing') {
      audioRef.current.pause();
      audioRef.current.currentTime = 0;
      setAudioState('stopped');
    } else {
      audioRef.current.play().then(() => setAudioState('playing')).catch(() => setAudioState('stopped'));
    }
  };

  React.useEffect(() => () => { if (audioRef.current) { audioRef.current.pause(); audioRef.current = null; } }, []);

  return (
    <div id="signup" style={{
      padding: m ? '32px 18px 40px' : '44px 56px 56px',
      textAlign: 'center', position: 'relative',
      background: PIPI.yellow, borderTop: `3px solid ${PIPI.ink}`, borderBottom: `3px solid ${PIPI.ink}`,
      scrollMarginTop: 96, zIndex: 0,
    }}>
      <FullBleedBg color={PIPI.yellow} borderTop={`3px solid ${PIPI.ink}`} borderBottom={`3px solid ${PIPI.ink}`}/>
      <div style={{
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        gap: m ? 12 : 18, flexWrap: 'wrap',
        flexDirection: m ? 'column' : 'row',
      }}>
        <Pipi size={m ? 80 : 96}/>
        <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700,
          fontSize: m ? 40 : 64, lineHeight: 1,
          textAlign: m ? 'center' : 'left' }}>
          {t.cta_title_1}<br/>{t.cta_title_2}
        </div>
      </div>

      {state === 'ok' ? (
        <div style={{ maxWidth: 560, margin: '32px auto 0',
          background: PIPI.paperLt, border: `3.5px solid ${PIPI.ink}`, borderRadius: 22,
          padding: '20px 22px', boxShadow: '5px 6px 0 rgba(0,0,0,0.18)',
        }}>
          <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: 36, lineHeight: 1 }}>
            {t.cta_ok_title}
          </div>
          <div style={{ fontSize: 19, marginTop: 8, lineHeight: 1.35, opacity: 0.85 }}>
            {t.cta_ok_body}
          </div>
        </div>
      ) : (
        <form onSubmit={submit} style={{
          marginTop: 28, display: 'flex', justifyContent: 'center', alignItems: 'stretch',
          gap: 12, flexWrap: 'wrap', maxWidth: 880, margin: '28px auto 0',
        }}>
          <label htmlFor="cta-email" style={{ position: 'absolute', left: -9999 }}>{t.cta_email_label}</label>
          <input id="cta-email" type="email" required autoComplete="email"
            value={email} onChange={(e) => setEmail(e.target.value)}
            placeholder={t.cta_email_ph}
            style={{
              flex: '1 1 280px', minWidth: 240,
              border: `3.5px solid ${PIPI.ink}`, borderRadius: 18,
              padding: '14px 18px', fontFamily: '"Patrick Hand", cursive', fontSize: 22,
              background: PIPI.paperLt, color: PIPI.ink, outline: 'none',
            }}/>
          <button type="submit" disabled={state === 'sending'} style={{
            border: `3.5px solid ${PIPI.ink}`, borderRadius: 999,
            padding: '12px 26px', background: PIPI.pink, color: PIPI.ink,
            fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: 26,
            cursor: state === 'sending' ? 'wait' : 'pointer',
            boxShadow: '5px 6px 0 rgba(0,0,0,0.20)',
          }}>{state === 'sending' ? t.cta_sending : t.cta_primary}</button>
          <button type="button" onClick={toggleSample} style={{
            border: `3.5px solid ${PIPI.ink}`, borderRadius: 999,
            padding: '12px 22px', background: PIPI.paperLt, color: PIPI.ink,
            fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: 24,
            cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 8,
            boxShadow: '5px 6px 0 rgba(0,0,0,0.18)',
          }}>
            <span style={{ display: 'inline-block', width: 14, height: 14 }}>
              {audioState === 'playing'
                ? <svg viewBox="0 0 14 14"><rect x="2" y="2" width="3.5" height="10" fill={PIPI.ink}/><rect x="8.5" y="2" width="3.5" height="10" fill={PIPI.ink}/></svg>
                : <svg viewBox="0 0 14 14"><path d="M2 1.5 L2 12.5 L12 7 Z" fill={PIPI.ink}/></svg>}
            </span>
            {audioState === 'playing' ? t.cta_listening : t.cta_secondary}
          </button>
          {state === 'err' && (
            <div style={{ flex: '1 0 100%', color: PIPI.ink,
              background: PIPI.pinkLt, border: `2.5px solid ${PIPI.ink}`, borderRadius: 14,
              padding: '8px 14px', fontSize: 17, textAlign: 'center',
            }}>{err}</div>
          )}
        </form>
      )}

      <div style={{ fontSize: 17, opacity: 0.7, marginTop: 18 }}>
        {t.cta_subnote}
      </div>
    </div>
  );
}

// Co-creation pillar — sits between Stories and Trust. Repositions
// Pipi from "tablet for kids alone" → "shared moment between parent
// and child". Three short pillar cards.
function LandingCoCreate({ t, m }) {
  if (!t || !t.cocreate_title_1) return null;
  return (
    <div style={{
      padding: m ? '40px 18px 32px' : '70px 56px',
      position: 'relative', zIndex: 0,
      scrollMarginTop: 80,
    }}>
      <FullBleedBg color={PIPI.paperLt} borderTop={`3px solid ${PIPI.ink}`} borderBottom={`3px solid ${PIPI.ink}`}/>
      <div style={{ display: 'flex', flexDirection: m ? 'column' : 'row', gap: m ? 18 : 48, alignItems: m ? 'stretch' : 'flex-start' }}>
        <div style={{ flex: 1 }}>
          <div style={{ display: 'inline-block', background: PIPI.yellow,
            border: `3px solid ${PIPI.ink}`, borderRadius: 22,
            padding: '4px 12px', fontSize: m ? 14 : 16, fontWeight: 700,
            fontFamily: '"Patrick Hand", cursive',
          }}>{t.cocreate_eyebrow}</div>
          <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700,
            fontSize: m ? 44 : 80, lineHeight: 0.98, marginTop: m ? 10 : 18,
          }}>
            {t.cocreate_title_1}<br/>
            <span style={{ background: PIPI.coral, padding: '0 10px', display: 'inline-block',
              transform: 'rotate(-1.2deg)', boxShadow: `0 0 0 4px ${PIPI.ink}`,
            }}>{t.cocreate_title_2}</span>
          </div>
          <div style={{ fontSize: m ? 17 : 21, lineHeight: 1.4, marginTop: m ? 14 : 22, opacity: 0.85, maxWidth: 520 }}>
            {t.cocreate_body}
          </div>
        </div>
        <div style={{
          flex: 1, display: 'grid', gap: m ? 12 : 16,
          gridTemplateColumns: m ? '1fr' : '1fr',
        }}>
          {(t.cocreate_pillars || []).map((p, i) => (
            <div key={i} style={{
              background: PIPI.paper, border: `3px solid ${PIPI.ink}`, borderRadius: 20,
              padding: m ? '14px 16px' : '16px 20px',
              boxShadow: '6px 8px 0 rgba(0,0,0,0.14)',
            }}>
              <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: m ? 28 : 32, lineHeight: 1 }}>
                {p.t}
              </div>
              <div style={{ fontSize: m ? 16 : 18, opacity: 0.82, marginTop: 6, lineHeight: 1.4 }}>
                {p.d}
              </div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// Comparison: classic book vs. tablet game vs. Pipi. Three columns,
// honest tradeoff framing — every column has BOTH pros and cons,
// then Pipi sits in the middle as a synthesis. Helps the reader
// place Pipi against what they already know.
function LandingCompare({ t, m }) {
  if (!t || !t.compare_title) return null;
  const toneColor = (tone) => tone === 'pink' ? PIPI.pinkLt : tone === 'yellow' ? PIPI.yellow : PIPI.paperLt;
  return (
    <div style={{
      padding: m ? '40px 18px 30px' : '70px 56px',
      position: 'relative', zIndex: 0,
      scrollMarginTop: 80,
    }}>
      <FullBleedBg color={PIPI.paper} borderTop={`3px solid ${PIPI.ink}`} borderBottom={`3px solid ${PIPI.ink}`}/>
      <div style={{ textAlign: 'center', marginBottom: m ? 18 : 32 }}>
        <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: m ? 38 : 60, lineHeight: 1 }}>
          {t.compare_title}
        </div>
        <div style={{ fontSize: m ? 16 : 19, opacity: 0.72, marginTop: 8 }}>
          {t.compare_sub}
        </div>
      </div>
      <div style={{
        display: 'grid',
        gridTemplateColumns: m ? '1fr' : 'repeat(3, 1fr)',
        gap: m ? 14 : 20,
      }}>
        {(t.compare_cols || []).map((c, i) => (
          <div key={i} style={{
            background: toneColor(c.tone),
            border: `3.5px solid ${PIPI.ink}`, borderRadius: 22,
            padding: m ? '16px 18px' : '18px 22px',
            boxShadow: '5px 6px 0 rgba(0,0,0,0.16)',
            transform: i === 1 ? 'rotate(-0.4deg)' : i === 2 ? 'rotate(0.6deg)' : 'rotate(-0.2deg)',
          }}>
            <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700,
              fontSize: m ? 32 : 38, lineHeight: 1, marginBottom: 10,
            }}>{c.t}</div>
            <ul style={{ margin: 0, paddingLeft: 18, fontSize: m ? 16 : 17, lineHeight: 1.45 }}>
              {(c.rows || []).map((r, j) => <li key={j} style={{ padding: '2px 0' }}>{r}</li>)}
            </ul>
          </div>
        ))}
      </div>
    </div>
  );
}

// Newsletter — a thin band between CTA and footer for people who
// don't want to sign up for the launch (the waitlist CTA above) but
// would like occasional updates after launch. Separate intent,
// separate database table (newsletter_subscribers), separate
// unsubscribe flow. Kept compact on purpose: this is not the main
// CTA, just a side option.
function LandingNewsletter({ t, m }) {
  const [email, setEmail] = React.useState('');
  const [status, setStatus] = React.useState('idle'); // idle | sending | ok | err
  const [error, setError] = React.useState('');
  const submit = async (e) => {
    e.preventDefault();
    if (!email || !email.includes('@')) { setStatus('err'); setError(t.news_invalid); return; }
    setStatus('sending'); setError('');
    try {
      const base = (typeof window !== 'undefined' && window.PIPI_API_BASE) || '';
      const res = await fetch(`${base}/api/newsletter`, {
        method: 'POST', headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ email: email.trim(), source: 'landing-newsletter', topics: ['updates', 'new-books'] }),
      });
      if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error || ('HTTP ' + res.status));
      setStatus('ok');
    } catch (err) { setStatus('err'); setError(err.message || t.news_neterr); }
  };
  return (
    <div style={{
      padding: m ? '24px 18px' : '36px 56px',
      position: 'relative', zIndex: 0,
    }}>
      <FullBleedBg color={PIPI.paperLt} borderTop={`3px solid ${PIPI.ink}`} borderBottom={`3px solid ${PIPI.ink}`}/>
      <div style={{
        display: 'flex', alignItems: m ? 'stretch' : 'center', justifyContent: 'space-between',
        gap: m ? 12 : 24, flexDirection: m ? 'column' : 'row',
      }}>
        <div style={{ flex: 1 }}>
          <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: m ? 28 : 34, lineHeight: 1, color: PIPI.ink }}>
            {t.news_title}
          </div>
          <div style={{ fontSize: m ? 14 : 16, opacity: 0.72, marginTop: 4, maxWidth: 480 }}>
            {t.news_body}
          </div>
        </div>
        {status === 'ok' ? (
          <div style={{
            padding: '10px 14px', background: PIPI.green, border: `2.5px solid ${PIPI.ink}`,
            borderRadius: 14, fontSize: 15, fontWeight: 700,
          }}>{t.news_ok}</div>
        ) : (
          <form onSubmit={submit} style={{ display: 'flex', gap: 8, flex: m ? '0 0 auto' : '0 0 380px', flexWrap: 'wrap' }}>
            <input type="email" value={email} onChange={(e) => setEmail(e.target.value)}
              placeholder={t.news_email_ph} required aria-label={t.news_title}
              style={{
                flex: 1, minWidth: 180, border: `2.5px solid ${PIPI.ink}`, borderRadius: 12,
                padding: '8px 12px', fontFamily: '"Patrick Hand", cursive', fontSize: 16,
                background: PIPI.paper, color: PIPI.ink, outline: 'none', minHeight: 42,
              }}/>
            <button type="submit" disabled={status === 'sending'} style={{
              background: PIPI.yellow, border: `2.5px solid ${PIPI.ink}`, borderRadius: 999,
              padding: '8px 18px', fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: 18,
              cursor: status === 'sending' ? 'wait' : 'pointer', color: PIPI.ink,
              boxShadow: '3px 4px 0 rgba(0,0,0,0.18)', whiteSpace: 'nowrap',
            }}>{status === 'sending' ? t.news_sending : t.news_cta}</button>
            {status === 'err' && <div style={{ width: '100%', background: PIPI.pink, padding: '4px 10px', borderRadius: 10, fontSize: 13 }}>{error}</div>}
          </form>
        )}
      </div>
    </div>
  );
}

function LandingFooter({ t, m }) {
  return (
    <div style={{ background: PIPI.ink, color: PIPI.paper,
      padding: m ? '28px 18px 22px' : '40px 56px 32px',
      fontFamily: '"Patrick Hand", cursive', fontSize: m ? 16 : 18,
      position: 'relative', zIndex: 0 }}>
      <FullBleedBg color={PIPI.ink}/>
      <div style={{
        display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start',
        width: '100%', gap: m ? 22 : 32, flexWrap: 'wrap',
        flexDirection: m ? 'column' : 'row',
      }}>
        <div>
          <PipiWordmark height={m ? 40 : 50} color={PIPI.paper} fill={PIPI.yellow}/>
          <div style={{ marginTop: 10, opacity: 0.7 }}>
            {t.footer_made_in}
          </div>
        </div>
        <div style={{
          display: m ? 'grid' : 'flex',
          gridTemplateColumns: m ? '1fr 1fr' : undefined,
          gap: m ? '14px 22px' : 56, flexWrap: 'wrap', width: m ? '100%' : 'auto',
        }}>
          <FooterCol title={t.footer_col_1_t} items={t.footer_col_1}/>
          <FooterCol title={t.footer_col_2_t} items={t.footer_col_2}/>
          <FooterCol title={t.footer_col_3_t} items={t.footer_col_3}/>
        </div>
      </div>
      <div style={{ borderTop: `1px solid rgba(245,231,199,0.18)`, width: '100%', paddingTop: 14, marginTop: m ? 18 : 26, opacity: 0.5, fontSize: m ? 13 : 15 }}>
        {t.footer_copy}
      </div>
    </div>
  );
}

function FooterCol({ title, items }) {
  // items used to be plain strings; now they're { label, href } so each
  // column item becomes a real anchor — fixes the user-reported
  // "footer links don't go anywhere" bug.
  return (
    <div>
      <div style={{ fontFamily: '"Caveat", cursive', fontWeight: 700, fontSize: 22,
        color: PIPI.yellow, marginBottom: 6 }}>{title}</div>
      {items.map((i) => {
        const item = typeof i === 'string' ? { label: i, href: null } : i;
        if (!item.href) {
          return <div key={item.label} style={{ opacity: 0.55, padding: '2px 0' }}>{item.label}</div>;
        }
        return (
          <a key={item.label} href={item.href}
            style={{
              display: 'block', padding: '2px 0', opacity: 0.78,
              color: PIPI.paper, textDecoration: 'none',
              borderBottom: '1.5px solid transparent', transition: 'border-color .15s, opacity .15s',
            }}
            onMouseEnter={(e) => { e.currentTarget.style.opacity = 1; e.currentTarget.style.borderBottomColor = PIPI.yellow; }}
            onMouseLeave={(e) => { e.currentTarget.style.opacity = 0.78; e.currentTarget.style.borderBottomColor = 'transparent'; }}>
            {item.label}
          </a>
        );
      })}
    </div>
  );
}

Object.assign(window, { PipiLanding, PIPI_STRINGS, PIPI_LANGS, pipiT });
