/* Klipzy.lv — shared components */
const { useState, useRef, useEffect, useMemo } = React;

/* ---------- formatting (Latvian) ---------- */
const _klipzyLang = () => { try { return localStorage.getItem('klipzy_lang') || 'lv'; } catch (_) { return 'lv'; } };
const eur = (n) => { const s = Number(n).toFixed(2).replace('.', ','); return _klipzyLang() === 'lv' ? s + ' €' : '€' + s; };
const eur0 = (n) => { const s = Number(n || 0).toLocaleString('lv-LV', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).replace(/\u00a0/g, ' ').replace(/,/g, '#').replace(/\./g, ' ').replace(/#/g, ','); return _klipzyLang() === 'lv' ? s + ' €' : '€' + s; };
const views = (n) => {
  if (n >= 1e6) return (n / 1e6).toFixed(n % 1e6 === 0 ? 0 : 1).replace('.', ',') + 'M';
  if (n >= 1000) return Math.round(n / 1000) + 'K';
  return String(n);
};
const numLv = (n) => Math.round(n).toLocaleString('lv-LV').replace(/,/g, ' ').replace(/\u00a0/g, ' ');

/* ---------- i18n (homepage) ---------- */
const TR_EN = {
  // hero (clipper)
  'Pelni no skatījumiem': 'Earn from views',
  'Pelni, veidojot klipus ': 'Earn by creating clips for ',
  'zīmoliem': 'brands',
  'Publicē klipus un pelni par to skatījumiem.': 'Post clips and get paid for the views they generate.',
  'Publicē klipus un pelni par sasniegtajiem skatījumiem.': 'Post clips and get paid for the views they generate.',
  'Sākt pelnīt': 'Start earning',
  'par 1000 skatījumiem': 'for 1000 views',
  'vidējais izmaksu laiks': 'Average payout time',
  'vidējais izmaksas laiks': 'Average payout time',
  'aktīvi zīmoli': 'Active brands',
  // hero mock (clipper)
  'Klipotāja panelis': 'Clipper dashboard',
  'šodien': 'Today',
  'Kopējie skatījumi': 'Total views',
  'Nopelnīts': 'Earned',
  'Aktīvās kampaņas': 'Active campaigns',
  'Rīga Energy izmaksa': 'Rīga Energy paid',
  'reāllaikā': 'live',
  'Izmaksāts klipotājiem': 'Paid to clippers',
  'izmaksa': 'payout',
  'Vēl nav aktīvu kampaņu': 'No active campaigns yet',
  'Šodien nav aktīvu kampaņu': 'No active campaigns today',
  'Mums uzticas': 'Trusted by',
  // par klipzy boxes
  'Kampaņas': 'Campaigns',
  'Pārlūko aktuālās zīmolu kampaņas': 'Browse the latest brand campaigns',
  'Kā tas darbojas': 'How it works',
  'Process klipotājiem un zīmoliem': 'Process for clippers and brands',
  'Mācības': 'Learning',
  'Mācies veidot klipus, kas piesaista skatījumus': 'Learn how to create clips that get views',
  'Iemācies veidot klipus, kas piesaista skatījumus': 'Learn how to create clips that get views',
  'Iemācies veidot pelnošus klipus': 'Learn how to create clips that get views',
  'Cenas': 'Pricing',
  'Maksā tikai par skatījumiem': 'Pay only for views',
  // how it works (clipper)
  'Sāc pelnīt 3 soļos': 'Start earning in 3 steps',
  'Ātra uzsākšana': 'Start earning in 3 steps',
  'Uzzināt vairāk': 'Learn more',
  'Izvēlies kampaņu, izveidot klipu un pelni par skatījumiem.': 'Choose a campaign, create a clip and get paid for views.',
  'Izvēlies kampaņu, izveido klipu un pelni par skatījumiem.': 'Choose a campaign, create a clip and earn from views.',
  'Sāc veidot saturu un pelni par iegūtajiem skatījumiem.': 'Choose a campaign, create a clip and get paid for views.',
  'Atrodi kampaņu': 'Find a campaign',
  'Aplūko zīmolu kapņas un izvēlies sev piemērotāko.': 'Browse active campaigns and choose one that fits you.',
  'Pārlūko zīmolu kampaņas un izvēlies sev piemērotāko nišu.': 'Browse active campaigns and choose one that fits you.',
  'Pārlūko aktīvās zīmolu kampaņās un izvēlies sev piemērotāko. Katra kampaņa skaidri norāda budzētu un satura vadlīnijas.': 'Browse active brand campaigns and choose the one that suits you best. Each campaign clearly outlines the budget and content guidelines.',
  'Pārlūko aktīvās zīmolu kampaņas, salīdzini cenas par 1000 skatījumiem un izvēlies sev piemērotāko nišu. Katra kampaņa skaidri norāda budžetu un satura vadlīnijas.': 'Browse active brand campaigns and choose the one that suits you best. Each campaign clearly outlines the budget and content guidelines.',
  'Izveido klipu': 'Create a clip',
  'Izveido īsformāta klipu pēc zīmola vadlīnijām.': "Create a short-form clip following the brand's guidelines.",
  'Uzņem un samontē īsformāta klipu pēc zīmola vadlīnijām.': "Create a short-form clip following the brand's guidelines.",
  'Izveido īsformāta klipu pēc zīmola vadlīnijām un publicē to savos kanālos — TikTok, Instagram vai YouTube.': "Create a short-form clip following the brand's guidelines and post it on your channels — TikTok, Instagram or YouTube.",
  'Uzņem un samontē īsformāta klipu pēc zīmola vadlīnijām, un publicē to savos kanālos — TikTok, Instagram Reels vai YouTube Shorts.': "Create a short-form clip following the brand's guidelines and post it on your channels — TikTok, Instagram or YouTube.",
  'Saņem samaksu': 'Receive payment',
  'Iesniedz saiti — skatījumi tiek izsekoti un izmaksāti automātiski.': 'Submit a video — views are tracked and paid out automatically.',
  'Iesniedz savu klipu Klipzy. Mēs automātiski uzskaitām tā skatījumus un aprēķinām jūsu ieņēmumus, pamatojoties uz kampaņas likmi.': 'Submit your clip to Klipzy. We track its views automatically and calculate your earnings based on the campaign rate.',
  'Iesniedz klipa saiti platformā. Skatījumi tiek izsekoti automātiski, un samaksa par katriem 1000 skatījumiem nonāk tavā kontā.': 'Submit your clip to Klipzy. We track its views automatically and calculate your earnings based on the campaign rate.',
  // featured campaigns
  'Aktuālās kampaņas': 'Current campaigns',
  'Sāc pelnīt jau šodien': 'Start earning today',
  'Skatīt visas kampaņas': 'View all campaigns',
  'Enerģijas dzēriens': 'Energy drink',
  'Sporta derības': 'Sports betting',
  'Fintech maksājumu lietotne': 'Fintech payment app',
  '/ 1000 skatījumi': '/ 1000 views',
  '/ 1000 skatījumiem': '/ 1000 views',
  'Sports': 'Sport',
  'Finanses': 'Finance',
  'Budžets': 'Budget',
  'Skatīt kampaņu': 'View campaign',
  // stats band
  'Izmaksāts klipotājiem': 'Paid to the clippers',
  // cta
  'Gatavs sākt?': 'Ready to start?',
  'Gatavs sākt pelnīt?': 'Ready to start earning?',
  'Pievienojies Latvijas pirmajai klipu kampaņu platformai.': "Join Latvia's first video campaign platform.",
  'Latvijas pirmā klipu kampaņas platforma.': "Latvia's first platform for clip-based campaigns.",
  'Sākt klipot': 'Start clipping',
  // footer
  'Klipu kampaņu platforma, kas savieno zīmolus ar klipotājiem un atlīdzību balsta uz sasniegtajiem skatījumiem.': 'A clip campaign platform connecting brands with clippers, with payments based on views.',
  'Klipu kampaņu platforma, kas savieno klipotājus un zīmolus. Maksā tikai par skatījumiem.': 'A clip campaign platform connecting brands with clippers, with payments based on views.',
  'Pieejams Latvijā': 'Available in Latvia',
  'Produkts': 'Products',
  'Uzņēmums': 'Company',
  'Par mums': 'About us',
  'Blogs': 'Blog',
  'Karjera': 'Career',
  'Kontakti': 'Contacts',
  'Resursi': 'Resources',
  'Palīdzība': 'Help',
  'Noteikumi': 'Rules',
  'Privātums': 'Privacy',
  'Privātuma politika': 'Privacy Policy',
  'Drošība': 'Security',
  'Klipotājiem': 'For Clippers',
  'Zīmoliem': 'For Brands',
  'Daļa no': 'Part of',
  'Šobrīd pieejams tikai Latvijas tirgū.': 'Currently available only on the Latvian market.',
  // ---- brand (Zīmoliem) page ----
  'Maksā tikai par rezultātu': 'Pay only for results',
  'Pārbaudīts saturs un ': 'Proven content and ',
  'garantēti rezultāti': 'guaranteed results',
  'Maksā tikai par ': 'Pay only for ',
  'rezultātu': 'results',
  'Garantēta redzamība, ': 'Guaranteed visibility, ',
  'Redzamība, ': 'Visibility, ',
  'Saturs, par kuru maksā ': 'Content you pay for ',
  'pēc rezultātiem': 'based on results',
  'kas maksā mazāk par reklāmām': 'that costs less than ads',
  'Sasniedz jaunu auditoriju ar klipotāju veidotu saturu un maksā par skatījumiem.': 'Reach new audiences with creator-made clips and pay based on views.',
  'Sasniedz auditoriju ar klipiem un maksā par rezultātiem.': 'Reach new audiences with creator-made clips and pay based on views.',
  'Reģistrēt zīmolu': 'Register your brand',
  'Sākt kampaņu': 'Start a campaign',
  'garantēti skatījumi': 'Average views',
  'vidējie skatījumi': 'Average views',
  'aktīvi klipotaji': 'Active clippers',
  'pirmie rezultāti': 'First results',
  'Zīmola panelis': 'Brand dashboard',
  'Pārbaudīti skatījumi': 'Verified views',
  'Aktīvie klipotaji': 'Active clippers',
  'Klipotājs': 'Clipper',
  'Klipotāja': 'Clipper',
  'Jauni skatījumi no Jānis': 'New views from Jānis',
  'No kampaņas līdz rezultātiem': 'From campaign to results',
  'Ātri un garantēti rezultāti': 'From campaign to results',
  'Izveido kampaņu, saņem klipotāju veidotu saturu un seko rezultātiem.': 'Launch a campaign, get content from clippers and track the results.',
  'Izveido kampaņu, piesaisti klipotājus un gaidi rezultātus.': 'Launch a campaign, get content from clippers and track the results.',
  'Izveido kampaņu': 'Create a campaign',
  'Nosaki cenu par 1000 skatījumiem, budžetu un vadlīnijas.': 'Set the price per 1,000 views, the budget, and guidelines.',
  'Nosaki cenu par 1000 skatījumiem, kopējo budžetu un satura vadlīnijas. Tavu kampaņu uzreiz redz visi platformas klipotāji.': 'Set the price per 1,000 views, your total budget, and content guidelines. Your campaign is instantly visible to all clippers on the platform.',
  'Klipotāji veido saturu': 'Clippers create content',
  'Klipotāji veido saturu tavam zīmolam.': 'Clippers create content for your brand.',
  'Desmitiem klipotāju veido klipus tavam zīmolam.': 'Clippers create content for your brand.',
  'Klipotāji veido un publicē saturu tavam zīmolam — TikTok, Instagram un YouTube platformās.': 'Clippers create and publish content for your brand across TikTok, Instagram and YouTube.',
  'Desmitiem klipotāju veido un publicē klipus tavam zīmolam dažādās platformās — bez fiksētām maksām un bez riska.': 'Clippers create and publish content for your brand across TikTok, Instagram and YouTube.',
  'Maksā tikai par pārbaudītiem skatījumiem.': 'Pay only for verified views.',
  'Maksā par reāliem skatījumiem — nevis par cerībām.': 'Pay only for verified views.',
  'Maksā par pārbaudītiem skatījumiem un seko kampaņas rezultātiem savā Klipzy panelī.': "Pay for verified views and track your campaign's performance from your Klipzy dashboard.",
  'Maksā tikai par pārbaudītiem, reāliem skatījumiem — nevis par cerībām. Visi rezultāti ir izsekojami reāllaikā tavā panelī.': "Pay for verified views and track your campaign's performance from your Klipzy dashboard.",
  'Atsauksmes': 'Testimonials',
  'Ko mūsu klienti saka par Klipzy': 'What our clients say about Klipzy',
  'Ko mūsu klienti saka par Mums': 'What our clients say about Klipzy',
  'Mēs maksājām tikai par reāliem skatījumiem — desmitiem klipotāju sasniedza auditoriju, ko paši nekad nebūtu aizsnieguši.': 'We paid only for real views — dozens of clippers reached an audience we never could have reached ourselves.',
  'Kampaņa bija gatava dažās minūtēs, un pirmie rezultāti ienāca jau tajā pašā dienā. Bez riska, bez liekām maksām.': 'The campaign was ready in minutes, and the first results came in the very same day. No risk, no extra fees.',
  'Labākā satura mārketinga investīcija — caurspīdīgi rezultāti un skatījumi, ko varam izsekot reāllaikā.': 'The best content marketing investment — transparent results and views we can track in real time.',
  'Klipzy palīdzēja mums sasniegt jaunu, jaunāku auditoriju autentiskā veidā. Iesakām katram zīmolam.': 'Klipzy helped us reach a new, younger audience in an authentic way. We recommend it to every brand.',
  'No budžeta līdz pirmajiem 100k skatījumiem — viss process bija vienkāršs un pilnībā pārredzams.': 'From budget to the first 100k views — the whole process was simple and completely transparent.',
  'Mūsu zīmola atpazīstamība auga strauji, maksājot tikai par sasniegtajiem rezultātiem.': 'Our brand awareness grew rapidly while paying only for the results achieved.',
  'Gatavs redzēt rezultātus?': 'Ready to launch a campaign?',
  'Gatavs sākt kampaņu?': 'Ready to launch a campaign?',
  'Pievienot zīmolu': 'Start a campaign',
  'Visas kampaņas': 'All campaigns',
  // ---- top nav auth ----
  'Pieslēgties': 'Log in',
  'Reģistrēties': 'Register',
  'Panelis': 'Dashboard',
  'Iziet': 'Sign out',
  // ---- login page ----
  'Laipni lūdzam atpakaļ Klipzy.': 'Welcome back to Klipzy.',
  'E-pasts': 'Email',
  'Parole': 'Password',
  'Atcerēties mani': 'Remember me',
  'Aizmirsi paroli?': 'Forgot password?',
  'Nav konta?': "Don't have an account?",
  'Reģistrējies': 'Sign up',
  // ---- register page ----
  'Pievienojies Klipzy': 'Join Klipzy',
  'Izvēlies, kā vēlies izmantot Klipzy.': 'Choose how you want to use Klipzy.',
  'Klipotājs': 'Clipper',
  'Veido klipus zīmoliem un pelni pēc skatījumiem.': 'Create clips for brands and earn based on views.',
  'Pārlūko kampaņas': 'Browse campaigns',
  'Veido un iesniedz klipus': 'Create & submit clips',
  'Saņem samaksu': 'Get paid',
  'Zīmols / Uzņēmums': 'Brand / Company',
  'Veido kampaņas un maksā par rezultātu.': 'Launch campaigns and pay for results.',
  'Izveido kampaņas': 'Create campaigns',
  'Saņem saturu no veidotājiem': 'Get content from creators',
  'Maksā par skatījumiem': 'Pay based on views',
  'Turpināt': 'Continue',
  'Jau ir konts?': 'Already have an account?',
  'Pieslēdzies': 'Log in',
  'Mainīt lomu': 'Change role',
  'Pārslēgt lomu': 'Switch role',
  'Vēl tikai daži soļi.': 'Just a few more steps.',
  'Izveido klipotāja kontu': 'Create a clipper account',
  'Reģistrē savu zīmolu': 'Register your brand',
  'Tikai dažas detaļas, un esi gatavs.': "Just a few more details, and you're all set",
  'Vārds, uzvārds': 'Full name',
  'piem. Jānis Bērziņš': 'e.g., Jānis Bērziņš',
  'Uzņēmuma nosaukums': 'Company name',
  'piem. Rīga Energy': 'e.g., Rīga Energy',
  'Izveidot klipotāja kontu': 'Create a clipper account',
  'Izveidot zīmola kontu': 'Create a brand account',
  'Reģistrējoties, tu piekrīti Klipzy noteikumiem un privātuma politikai.': "By registering, you agree to Klipzy's terms and conditions and privacy policy.",
  'Turpināt ar Google': 'Continue with Google',
  'vai': 'or',
  'Notiek...': 'Working...',
  'Minimālais kampaņas budžets ir €10 (ar komisiju).': 'The minimum campaign budget is €10 (including fee).',
  // ── admin dashboard ──
  'Apstiprināt izmaksu': 'Confirm payout',
  'Vai tiešām atzīmēt šo izmaksu kā izmaksātu?': 'Mark this payout as paid?',
  'Izmaksa atzīmēta kā izmaksāta.': 'Payout marked as paid.',
  'Izmaksa atteikta un līdzekļi atgriezti.': 'Payout declined and funds returned.',
  'Noraidīt klipu': 'Reject clip',
  'Klipotājs redzēs norādīto iemeslu.': 'The clipper will see the reason you provide.',
  'Neatbilst vadlīnijām': 'Not meeting guidelines',
  'Zema kvalitāte': 'Low quality',
  'Cits iemesls': 'Other reason',
  'Ieraksti iemeslu…': 'Write a reason…',
  'Bez iemesla / izlaist': 'No reason / skip',
  'Iesniegt jaunu saiti': 'Submit a new link',
  'Noraidīšanas iemesls': 'Rejection reason',
  'Nomaini saiti uz jaunu klipu — tas tiks nosūtīts atkārtotai pārbaudei. Pārējie kampaņas dati paliek nemainīgi.': 'Replace the link with a new clip — it will be sent for review again. The rest of the campaign details stay the same.',
  'Jaunā klipa saite': 'New clip link',
  'Iesniegt atkārtoti': 'Resubmit',
  'Jauna saite': 'New link',
  // ── Brand dashboard ──
  'Manas aktīvās kampaņas': 'My active campaigns',
  'Nav aktīvu kampaņu.': 'No active campaigns.',
  'Manas kampaņas': 'My campaigns',
  'Iesniegtie klipi': 'Submitted clips',
  'Maksājumi': 'Payments',
  'Iestatījumi': 'Settings',
  'Pārskats par taviem kampaņu rezultātiem.': 'Overview of your campaign results.',
  'Aktīvie klipotāji': 'Active clippers',
  'Iztērēts / Budžets': 'Spent / Budget',
  'Gaida pārbaudi': 'Awaiting review',
  'Skatījumi laikā': 'Views over time',
  'Pēdējās 30 dienas': 'Last 30 days',
  'Kampaņa': 'Campaign',
  'Statuss': 'Status',
  'Skatījumi': 'Views',
  'Iztērēts': 'Spent',
  'Klipotāji': 'Clippers',
  'Top klipotāji': 'Top clippers',
  'Aktīva': 'Active',
  'Izveidot kampaņu': 'Create a campaign',
  'Visas': 'All',
  'Veēl nav kampaņu. Izveido savu pirmo!': 'No campaigns yet. Create your first!',
  'Visas tavas izveidotās kampaņas.': 'All of your created campaigns.',
  'Ielādē…': 'Loading…',
  'Veēl nav publicētu kampaņu.': 'No published campaigns yet.',
  'Klipotāji, kas veido saturu taviem zīmoliem.': 'Creators who create content for your brands.',
  'Klipotājs': 'Clipper',
  'Klipi': 'Clips',
  'Apstiprināti': 'Approved',
  'Profils': 'Profile',
  'Kopējie ieņēmumi': 'Total earnings',
  'Iesniegtie klipi': 'Submitted clips',
  'Ģenerētie skatījumi': 'Generated views',
  'Veēl neviens klipotājs nav iesniedzis klipu tavām kampaņām.': 'No clipper has submitted a clip to your campaigns yet.',
  'Viss pārbaudīts!': 'Everything has been checked!',
  'Nav neviena klipa, kas gaidītu vadlīniju apstiprinājumu.': 'There are no clips awaiting approval of the guidelines.',
  'Budžeti, depozīti un izmaksu vēsture.': 'Budgets, deposits, and payment history.',
  'Konta atlikums': 'Account balance',
  'Kampaņu izmaksas': 'Campaign payouts',
  'Rezervētā summa': 'Reserved amount',
  'Pievienoti līdzekļi': 'Funds allocated',
  'Izmaksāts klipotājiem': 'Paid to the clippers',
  'Maksājumu vēsture': 'Payment history',
  'Visi': 'All',
  'Pievienoti': 'Added',
  'Rezervēti': 'Reserved',
  'Izmaksāti': 'Issued',
  'Atgriezti': 'Returned',
  'Izņemti': 'Withdrawn',
  'Maksas': 'Fees',
  'Nav darījumu.': 'No transactions.',
  'Datums': 'Date',
  'Tips': 'Type',
  'Piezīme': 'Note',
  'Summa': 'Amount',
  'Izmaksāts klipotājam': 'Paid to the clipper',
  'Rezervēts kampaņai': 'Reserved for the campaign',
  'Izveides maksa (1%)': 'Setup fee (1%)',
  'Izņemts uz kontu': 'Withdrawn to an account',
  'Izmaksas maksa': 'Payout fee',
  'Atgriezts': 'Returned',
  'Izmaksāt': 'Pay out',
  'Pievienot līdzekļus': 'Add funds',
  'Metode': 'Method',
  'Karte': 'Card',
  'Pārskaitījums': 'Transfer',
  'Bankas pārskaitījums': 'Bank transfer',
  'Izmaksāt līdzekļus': 'Cash out funds',
  'Pieejams izņemšanai': 'Available to cash out',
  'Visa summa': 'Total amount',
  'Tūlītēja izmaksa': 'Instant payout',
  'Vārds': 'Name',
  'E-pasts': 'Email',
  'Parole': 'Password',
  'Jauna parole': 'New password',
  'IBAN (izmaksām)': 'IBAN (for payments)',
  'Saglabāt izmaiņas': 'Save changes',
  'Dzēst kontu': 'Delete account',
  'Konta un profila iestatījumi.': 'Account and profile settings.',
  'Konta dzēšana ir neatgriezeniska. Visi tavi dati tiks dzēsti.': 'Deleting your account is irreversible. All your data will be deleted.',
  'Tev ir aktīvas vai pauzētas kampaņas. Vispirms tās dzēs.': 'You have active or paused campaigns. Delete them first.',
  'Dzēst manu kontu': 'Delete my account',
  // campaign / clip states
  'Aktīva': 'Active',
  'Melnraksts': 'Draft',
  'Ierobežota': 'Limited',
  'Pauzēta': 'Paused',
  'Pabeigta': 'Finished',
  'Beigusies': 'Expired',
  'Dzēsta': 'Deleted',
  'Apstiprināts': 'Approved',
  'Noraidīts': 'Rejected',
  'Iesniegts': 'Submitted',
  'Tiek izsekots': 'Tracking',
  'Strīdā': 'Under dispute',
  'Krāpšanas pārbaudē': 'Fraud review',
  'Parastā izmaksa nonāk kontā 7 darba dienu laikā. Rezervēto summu nevar izņemt, kamēr kampaņas ir aktīvas.': 'Standard payments are credited to your account within 7 business days. You cannot withdraw the reserved amount while the campaigns are active.',
  '+1% maksa · citādi 7 darba dienu laikā': '+1% fee · otherwise, within 7 business days',
  'Pieejams izņemšanai': 'Available to cash out',
  'Apstrādā…': 'Processing…',
  'Demonstrācijas maksājums — līdzekļi tiek pievienoti tavam platformas atlikumam.': 'Demo payment — funds are added to your platform balance.',
  'Lai izveidotu kampaņas un pievienotu līdzekļus, vispirms verificē savu e-pastu un tālruni.': 'To create campaigns and add funds, first verify your email and phone number.',
  'E-pasts nav verificēts.': 'Email not verified.',
  'Tālrunis nav verificēts.': 'Phone not verified.',
  'Vispirms verificē e-pastu.': 'First verify your email.',
  'Vispirms verificē e-pastu un tālruni.': 'First verify your email and phone.',
  'Lai pievienotu līdzekļus, vispirms verificē savu e-pastu.': 'To add funds, first verify your email.',
  'Lai pievienotu līdzekļus, vispirms verificē savu e-pastu un tālruni.': 'To add funds, first verify your email and phone number.',
  'Lai iesniegtu klipus, vispirms verificē savu e-pastu un tālruni.': 'To submit clips, first verify your email and phone number.',
  'Vispirms verificē savu kontu': 'First verify your account',
  'Lai izveidotu kampaņas un pievienotu līdzekļus, verificē savu e-pastu un tālruni iestatījumos.': 'To create campaigns and add funds, verify your email and phone in settings.',
  'Nav verificēts': 'Not verified',
  'Uz iestatījumiem': 'Go to settings',
  'Vispirms verificē savu e-pastu un tālruni Iestatījumos, lai iesniegtu klipus.': 'First verify your email and phone in Settings to submit clips.',
  'E-pasts veiksmīgi verificēts.': 'Email successfully verified.',
  'Ievadi 6 ciparu kodu, kas nosūtīts uz tavu e-pastu.': 'Enter the 6-digit code sent to your email.',
  'klipi gaida vadlīniju apstiprinājumu': 'clips are awaiting approval of the guidelines',
  'Līdzekļi ir pievienoti tavam kontam.': 'Funds have been added to your account.',
  'Izmaksas pieprasījums ir pieņemts.': 'Your payout request has been accepted.',
  'Aktīvie klipi': 'Active clips',
  'Kontā ir negatīvs atlikums. Vispirms to nokārto.': 'Your account has a negative balance. Settle it first.',
  'Kontā vēl ir līdzekļi': 'Your account still has funds',
  'Izņem tos pirms konta dzēšanas.': 'Withdraw them before deleting your account.',
  'Iemaksāt': 'Deposit',
  'Mobilais tālrunis': 'Mobile phone',
  'Tālruņa numurs': 'Phone number',
  'Verificēt': 'Verify',
  'Nosūtīts': 'Sent',
  'Verifikācijas kods nosūtīts uz': 'Verification code sent to',
  'TikTok konta verifikācija': 'TikTok account verification',
  'TikTok konts verificēts': 'TikTok account verified',
  'Verificē savu TikTok kontu, lai varētu iesniegt TikTok klipus.': 'Verify your TikTok account so you can submit TikTok clips.',
  'Verificēt TikTok kontu': 'Verify TikTok account',
  'Ģenerē…': 'Generating…',
  'Pievieno šo kodu savam TikTok profila aprakstam (bio). Vari saglabāt esošo tekstu — kodam tikai jāparādās aprakstā.': 'Add this code to your TikTok profile description (bio). You can keep your existing text — the code just needs to appear in the description.',
  'piem.': 'e.g.',
  '@tavs_tiktok': '@your_tiktok',
  'Pārbauda…': 'Checking…',
  'Ievadi savu TikTok lietotājvārdu.': 'Enter your TikTok username.',
  'Kods netika atrasts tavā TikTok aprakstā. Pārbaudi un mēģini vēlreiz.': 'The code was not found in your TikTok description. Check and try again.',
  'Neizdevās pārbaudīt TikTok profilu. Mēģini vēlreiz.': 'Could not verify the TikTok profile. Try again.',
  'Neizdevās. Mēģini vēlreiz.': 'Something went wrong. Try again.',
  'Lūdzu, verificē savu TikTok kontu Iestatījumos pirms TikTok klipu iesniegšanas.': 'Please verify your TikTok account in Settings before submitting TikTok clips.',
  'Lūdzu, verificē savu Instagram kontu Iestatījumos pirms Instagram klipu iesniegšanas.': 'Please verify your Instagram account in Settings before submitting Instagram clips.',
  'Ievadi savu Instagram lietotājvārdu.': 'Enter your Instagram username.',
  'Neizdevās nolasīt tavu Instagram aprakstu. Pārliecinies, ka profils ir publisks.': 'Could not read your Instagram bio. Make sure the profile is public.',
  'Noņemt verificēto kontu': 'Remove verified account',
  'Kods netika atrasts tavā Instagram aprakstā. Pārbaudi un mēģini vēlreiz.': 'The code was not found in your Instagram bio. Check it and try again.',
  'Neizdevās pārbaudīt Instagram profilu. Mēģini vēlreiz.': 'Could not verify your Instagram profile. Try again.',
  'Pievieno šo kodu savam Instagram profila aprakstam (bio). Vari saglabāt esošo tekstu — kodam tikai jāparādās aprakstā.': 'Add this code to your Instagram profile bio. You can keep your existing text — the code just needs to appear in the bio.',
  '@tavs_instagram': '@your_instagram',
  'Nepieciešams, lai konts būtu pilnībā darbotiesspējīgs.': 'Required for the account to be fully operational.',
  'Sociālo tīklu verifikācija': 'Social media verification',
  'Verificē savus kontus, lai varētu iesniegt klipus.': 'Verify your accounts so you can submit clips.',
  'Verificēts': 'Verified',
  'Klipu var iesniegt tikai 60 minūšu laikā pēc publicēšanas. Šis klips ir par vecu.': 'Clips can only be submitted within 60 minutes of publication. This clip is too old.',
  'Klipu var iesniegt tikai 60 minūšu laikā pēc tā publicēšanas.': 'Clips can only be submitted within 60 minutes of being published.',
  'Neizdevās noteikt klipa publicēšanas laiku. Mēģini vēlreiz.': 'Could not determine the clip’s publish time. Please try again.',
  'Neizdevās pārbaudīt klipa publicēšanas laiku. Mēģini vēlreiz.': 'Could not verify the clip’s publish time. Please try again.',
  'Pārbaudīt': 'Review',
  'Apstiprināt': 'Approve',
  'Šo klipu nevar atskaņot platformā.': 'This clip cannot be played inside the platform.',
  'Atvērt platformā': 'Open on the platform',
  'Atvērt klipu jaunā cilnē': 'Open the clip in a new tab',
  'Nosaukums': 'Name',
  'Zīmola nosaukums': 'Brand name',
  'Zīmola logo': 'Brand logo',
  'Profila attēls': 'Profile picture',
  'nav obligāti': 'optional',
  'Augšupielādēt': 'Upload',
  'Augšupielādē…': 'Uploading…',
  'Nomainīt': 'Change',
  'Noņemt': 'Remove',
  'JPG, PNG vai WebP · maks. 5 MB': 'JPG, PNG or WebP · max 5 MB',
  'Attēls ir par lielu. Maksimālais izmērs 5 MB.': 'The image is too large. Maximum size is 5 MB.',
  'Atļauti tikai attēli.': 'Only images are allowed.',
  'Neizdevās augšupielādēt attēlu.': 'Could not upload the image.',
  'Maksimums €200.': 'Maximum €200.',
  'Maksimālā izmaksa par klipu (nav obligāti)': 'Maximum payout per clip (optional)',
  'Klips beigs pelnīt, kad sasniegs': 'The clip will stop earning once it reaches',
  ', un tiks atzīmēts kā pabeigts.': ', and will be marked as completed.',
  'Atstāj tukšu, lai klipam nebūtu maksimālā izmaksas limita.': 'Leave blank so the clip has no maximum payout limit.',
  'Rediģēt kampaņu': 'Edit campaign',
  'Piemēra klipi': 'Example clips',
  'Ievadi TikTok, Instagram vai YouTube saiti.': 'Enter a TikTok, Instagram or YouTube link.',
  'Šī saite jau ir pievienota.': 'This link has already been added.',
  'Šie klipi tiks parādīti kampaņas lapā kā piemēri klipotājiem.': 'These clips will be shown on the campaign page as examples for clippers.',
  'Pievienot': 'Add',
  'Saglabā…': 'Saving…',
  'Neizdevās saglabāt. Mēģini vēlreiz.': 'Could not save. Please try again.',
  'Materiālu saite': 'Link to materials',
  'Vispirms pabeidz konta iestatīšanu': 'Finish setting up your account first',
  'Lai izveidotu kampaņas un pievienotu līdzekļus, verificē savu e-pastu un pievieno zīmola logo iestatījumos.': 'To create campaigns and add funds, verify your email and add a brand logo in settings.',
  'Lai izveidotu kampaņas un pievienotu līdzekļus, verificē savu e-pastu, tālruni un pievieno zīmola logo iestatījumos.': 'To create campaigns and add funds, verify your email, phone and add a brand logo in settings.',
  'Nav pievienots': 'Not added',
  'Atjaunot paroli': 'Reset password',
  'Ievadi savu e-pastu, un mēs nosūtīsim 6 ciparu kodu paroles atjaunošanai.': 'Enter your email and we will send a 6-digit code to reset your password.',
  'Ievadi savu e-pastu.': 'Enter your email.',
  'Nosūtīt kodu': 'Send code',
  'Nosūtīt kodu vēlreiz': 'Send the code again',
  'Ja konts eksistē, kods ir nosūtīts uz': 'If the account exists, a code has been sent to',
  'Kods derīgs 30 minūtes.': 'The code is valid for 30 minutes.',
  'Kods': 'Code',
  'Jaunā parole': 'New password',
  'Nomainīt paroli': 'Change password',
  'Parole nomainīta!': 'Password changed!',
  'Tagad vari pieslēgties ar jauno paroli.': 'You can now log in with your new password.',
  'Ievadi 6 ciparu kodu.': 'Enter the 6-digit code.',
  'Parolei jābūt vismaz 6 simbolus garai.': 'The password must be at least 6 characters long.',
  'Sūta…': 'Sending…',
  'Lai iesniegtu klipus, vispirms verificē savu e-pastu.': 'To submit clips, verify your email first.',
  'Vispirms verificē savu e-pastu Iestatījumos, lai iesniegtu klipus.': 'Verify your email in Settings first to submit clips.',
  'Atcelt verifikāciju': 'Cancel verification',
  'Nosūtīt jaunu kodu': 'Send a new code',
  'Jaunā parole nedrīkst būt tāda pati kā iepriekšējā.': 'The new password must be different from your previous one.',
  'Jauns kods nosūtīts. Pārbaudi savu e-pastu.': 'A new code has been sent. Check your email.',
  'Kods nosūtīts vēlreiz. Pārbaudi savu e-pastu.': 'The code has been resent. Check your email.',
  'Vispirms pieprasi kodu.': 'Request a code first.',
  'Pārāk daudz mēģinājumu. Mēģini vēlāk.': 'Too many attempts. Try again later.',
  'Šis e-pasts nav reģistrēts.': 'This email address is not registered.',
  'Nosūtīt atkārtoti': 'Resend code',
  'Kods ir beidzies. Pieprasi jaunu kodu.': 'The code has expired. Request a new one.',
  'Saglabāt kā melnrakstu': 'Save as draft',
  '(maks. 3 faili, 20 MB katrs)': '(max 3 files, 20 MB each)',
  'Maksimums 3 faili.': 'Maximum 3 files.',
  'Fails ir par lielu. Maksimālais izmērs 20 MB.': 'The file is too large. Maximum size is 20 MB.',
  'Neizdevās augšupielādēt failu.': 'Could not upload the file.',
  'Augšupielādē…': 'Uploading…',
  'Pievieno līdzekļus sadaļā Maksājumi.': 'Add funds under Payments.',
  // ---- brand campaign actions ----
  'Papildu līdzekļi tiek rezervēti šai kampaņai (+1% maksa) un tā atkal tiek atvērta klipotājiem. Pieejams kontā:': 'Extra funds are reserved for this campaign (+1% fee) and it reopens to clippers. Available in account:',
  'Summa': 'Amount',
  'Budžets': 'Budget',
  'Kopā no konta': 'Total from account',
  'Pievienot': 'Add',
  'Apstrādā…': 'Processing…',
  'Palielināt budžetu': 'Increase the budget',
  'Kampaņa dzēsta.': 'Campaign deleted.',
  'Kampaņu vēl nevar dzēst': 'Campaign can\u2019t be deleted yet',
  'Pēc tam kampaņu varēs dzēst.': 'After that the campaign can be deleted.',
  'Kampaņa': 'Campaign',
  'tiks neatgriezeniski dzēsta no platformas. Neizlietotais budžets': 'will be permanently deleted from the platform. The unused budget',
  'tiks atgriezts tavā Klipzy kontā.': 'will be returned to your Klipzy account.',
  'Dzēš…': 'Deleting…',
  'Rediģēt melnrakstu': 'Edit draft',
  'Rediģēt kampaņu': 'Edit campaign',
  'Cena par 1 000 skatījumiem': 'Price for 1 000 views',
  'Maks. par klipu': 'Max per clip',
  'Minimālais skatījumu slieksnis izmaksai': 'Minimum view threshold for payout',
  'Dzēst kampaņu?': 'Delete campaign?',
  'Dzēst kampaņu': 'Delete campaign',
  'Melnraksts saglabāts.': 'Draft saved.',
  'Melnraksts dzēsts.': 'Draft deleted.',
  'Dzēst melnrakstu': 'Delete draft',
  'Vari saglabāt ne vairāk kā 5 melnrakstus.': 'You can save at most 5 drafts.',
  'skatījumi': 'views',
  'Izmaksas slieksnis:': 'Payout threshold:',
  'skatījumi pirms pirmās izmaksas.': 'views before the first payout.',
  'Atvērt Reel jaunā cilnē': 'Open the Reel in a new tab',
  'Instagram neļauj atskaņot Reels iegultā skatā.': 'Instagram does not allow Reels to play in an embedded view.',
  'TikTok tiešraides nevar iesniegt — tikai video.': 'TikTok live streams cannot be submitted — videos only.',
  'YouTube tiešraides nevar iesniegt — tikai video.': 'YouTube live streams cannot be submitted — videos only.',
  'Saite neatbilst izvēlētajai platformai. Iesniedz {p} video saiti.': 'The link does not match the selected platform. Submit a {p} video link.',
  'Instagram klipiem izmanto Reel saiti (instagram.com/reel/...).': 'For Instagram clips, use a Reel link (instagram.com/reel/...).',
  'Šī platforma drīzumā būs pieejama verifikācijai.': 'This platform will be available for verification soon.',
  'Apstiprināt kodu': 'Confirm code',
  'Tālrunis veiksmīgi verificēts.': 'Phone successfully verified.',
  'Ievadi 4 ciparu kodu, kas nosūtīts uz': 'Enter the 4-digit code sent to',
  // ── Create campaign ──
  'Izveidot kampaņu': 'Create a campaign',
  'Iestati kampaņu — klipotāji to redzēs tirgū.': 'Set up a campaign — clippers will see it on the catalog.',
  'Pamatinformācija': 'Basic information',
  'Cena & budžets': 'Price & budget',
  'Vadlīnijas': 'Guidelines',
  'Pārskats': 'Summary',
  'Kampaņas nosaukums': 'Campaign name',
  'piem. Rīga Energy — Vasara 2026': 'e.g., Riga Energy — Summer 2026',
  'Niša': 'Niche',
  'Spēles': 'Games',
  'Sports': 'Sport',
  'Izklaide': 'Entertainment',
  'Tehnoloģijas': 'Technologies',
  'Pārtika': 'Food',
  'Finanses': 'Finance',
  'Apraksts': 'Description',
  'Ko tu sagaidi no klipotājiem? Apraksti zīmola toni, mērķi un vēlamo saturu…': "What do you expect from the clippers? Describe the brand's tone, goals, and desired content…",
  'Atcelt': 'Cancel',
  'Tālāk': 'Next',
  'Atpakaļ': 'Back',
  'Cena par 1 000 skatījumiem (€)': 'Price for 1 000 views (€)',
  'Kopējais budžets (€)': 'Total budget (€)',
  'Pieejams:': 'Available:',
  'Visu': 'All',
  'Budžets pārsniedz pieejamos līdzekļus.': 'The budget exceeds available funds.',
  'Budžets pārsniedz pieejamos līdzekļus. Pievieno līdzekļus sadaļā Maksājumi.': 'The budget exceeds available funds. Add funds in the Payments section.',
  'Ar šo budžetu tu vari iegūt līdz': 'With this budget, you can get up to',
  'skatījumiem': 'views',
  'aptuveni': 'approximately',
  'klipi': 'clips',
  'no dažādiem klipotājiem.': 'from various clippers.',
  'Minimālais skatījumu slieksnis izmaksai (nav obligāti)': 'Minimum view threshold for payment (optional)',
  'piem. 10000': 'e.g., 10 000',
  'Klipotājs saņem izmaksu, kad klips sasniedz': 'The clipper gets paid once the clip reaches',
  'skatījumus, un pēc tam par katriem nākamajiem skatījumiem. Maksimums 10 000.': 'views, and then for each subsequent view. Maximum 10 000.',
  'Atstāj tukšu, lai klipotāji saņemtu izmaksu jau no pirmajiem 1 000 skatījumiem. Maksimums 10 000.': 'Leave this blank so that clippers can earn revenue starting from the first 1 000 views. Maximum: 10 000.',
  'Atļautās platformas': 'Allowed platforms',
  'piem. Rādi produktu pirmajās 3 sekundēs': 'e.g. Show the product in the first 3 seconds',
  'piem. Neizmanto rupjus vārdus': 'e.g. Don\u2019t use profanity',
  'Pievienot vēl': 'Add another',
  "Ieteicams (do's)": "Recommended (do's)",
  "Izvairies (don'ts)": "Things to avoid (don'ts)",
  'Katrā rindā viena vadlīnija…': 'One guideline per line…',
  'Katrā rindā viena lieta, no kā izvairīties…': 'One thing to avoid per line…',
  'Sākuma datums': 'Start date',
  'Beigu datums': 'End date',
  '(maks. 30 dienas)': '(max 30 days)',
  'Kampaņa var ilgt ne vairāk kā 30 dienas.': 'A campaign can run for no more than 30 days.',
  'Materiāli / brand assets': 'Assets',
  'Velc failus šeit vai pārlūko': 'Drag and drop files here to browse',
  'Logo, produkta foto, vadlīnijas · PNG, PDF, ZIP': 'Logo, product photo, guidelines · PNG, PDF, ZIP',
  'Materiālu saite': 'Link to materials',
  'Jauna kampaņa': 'New campaign',
  'Cena / 1 000': 'Price / 1 000',
  'Budžets': 'Budget',
  'Min. slieksnis': 'Min. threshold',
  'Nav (no 1 000)': 'None (from 1 000)',
  'Platformas': 'Platforms',
  'Periods': 'Period',
  'Izveides maksa (1%)': 'Creation fee (1%)',
  'Kopā no konta': 'Total from the account',
  'Nav apraksta.': 'No description.',
  'Publicē…': 'Publishing…',
  'Publicēt kampaņu': 'Publish a campaign',
  // ── Brand campaign detail ──
  'Atjaunot skatījumus': 'Refresh views',
  'Pieprasīts': 'Requested',
  'Pauzēt': 'Pause',
  'Atsākt': 'Resume',
  'Mainīt cenu, budžetu, platformas un vadlīnijas.': 'Change price, budget, platforms and guidelines.',
  'Pievieno vairāk līdzekļu šai kampaņai no konta atlikuma.': 'Add more funds to this campaign from your account balance.',
  'Atsāc kampaņu, lai tā atkal būtu redzama klipotājiem.': 'Resume the campaign so it becomes visible to clippers again.',
  'Uz laiku aptur kampaņu — to redzēsi tikai tu.': 'Temporarily pause the campaign — only you will see it.',
  'Neatgriezeniski dzēš kampaņu — neizmantotais budžets tiek atgriezts kontā.': 'Permanently deletes the campaign — the unused budget is returned to your account.',
  'Skatījumu atjaunošana var aizņemt līdz 24 stundām.': 'It may take up to 24 hours for views to be updated.',
  'Dzēst': 'Delete',
  'Pagarināt (30 d.)': 'Extend (30 d.)',
  'Vispirms izmaksā visus validētos skatījumus': 'First pay out all validated views',
  'Vispirms pievieno līdzekļus un nokārto negatīvo atlikumu': 'First add funds and settle the negative balance',
  'Visas kampaņas': 'All campaigns',
  'Pārbaudīti skatījumi': 'Verified views',
  'Aktīvie klipi': 'Active clips',
  'Rezervēts (atlikums)': 'Reserved (remaining)',
  'Jāizmaksā klipotājiem': 'Pay the clippers',
  'Izmaksāts klipotājiem': 'Paid to the clippers',
  'Budžeta izlietojums': 'Budget expenditures',
  'Rezervēts': 'Reserved',
  'Apstrādē': 'Processing',
  'Izmaksāts': 'Paid',
  'Pieejams': 'Available',
  'Klipotāji šajā kampaņā': 'Clippers in this campaign',
  'Skatīt lapu': 'View page',
  'Šī kampaņa ir pauzēta — to redzi tikai tu. Atsāc, lai tā atkal būtu redzama klipotājiem.': 'This campaign is paused — only you can see it. Resume the campaign to make it visible to the clippers.',
  'validēti': 'validated',
  'Vēl nav validētu klipotāju šajā kampaņā.': 'There are no validated clippers in this campaign yet.',
  // ---- Google sign-up profile completion ----
  'Tikai viens solis': 'Just one step',
  'Ievadi sava zīmola nosaukumu.': 'Enter your brand name.',
  'Ievadi savu vārdu.': 'Enter your name.',
  'Zīmola nosaukums': 'Brand name',
  'Lūdzu, ievadi vārdu.': 'Please enter a name.',
  // ---- marketplace / campaigns page ----
  'Kampaņas': 'Campaigns',
  'Atrodi kampaņu, izveido klipu un pelni par skatījumiem.': 'Find a campaign, create a clip and earn for views.',
  'Meklēt zīmolu, produktu vai nišu…': 'Search for a brand, product or niche…',
  'Augstākā cena': 'Highest price',
  'Lielākais budžets': 'Largest budget',
  'Beidzas drīzāk': 'Ending soonest',
  'Dalīties ar kampaņu': 'Share campaign',
  'Saite nokopēta': 'Link copied',
  'Drīz beidzas': 'Ending soon',
  'Filtri': 'Filters',
  'Notīrīt': 'Clear',
  'Platforma': 'Platform',
  'Niša': 'Niche',
  'Min. cena / 1000': 'Min. price / 1000',
  'kampaņa': 'campaign',
  'kampaņas': 'campaigns',
  'Ielādē kampaņas…': 'Loading campaigns…',
  'Nav atrasta neviena kampaņa': 'No campaigns found',
  'Pamēģini mainīt filtrus vai meklēšanas vaicājumu.': 'Try changing the filters or search query.',
  'Kampaņa nav atrasta': 'Campaign not found',
  'Visas kampaņas': 'All campaigns',
  'Izmaksa': 'Payout',
  'par 1 000 skatījumiem': 'per 1,000 views',
  'Min. slieksnis': 'Min. threshold',
  'skatījumi izmaksai': 'views for payout',
  'no 1 000 skatījumiem': 'from 1,000 views',
  'Atlikušais budžets': 'Remaining budget',
  'no': 'of',
  'Termiņš': 'Deadline',
  'd.': 'd',
  'Izmaksa sākas, kad klips sasniedz': 'Payout starts when a clip reaches',
  'skatījumus — pēc tam tiek izmaksāts par katriem nākamajiem skatījumiem.': 'views — after that you are paid for every additional view.',
  'Apraksts': 'Description',
  'Vadlīnijas': 'Guidelines',
  'Ieteicams': 'Recommended',
  'Izvairies': 'Avoid',
  'Seko zīmola vadlīnijām.': 'Follow the brand guidelines.',
  'Neizmanto neatļautu saturu.': 'Do not use disallowed content.',
  'Atļautās platformas': 'Allowed platforms',
  'Resursi / Materiāli': 'Resources / Assets',
  'Materiālu saite': 'Assets link',
  'Atvērt': 'Open',
  'Lejupielādēt': 'Download',
  'Lejupielādēt rēķinu': 'Download invoice',
  'Faili': 'Files',
  'fails': 'file',
  'faili': 'files',
  'Saites': 'Links',
  'saite': 'link',
  'saites': 'links',
  'Materiāls': 'Material',
  'Zīmols nav pievienojis materiālus.': 'The brand has not added any assets.',
  'Piemēra klipi': 'Example clips',
  'Pievienoties kampaņai': 'Join campaign',
  'Par zīmolu': 'About the brand',
  'Aktīvi klipotāji': 'Active clippers',
  'Iesniegt klipu': 'Submit a clip',
  'Piemēra ieņēmumi': 'Example earnings',
  'Maksimālais, ko var nopelnīt ar vienu klipu': 'The maximum you can earn from one clip',
  'skatījumi': 'views',
  'Ja tavs klips sasniedz': 'If your clip reaches',
  'skatījumus': 'views',
  'tu nopelni': 'you earn',
  'Spēles': 'Gaming',
  'Sports': 'Sports',
  'Izklaide': 'Entertainment',
  'Tehnoloģijas': 'Technology',
  'Pārtika': 'Food',
  'Finanses': 'Finance',
  // ---- payments / audit ----
  'Tavu izmaksu vēsture un statuss.': 'Your payout history and status.',
  'Vēl nav izmaksu.': 'No payouts yet.',
  'Audita žurnāls': 'Audit log',
  'Sistēmas notikumu vēsture — nemaināma.': 'History of system events — immutable.',
  'Krāpšana': 'Fraud',
  'Strīdi': 'Disputes',
  'Notikumi': 'Events',
  'Nav ierakstu.': 'No entries.',
  'Šis klips jau ir iesniegts platformā. Vienu un to pašu saturu nevar iesniegt vairākas reizes vai no vairākiem kontiem.': 'This clip is already submitted on the platform. The same content cannot be submitted multiple times or from multiple accounts.',
  // ---- notifications ----
  'Paziņojumi': 'Notifications',
  'Nav jaunu paziņojumu.': 'No new notifications.',
  'Atzīmēt kā izlasītu': 'Mark as read',
  // ---- clipper dashboard ----
  'Vispirms verificē šo kontu Iestatījumos.': 'Verify this account in Settings first.',
  'Platforma nav verificēta. Verificē to Iestatījumos.': 'Platform not verified. Verify it in Settings.',
  'Verificē kādu no šīs kampaņas platformām, lai pievienotos.': 'Verify one of this campaign\u2019s platforms to join.',
  'Tīkls': 'Network',
  'Pārliecinies, ka tīkls atbilst tavam makam — nepareizs tīkls nozīmē zaudētus līdzekļus.': 'Make sure the network matches your wallet — the wrong network means lost funds.',
  'Panelis': 'Dashboard',
  'Manas kampaņas': 'My campaigns',
  'Mani klipi': 'My clips',
  'Ieņēmumi': 'Earnings',
  'Mācības': 'Learning',
  'Sveiks': 'Hi',
  'Lūk, kā veicas taviem klipiem.': "Here's how your clips are doing.",
  'Pārlūkot kampaņas': 'Browse campaigns',
  'Iesniegt jaunu klipu': 'Submit a new clip',
  'Kopējie skatījumi': 'Total views',
  'Nopelnīts (kopā)': 'Earned (total)',
  'Gaida apstiprinājumu': 'Awaiting approval',
  'Aktīvās kampaņas': 'Active campaigns',
  'Visas': 'All',
  'Ielādē…': 'Loading…',
  'Veēl neesi pievienojies kampaņām.': "You haven't joined any campaigns yet.",
  'klipi': 'clips',
  'Nākamā izmaksa': 'Next payout',
  'Pieejamais atlikums': 'Available balance',
  'Izmaksas tiek veiktas automātiski, kad sasniegts €10 slieksnis. Nauda kontā nonāk vidēji 1–2 darba dienu laikā.': 'Payouts are made automatically once the €10 threshold is reached. Money arrives in your account on average within 1–2 business days.',
  'Pēdējie iesniegtie klipi': 'Recently submitted clips',
  'Visi klipi': 'All clips',
  'Vēl nav iesniegtu klipu.': 'No submitted clips yet.',
  'Klips': 'Clip',
  'Statuss': 'Status',
  'Apstrādē': 'Processing',
  'Izmaksāts': 'Paid',
  'Iesniegt strīdu': 'Submit a dispute',
  'Dzēst klipu': 'Delete clip',
  'Apturēta uz laiku': 'Paused',
  'Pārtraukta': 'Stopped',
  'Aktīva': 'Active',
  'Kampaņas, kurām esi pievienojies.': "Campaigns you've joined.",
  'Pievienoties kampaņai': 'Join a campaign',
  'Veēl neesi pievienojies nevienai kampaņai.': "You haven't joined any campaign yet.",
  'skatījumi': 'views',
  'Kampaņa vairs nav pieejama': 'Campaign is no longer available',
  'Zīmols ir pārtraucis šo kampaņu.': 'The brand has stopped this campaign.',
  'Zīmols šo kampaņu uz laiku ir apturējis.': 'The brand has paused this campaign.',
  'Nopelnīts': 'Earned',
  'Klipi': 'Clips',
  'Noņemt no saraksta': 'Remove from list',
  'Detaļas': 'Details',
  'Iesniegt klipu': 'Submit a clip',
  'Atcelt dalību': 'Cancel participation',
  'Noņemt kampaņu?': 'Remove campaign?',
  'Atcelt dalību?': 'Cancel participation?',
  'Kampaņa tiks noņemta no tava saraksta. Tavi iesniegtie klipi šai kampaņai arī tiks dzēsti.': 'The campaign will be removed from your list. Your submitted clips for it will also be deleted.',
  'Tava dalība kampaņā': 'Your participation in campaign',
  'tiks atcelta un visi tavi iesniegtie klipi šai kampaņai tiks noņemti no zīmola pārbaudes.': 'will be cancelled and all your submitted clips for it will be removed from brand review.',
  'Noņemt': 'Remove',
  'iesniegti klipi': 'submitted clips',
  'Strīds par klipu': 'The dispute for the clip',
  'tiks nosūtīts Klipzy atbalstam. Skatījumi paliek iesaldēti līdz administrācijas lēmumam.': "will be sent to Klipzy support. Views stay frozen until admin decides.",
  'Strīda iemesls': 'Dispute reason',
  'Paskaidro, kāpēc nepiekrīti lēmumam…': "Explain why you disagree with the decision…",
  'Pierādījumi / saite (nav obligāti)': 'Evidence / link (optional)',
  'Sūta…': 'Sending…',
  'Nosūtīt strīdu': 'Send dispute',
  'Dzēst klipu?': 'Delete clip?',
  'Šis klips': 'This clip',
  'ir apstiprināts. Dzēšot to, tas tiks noņemts un vairs nepelnīs.': 'is approved. Deleting it removes it and it will no longer earn.',
  'Klips': 'Clip',
  'tiks dzēsts un vairs nerādīsies zīmola pārbaudē.': 'will be deleted and no longer shown in brand review.',
  'Tavi nopelnītie līdzekļi.': 'Your earnings.',
  'Tavi nopelnītie līdzekļi un izmaksu vēsture.': 'Your earnings and payout history.',
  'Nopelnīts (kopā)': 'Earned (total)',
  'Nopelnīts (validēts)': 'Earned (verified)',
  'Pieejams izmaksai': 'Available to withdraw',
  'Validētie ieņēmumi': 'Verified earnings',
  'Veēl nav validētu ieņēmumu. Skatījumi tiek izmaksāti pēc tam, kad zīmols tos apstiprina.': 'No verified earnings yet. Views are paid out after the brand approves them.',
  'Datums': 'Date',
  // ---- clipper submit clip ----
  'Klips iesniegts pārbaudei': 'Clip submitted for review',
  'Skatījumi tiks izsekoti automātiski. Tiklīdz zīmols apstiprinās klipu, tas parādīsies tavā panelī.': 'Views will be tracked automatically. Once the brand approves the clip, it appears in your dashboard.',
  'Platforma': 'Platform',
  'Saite': 'Link',
  'Iesniegt vēl vienu': 'Submit another',
  'Skatīt manus klipus': 'View my clips',
  'Pievieno sava klipa saiti — pārējo izdarīsim mēs.': "Add your clip link — we'll handle the rest.",
  'Nav pievienotu kampaņu': 'No joined campaigns',
  'Izvēlies kampaņu…': 'Choose a campaign…',
  'Vispirms pievienojies kampaņai': 'First join a campaign in the',
  'tirgū': 'catalog',
  'Klipa saite (URL)': 'Clip link (URL)',
  'Lūdzu, ievadi derīgu klipa saiti.': 'Please enter a valid clip link.',
  'Piezīmes': 'Notes',
  'neobligāti': 'optional',
  'Kaut kas, ko zīmolam vajadzētu zināt par šo klipu…': 'Anything the brand should know about this clip…',
  'Skatījumi tiks izsekoti automātiski no publiskās saites.': 'Views are tracked automatically from the public link.',
  'Šī kampaņa vairs nepieņem jaunus klipus (budžets ir zems vai iztērēts).': 'This campaign no longer accepts new clips (budget is low or spent).',
  'Iesniedz…': 'Submitting…',
  'Neizdevās iesniegt klipu. Mēģini vēlreiz.': 'Could not submit the clip. Please try again.',
  'Šis klips jau ir iesniegts šai kampaņai. Vienu un to pašu saturu nevar iesniegt divreiz.': 'This clip is already submitted to this campaign. The same content cannot be submitted twice.',
  'Tu pievienojies kampaņai': 'You joined the campaign',
  'Izveido klipu pēc vadlīnijām un iesniedz to pārbaudei.': 'Create a clip per the guidelines and submit it for review.',
  // ---- fees (Komisija) ----
  'Pieprasīt izmaksu': 'Request payout',
  'Pieejams izmaksai': 'Available to withdraw',
  'Izmaksas metode': 'Payout method',
  'maka adrese': 'wallet address',
  'maks': 'wallet',
  'Saglabātā adrese': 'Saved address',
  'Ievadīt jaunu adresi': 'Enter a new address',
  'Dzēst saglabāto adresi': 'Delete saved address',
  'Saglabāt šo adresi turpmākai lietošanai': 'Save this address for future use',
  'Maka nosaukums (piem. Galvenais)': 'Wallet name (e.g. Main)',
  'adrese': 'address',
  'Ievadi kripto maka adresi.': 'Enter a crypto wallet address.',
  'Neizdevās izpildīt izmaksu. Pārbaudi adresi un mēģini vēlreiz.': 'Payout failed. Check the address and try again.',
  'Summa': 'Amount',
  'Saņemsi': "You'll receive",
  'Izmaksāt': 'Withdraw',
  'Apstrādā…': 'Processing…',
  'Tūlītēja izmaksa nonāk kontā dažu minūšu laikā.': 'Instant payout arrives within a few minutes.',
  'Parastā izmaksa nonāk 7 darba dienu laikā.': 'Standard payout arrives within 7 business days.',
  'Minimālā izmaksa €10.': 'Minimum payout €10.',
  '+1% maksa · citādi 7 darba dienu laikā': '+1% fee · otherwise within 7 business days',
  'Izmaiņas saglabātas': 'Changes saved',
  'Saglabā…': 'Saving…',
  'Neizdevās saglabāt izmaiņas. Mēģini vēlreiz.': 'Could not save changes. Please try again.',
  'Komisijas': 'Fees',
  // ---- NOWPayments deposits ----
  'Minimālā iemaksa ir €10.': 'Minimum deposit is €10.',
  'Neizdevās izveidot maksājumu. Mēģini vēlreiz.': 'Could not create the payment. Please try again.',
  'Maksājums saņemts — līdzekļi pievienoti.': 'Payment received — funds added.',
  'Gaidām maksājuma apstiprinājumu… Šo logu var atstāt atvērtu.': 'Waiting for payment confirmation… you can leave this window open.',
  'Atvērt maksājuma lapu vēlreiz': 'Open the payment page again',
  'Kad maksājums būs apstiprināts, atlikums tiks atjaunināts automātiski.': 'Once the payment is confirmed, your balance updates automatically.',
  'Turpināt uz maksājumu': 'Continue to payment',
  'Maksājumu droši apstrādā NOWPayments. Atlikums tiek ieskaitīts eiro.': 'Payments are securely processed by NOWPayments. Your balance is credited in euros.',
  'Komisija': 'Fee',
  'Komisija (1%)': 'Fee (1%)',
  'Izveides komisija (1%)': 'Setup fee (1%)',
  'Izmaksas komisija': 'Payout fee',
  // ---- admin dashboard ----
  'Kopēt summu': 'Copy amount',
  'Kopēt adresi': 'Copy address',
  'Nokopēts': 'Copied',
  'Kopēt': 'Copy',
  'Maksājumi': 'Payments',
  'Skatīt un apstrādāt izmaksas': 'View and process payouts',
  'Izslēgta': 'Disabled',
  'Atļaujas': 'Permissions',
  'Lietotāju pārvaldība': 'User management',
  'Skatīt, apstiprināt un dzēst kontus': 'View, approve and delete accounts',
  'Kampaņu pārraudzība': 'Campaign oversight',
  'Pārraudzīt visas platformas kampaņas': 'Oversee all platform campaigns',
  'Pilna piekļuve': 'Full access',
  'Piekļuve visiem administrācijas rīkiem': 'Access to all admin tools',
  'Atļaujas nosaka sistēma — tās nevar mainīt.': 'Permissions are set by the system — they cannot be changed.',
  'Noņemt profila bildi': 'Remove profile photo',
  'Ziņas': 'Messages',
  'Ziņas no kontaktu formas.': 'Messages from the contact form.',
  'Nav ziņu.': 'No messages.',
  '(bez tēmas)': '(no subject)',
  'Noņem…': 'Removing…',
  'Lietotāji': 'Users',
  'Zīmols': 'Brand',
  'Administrācijas pārskats': 'Admin overview',
  'Platformas darbības kopskats.': 'Overview of platform activity.',
  'Zīmolu pieteikumi': 'Brand requests',
  'Skatījumu atjaunošanas pieprasījumi': 'View refresh requests',
  'Kampaņa': 'Campaign',
  'Strīdi': 'Disputes',
  'Iesaldēti skatījumi gaida lēmumu': 'Frozen views awaiting a decision',
  'skat.': 'views',
  'iesaldēts': 'frozen',
  'Izskatīt': 'Review',
  'Pieprasīt info': 'Request info',
  'Krāpšanas pārbaude': 'Fraud review',
  'Uzturēt noraidījumu': 'Uphold rejection',
  'Atcelt noraidījumu (izmaksāt)': 'Reverse rejection (pay out)',
  'Iemesls:': 'Reason:',
  'Pierādījumi:': 'Evidence:',
  'Atvērts': 'Open',
  'Tiek izskatīts': 'Under review',
  'Gaida informāciju': 'Awaiting information',
  'Par labu klipotājam': 'In favor of clipper',
  'Par labu zīmolam': 'In favor of brand',
  'Slēgts': 'Closed',
  'Lietotāji kopā': 'Total users',
  'Apgrozījums': 'Revenue',
  'Platformas aktivitāte': 'Platform activity',
  'Skatījumi / dienā': 'Views / day',
  'Klipi / dienā': 'Clips / day',
  'Jaunākie lietotāji': 'Newest users',
  'Visi': 'All',
  'Ielādē…': 'Loading…',
  'Nav lietotāju.': 'No users.',
  'Top kampaņas': 'Top campaigns',
  'Visas': 'All',
  'Nav kampaņu.': 'No campaigns.',
  'Skatījumi ir atjaunoti': 'Views have been refreshed',
  'klipi': 'clips',
  'Atjaunoti': 'Refreshed',
  'klipu skatījumi.': 'clip views.',
  'Izvēlies platformas, kurām atjaunot visu aktīvo iesniegto klipu skatījumus.': 'Choose which platforms to refresh views for across all active submitted clips.',
  'Atjauno…': 'Refreshing…',
  'Visi reģistrētie klipotāji, zīmoli un administratori.': 'All registered clippers, brands and administrators.',
  'Filtrēt': 'Filter',
  'Administratori': 'Administrators',
  'Kārtot': 'Sort',
  'Reģistrēts': 'Registered',
  'jaunākie': 'newest',
  'vecākie': 'oldest',
  'Nav lietotāju ar izvēlētajiem filtriem.': 'No users match the selected filters.',
  'Visas platformas kampaņas.': 'All platform campaigns.',
  'Kārtot pēc': 'Sort by',
  'Augstākie': 'Highest',
  'Zemākie': 'Lowest',
  'Vēl nav publicētu kampaņu.': 'No published campaigns yet.',
  'Klipotājs': 'Clipper',
  'Administrators': 'Administrator',
  'Lietotājs': 'User',
  'Loma': 'Role',
  'gaida': 'pending',
  'Darbības': 'Actions',
  'Aizvērt': 'Close',
  'Zīmola dati': 'Brand details',
  'Klipotāja dati': 'Clipper details',
  'Pēdējā kampaņa': 'Last campaign',
  'Kopā izmaksāts': 'Total paid',
  'Aktīvās': 'Active',
  'Pabeigtās': 'Finished',
  'Nav aktīvu kampaņu.': 'No active campaigns.',
  'Nav pabeigtu kampaņu.': 'No finished campaigns.',
  'Apstiprināt': 'Approve',
  'Konts apstiprināts': 'Account approved',
  'Pieprasīt papildu informāciju': 'Request additional information',
  'Pieprasījums nosūtīts': 'Request sent to',
  'zīmolam': 'brand',
  'klipotājam': 'clipper',
  'Ziņa': 'Message to',
  'Atģādinājums': 'Reminder',
  'Jādara tagad': 'Do now',
  'Sūta…': 'Sending…',
  'Nosūtīt': 'Send',
  'Dzēst zīmola kontu': 'Delete brand account',
  'Dzēst klipotāja kontu': 'Delete clipper account',
  'Dzēst kontu?': 'Delete account?',
  'Ievadi savu paroli, lai apstiprinātu. Šī darbība ir neatgriezeniska.': 'Enter your password to confirm. This action is irreversible.',
  'Ievadi paroli.': 'Enter your password.',
  'Nepareiza parole.': 'Wrong password.',
  'Neizdevās dzēst kontu. Mēģini vēlreiz.': 'Could not delete the account. Please try again.',
  'Dzēš…': 'Deleting…',
  'Dzēst kontu': 'Delete account',
  'Dzēst šo kontu?': 'Delete this account?',
  'Šo darbību nevar atsaukt.': 'This action cannot be undone.',
  'Apstiprināt dzēšanu': 'Confirm deletion',
  'Izmaksas': 'Payouts',
  'Klipotāju un zīmolu izmaksas pieprasījumi, kas jāapstrādā manuāli.': 'Clipper and brand payout requests to process manually.',
  'Neapstrādātas': 'Pending',
  'Nav izmaksas pieprasījumu.': 'No payout requests.',
  'Summa': 'Amount',
  'Metode': 'Method',
  'tūlītēja': 'instant',
  'dienas atlikušas': 'days left',
  'Atzīmēt kā izmaksātu': 'Mark as paid',
  'Apstrādē': 'Processing',
  'Saņemts': 'Received',
  'Procesā': 'In progress',
  'Atteikts': 'Declined',
  'Atteikt': 'Decline',
  'Atteikt izmaksu': 'Decline payout',
  'Atteikuma iemesls (redzams': 'Decline reason (visible to the',
  'Atteikt un atgriezt līdzekļus': 'Decline and return funds',
  'Neizdošanās iemesls:': 'Failure reason:',
  'Neizdevās': 'Failed',
  'Neizdošanās iemesls (redzams klipotājam):': 'Failure reason (visible to the clipper):',
  'Saglabā…': 'Saving…',
};
const tr = (s, lang) => (lang === 'en' ? (TR_EN[s] || s) : s);

/* Account verification state (email + phone). Persisted per-uid in
   localStorage as a visual stand-in until the real backend is wired.
   accountVerified(uid) → both done; setVerifyFlag broadcasts a change. */
function verifyKey(uid) { return 'klipzy_verify_' + (uid || 'anon'); }
function getVerify(uid) {
  try { return JSON.parse(localStorage.getItem(verifyKey(uid)) || '{}') || {}; } catch (_) { return {}; }
}
function setVerifyFlag(uid, field, val) {
  const cur = getVerify(uid);
  cur[field] = val;
  try { localStorage.setItem(verifyKey(uid), JSON.stringify(cur)); window.dispatchEvent(new CustomEvent('klipzy-verify', { detail: uid })); } catch (_) {}
}
function accountVerified(uid, profile, role) {
  const v = getVerify(uid);
  const emailOk = !!(v.email || (profile && profile.emailVerified));
  const phoneOk = !!(v.phone || (profile && profile.phoneVerified));
  // Brands must also upload a logo before they can run campaigns.
  const logoOk = role === 'brand' ? !!(profile && profile.photoURL) : true;
  const needsPhone = false; // phone verification not required for any role
  return { emailOk, phoneOk, logoOk, needsPhone, both: emailOk && logoOk };
}
/* Re-renders when this user's verification flags change. */
function useVerify(uid, profile, role) {
  const [, force] = React.useState(0);
  React.useEffect(() => {
    const on = (e) => { if (!e.detail || e.detail === uid) force((n) => n + 1); };
    window.addEventListener('klipzy-verify', on);
    return () => window.removeEventListener('klipzy-verify', on);
  }, [uid]);
  return accountVerified(uid, profile, role);
}

/* Shared dashboard language. Persists to the signed-in user's profile so the
   choice follows them across devices; localStorage is the offline fallback. */
function useLang() {
  const [lang, setLang] = React.useState(() => { try { return localStorage.getItem('klipzy_lang') || 'lv'; } catch (_) { return 'lv'; } });
  React.useEffect(() => {
    const on = (e) => setLang(e.detail || (localStorage.getItem('klipzy_lang') || 'lv'));
    window.addEventListener('klipzy-lang', on);
    // Adopt the profile language ONLY if the user hasn't made an explicit choice
    // (the homepage/switcher writes klipzy_lang). The switcher choice always wins.
    let alive = true;
    (async () => {
      try {
        if (localStorage.getItem('klipzy_lang')) return; // explicit choice exists — respect it
        const fb = window.KlipzyFirebase;
        const uid = fb && fb.auth && fb.auth.currentUser && fb.auth.currentUser.uid;
        if (!uid || !fb.getUserDoc) return;
        const p = await fb.getUserDoc(uid);
        const saved = p && p.lang;
        if (alive && saved) {
          try { localStorage.setItem('klipzy_lang', saved); window.dispatchEvent(new CustomEvent('klipzy-lang', { detail: saved })); } catch (_) {}
          setLang(saved);
        }
      } catch (_) {}
    })();
    return () => { alive = false; window.removeEventListener('klipzy-lang', on); };
  }, []);
  return lang;
}

/* Map a Firestore role to its dashboard route. */
function homeForRole(role) {
  if (role === 'brand') return 'brand';
  if (role === 'admin') return 'admin';
  return 'clipper';
}

/* Password input with a show/hide eye toggle on the right. */
function PasswordField({ value, onChange, onKeyDown, placeholder, label, autoComplete, id, required }) {
  const [show, setShow] = React.useState(false);
  const fid = id || 'pw-' + (autoComplete || 'field');
  return (
    <div className={'field' + (required ? ' required' : '')}>
      {label ? <label htmlFor={fid}>{label}</label> : null}
      <div style={{ position: 'relative' }}>
        <input
          className="input"
          id={fid}
          name={autoComplete === 'new-password' ? 'new-password' : 'password'}
          autoComplete={autoComplete || 'current-password'}
          type={show ? 'text' : 'password'}
          value={value}
          onChange={onChange}
          onKeyDown={onKeyDown}
          placeholder={placeholder}
          style={{ paddingRight: 44, width: '100%' }}
        />
        <button
          type="button"
          onClick={() => setShow((s) => !s)}
          aria-label={show ? 'Paslēpt paroli' : 'Rādīt paroli'}
          aria-pressed={show}
          style={{
            position: 'absolute', top: '50%', right: 6, transform: 'translateY(-50%)',
            width: 32, height: 32, border: 'none', background: 'transparent', cursor: 'pointer',
            display: 'grid', placeItems: 'center', color: 'var(--muted)', borderRadius: 7,
          }}
          onMouseEnter={(e) => { e.currentTarget.style.color = 'var(--text-2)'; }}
          onMouseLeave={(e) => { e.currentTarget.style.color = 'var(--muted)'; }}
        >
          <Icon d={show ? I.eyeOff : I.eye} size={18} />
        </button>
      </div>
    </div>
  );
}

function AuthLoading() {
  return (
    <div style={{ height: '100%', display: 'grid', placeItems: 'center', background: '#fff' }}>
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 16 }}>
        <div className="klipzy-spinner" />
        <span className="muted" style={{ fontSize: 14 }}>Notiek ielāde…</span>
      </div>
    </div>
  );
}

/* ---------- icons (stroke, 1.6) ---------- */
function Icon({ d, size = 18, fill = 'none', stroke = 'currentColor', sw = 1.7, style, children }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill} stroke={stroke}
      strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round" style={style} aria-hidden="true">
      {d ? <path d={d} /> : children}
    </svg>
  );
}
const I = {
  copy: 'M9 9h10a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1V10a1 1 0 0 1 1-1z M5 15H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v1',
  grid: 'M3 3h7v7H3zM14 3h7v7h-7zM14 14h7v7h-7zM3 14h7v7H3z',
  megaphone: 'M3 11v2a1 1 0 0 0 1 1h2l3.5 3.5V6.5L6 10H4a1 1 0 0 0-1 1z M14 6.5a5 5 0 0 1 0 11 M18 4a8 8 0 0 1 0 16',
  film: 'M4 4h16v16H4zM4 9h16M4 15h16M9 4v16M15 4v16',
  wallet: 'M3 7h15a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h11v3M17 13h.01',
  card: 'M3 6a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z M3 10h18 M7 15h4',
  book: 'M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2zM4 19V5M19 19v2',
  file: 'M6 3h8l4 4v14a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z M14 3v4h4 M8 13h8 M8 17h6',
  shield: 'M12 3l7 3v5c0 4.5-3 7.8-7 9-4-1.2-7-4.5-7-9V6z M9 12l2 2 4-4',
  gear: 'M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6z M19 12a7 7 0 0 0-.1-1l2-1.5-2-3.5-2.4 1a7 7 0 0 0-1.7-1l-.4-2.5h-4l-.4 2.5a7 7 0 0 0-1.7 1l-2.4-1-2 3.5 2 1.5a7 7 0 0 0 0 2l-2 1.5 2 3.5 2.4-1a7 7 0 0 0 1.7 1l.4 2.5h4l.4-2.5a7 7 0 0 0 1.7-1l2.4 1 2-3.5-2-1.5a7 7 0 0 0 .1-1z',
  users: 'M16 19v-2a3 3 0 0 0-3-3H5a3 3 0 0 0-3 3v2 M9 11a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7 M22 19v-2a3 3 0 0 0-2.2-2.9 M16 4.1a3.5 3.5 0 0 1 0 6.8',
  inbox: 'M3 12h5l2 3h4l2-3h5 M5 5h14a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2z',
  chart: 'M4 19V5M4 19h16M8 16v-4M12 16V8M16 16v-6M20 16v-9',
  search: 'M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16z M21 21l-4.3-4.3',
  arrowR: 'M5 12h14M13 6l6 6-6 6',
  arrowL: 'M19 12H5M11 18l-6-6 6-6',
  check: 'M5 12l4.5 4.5L19 7',
  x: 'M6 6l12 12M18 6L6 18',
  plus: 'M12 5v14M5 12h14',
  play: 'M7 5l11 7-11 7z',
  pause: 'M8 5v14M16 5v14',
  chevronR: 'M9 6l6 6-6 6',
  lock: 'M6 10V8a6 6 0 0 1 12 0v2 M5 10h14a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1z',
  bell: 'M18 8a6 6 0 1 0-12 0c0 7-3 8-3 8h18s-3-1-3-8 M13.7 21a2 2 0 0 1-3.4 0',
  alert: 'M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z M12 9v4 M12 17h.01',
  refresh: 'M3 12a9 9 0 0 1 15-6.7L21 8 M21 3v5h-5 M21 12a9 9 0 0 1-15 6.7L3 16 M3 21v-5h5',
  info: 'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18z M12 11v5 M12 8h.01',
  clock: 'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18z M12 7v5l3 2',
  upload: 'M12 16V4M7 9l5-5 5 5 M4 17v2a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-2',
  link: 'M9 15l6-6 M11 6l1-1a4 4 0 0 1 6 6l-1 1 M13 18l-1 1a4 4 0 0 1-6-6l1-1',
  trend: 'M3 17l6-6 4 4 8-8M21 7h-5M21 7v5',
  calendar: 'M4 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v13a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1zM4 9h16M8 3v4M16 3v4',
  download: 'M12 4v12M7 11l5 5 5-5 M4 20h16',
  spark: 'M12 5l1.8 5.2L19 12l-5.2 1.8L12 19l-1.8-5.2L5 12l5.2-1.8z',
  star: 'M12 3l2.6 5.6L21 9.3l-4.5 4.3L17.5 20 12 16.8 6.5 20l1-6.4L3 9.3l6.4-.7z',
  trophy: 'M8 4h8v4a4 4 0 0 1-8 0zM8 5H5v2a3 3 0 0 0 3 3M16 5h3v2a3 3 0 0 1-3 3M10 14h4M9 20h6M12 16v4',
  logout: 'M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4 M16 17l5-5-5-5 M21 12H9',
  chevR: 'M9 6l6 6-6 6',
  man: 'M12 11a3.4 3.4 0 1 0 0-6.8 3.4 3.4 0 0 0 0 6.8z M5.5 20v-.5a6.5 6.5 0 0 1 13 0v.5',
  woman: 'M12 10.6a3.2 3.2 0 1 0 0-6.4 3.2 3.2 0 0 0 0 6.4z M7 20l2-7.4a3 3 0 0 1 6 0L17 20z',
  eye: 'M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z',
  eyeOff: 'M3 3l18 18 M10.6 10.6a3 3 0 0 0 4.2 4.2 M9.4 5.2A9.4 9.4 0 0 1 12 5c6.5 0 10 7 10 7a17 17 0 0 1-3.2 4 M6.2 6.2A17 17 0 0 0 2 12s3.5 7 10 7a9.3 9.3 0 0 0 3.3-.6',
  dots: 'M12 6v.01 M12 12v.01 M12 18v.01',
  edit: 'M12 20h9 M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z',
  arrowUp: 'M12 19V5M6 11l6-6 6 6',
  arrowDown: 'M12 5v14M6 13l6 6 6-6',
  trash: 'M4 7h16 M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2 M6 7l1 13a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1l1-13',
  send: 'M22 2L11 13 M22 2l-7 20-4-9-9-4z',
  building: 'M3 21h18 M5 21V4a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v17 M9 7h2 M9 11h2 M9 15h2 M15 21V9h3a1 1 0 0 1 1 1v11',
  login: 'M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4 M10 17l5-5-5-5 M15 12H3',
  userPlus: 'M16 19v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2 M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8 M19 8v6 M22 11h-6',
  menu: 'M3 6h18 M3 12h18 M3 18h18',
};

/* ---------- Logo ---------- */
function Logo({ size = 22, onClick, light }) {
  // full logo SVG is 959x262 (≈ 3.66:1)
  const h = Math.round(size * 1.05);
  return (
    <div onClick={onClick} style={{ display: 'flex', alignItems: 'center', cursor: onClick ? 'pointer' : 'default', userSelect: 'none' }}>
      <img src="assets/klipzy-logo.svg" alt="Klipzy" style={{ height: h, width: 'auto', display: 'block', filter: light ? 'brightness(0) invert(1)' : 'none' }} />
    </div>
  );
}

/* ---------- gradient placeholder ---------- */
function GradTile({ grad, style, children, radius = 10 }) {
  return (
    <div className="tile" style={{
      background: `linear-gradient(135deg, ${grad[0]}, ${grad[1]})`,
      borderRadius: radius, ...style,
    }}>{children}</div>
  );
}
function BrandLogo({ initials, grad, size = 44, radius = 11, src }) {
  // A real uploaded logo takes precedence over the generated initials tile.
  if (src) {
    return <img src={src} alt="" style={{ width: size, height: size, borderRadius: radius, objectFit: 'cover', flex: 'none', display: 'block', border: '1px solid var(--border)' }} />;
  }
  return (
    <GradTile grad={grad} radius={radius} style={{
      width: size, height: size, flex: 'none', display: 'grid', placeItems: 'center',
      color: '#fff', fontWeight: 600, fontSize: size * .36, letterSpacing: '-0.02em'
    }}>{initials}</GradTile>
  );
}

/* ---------- pills / platforms ---------- */
function Platform({ name }) { return <span className="pill">{String(name || '').replace(/\s*reels?/i, '').replace(/\s*shorts?/i, '').trim() || name}</span>; }

/* ---------- status badge (clip statuses) ---------- */
const STATUS = {
  approved: { cls: 'badge-green', label: 'Apstiprināts' },
  pending: { cls: 'badge-amber', label: 'Gaida pārbaudi' },
  rejected: { cls: 'badge-red', label: 'Noraidīts' },
  active: { cls: 'badge-green', label: 'Aktīva' },
  draft: { cls: 'badge-gray', label: 'Melnraksts' },
  limited: { cls: 'badge-amber', label: 'Ierobežota' },
  paused: { cls: 'badge-amber', label: 'Pauzēta' },
  finished: { cls: 'badge-gray', label: 'Pabeigta' },
  expired: { cls: 'badge-gray', label: 'Beigusies' },
  deleted: { cls: 'badge-red', label: 'Dzēsta' },
  // clip lifecycle states
  submitted: { cls: 'badge-amber', label: 'Iesniegts' },
  tracking: { cls: 'badge-green', label: 'Tiek izsekots' },
  under_dispute: { cls: 'badge-amber', label: 'Strīdā' },
  fraud_review: { cls: 'badge-red', label: 'Krāpšanas pārbaudē' },
  closed: { cls: 'badge-gray', label: 'Slēgts' },
};
function StatusBadge({ status, lang }) {
  const s = STATUS[status] || STATUS.pending;
  const lg = lang || (() => { try { return localStorage.getItem('klipzy_lang') || 'lv'; } catch (_) { return 'lv'; } })();
  return <span className={'badge ' + s.cls}>{tr(s.label, lg)}</span>;
}

/* Derive a clip's explicit lifecycle state:
   Submitted | Approved | Rejected | Tracking | Under Dispute | Fraud Review | Closed.
   `camp` (optional) lets us mark clips Closed when their campaign has ended. */
function clipState(s, camp) {
  if (!s) return 'submitted';
  if (s.fraudReview) return 'fraud_review';
  if (s.disputed) return 'under_dispute';
  const review = s.reviewStatus || s.review || 'pending';
  if (review === 'rejected') return 'rejected';
  if (review === 'pending') return 'submitted';
  // approved:
  if (camp) { const cs = campaignState(camp); if (cs === 'finished' || cs === 'expired' || cs === 'deleted') return 'closed'; }
  if (s.campaignDeleted) return 'closed';
  return 'tracking';
}

/* Derive the explicit lifecycle state of a campaign from its stored fields:
   Draft | Active | Limited | Paused | Finished | Expired | Deleted. */
function campaignState(c) {
  if (!c) return 'active';
  if (c.status === 'deleted') return 'deleted';
  if (c.status === 'draft') return 'draft';
  if (c.status === 'paused') return 'paused';
  if (c.status === 'finished') return 'finished';
  const remaining = c.budgetRemaining != null ? c.budgetRemaining : (c.budget || 0) - (c.spent || 0);
  if (remaining <= 0 && (c.budget || 0) > 0) return 'finished';
  if (c.end && new Date(c.end).getTime() < Date.now()) return 'expired';
  const total = c.budgetTotal != null ? c.budgetTotal : c.budget || 0;
  if (total > 0 && remaining <= total * 0.1) return 'limited';
  return 'active';
}

/* ---------- notification banner (admin info requests) ----------
   Rendered directly under a dashboard heading. severity: 'critical' → red
   (must-do now), 'reminder' → amber (reminder). onResolve marks it done. */
function NotifBanner({ notes, onResolve, showWho }) {
  if (!notes || notes.length === 0) return null;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
      {notes.map((n) => {
        const critical = n.severity === 'critical';
        const c = critical
          ? { bg: '#FEF2F2', bd: '#FECACA', fg: '#B91C1C', icon: I.alert || I.x, tag: 'Jādara tagad' }
          : { bg: 'var(--amber-tint)', bd: '#FDE68A', fg: '#92400E', icon: I.inbox, tag: 'Atgādinājums' };
        return (
          <div key={n.id} style={{ display: 'flex', alignItems: 'flex-start', gap: 12, background: c.bg, border: '1px solid ' + c.bd, borderRadius: 12, padding: '13px 16px' }}>
            <span style={{ width: 32, height: 32, borderRadius: 8, background: '#fff', color: c.fg, display: 'grid', placeItems: 'center', flex: 'none' }}><Icon d={c.icon} size={17} /></span>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 2 }}>
                <span style={{ fontSize: 11, fontWeight: 700, letterSpacing: '.05em', textTransform: 'uppercase', color: c.fg }}>{c.tag}</span>
                {showWho && n.toName ? <span className="muted" style={{ fontSize: 12 }}>· {n.toName}</span> : null}
              </div>
              <div style={{ fontSize: 13.5, color: c.fg, lineHeight: 1.5 }}>{n.message}</div>
            </div>
            {onResolve && (
              <button className="btn btn-sm" style={{ flex: 'none', background: '#fff', color: c.fg, border: '1px solid ' + c.bd, gap: 6 }} onClick={() => onResolve(n)}>
                <Icon d={I.check} size={15} sw={2.4} /> Atzīmēt kā izpildītu
              </button>
            )}
          </div>
        );
      })}
    </div>
  );
}

/* ---------- stat card ---------- */
function StatCard({ label, value, trend, trendUp = true, icon }) {
  return (
    <div className="card" style={{ padding: '18px 20px', display: 'flex', flexDirection: 'column', gap: 10 }}>
      <div className="spread">
        <span className="eyebrow">{label}</span>
        {icon && <span style={{ color: 'var(--muted-2)' }}><Icon d={I[icon]} size={17} /></span>}
      </div>
      <div className="tnum" style={{ fontSize: 28, fontWeight: 600, letterSpacing: '-0.03em' }}>{value}</div>
      {trend && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 12.5, fontWeight: 540, color: trendUp ? 'var(--green)' : 'var(--red)' }}>
          <Icon d={I.trend} size={14} style={{ transform: trendUp ? 'none' : 'scaleY(-1)' }} />
          {trend}<span className="muted" style={{ fontWeight: 450 }}>pret pagājušo mēnesi</span>
        </div>
      )}
    </div>
  );
}

/* ---------- progress ---------- */
function Budget({ spent, budget, showLabel = true, lang }) {
  const pct = Math.min(100, Math.round((spent / budget) * 100));
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      {showLabel && (
        <div className="spread" style={{ fontSize: 12.5 }}>
          <span className="muted">{tr('Budžets', lang)}</span>
          <span className="tnum" style={{ fontWeight: 540 }}>{eur0(budget - spent)} <span className="muted" style={{ fontWeight: 440 }}>/ {eur0(budget)}</span></span>
        </div>
      )}
      <div className="prog"><i style={{ width: pct + '%' }} /></div>
    </div>
  );
}

/* ---------- area chart (electric blue) ----------
   `data` is the primary series (blue). Optional `data2` renders a second
   series (amber). Handles empty/flat data without NaN paths. */
function AreaChart({ data, data2, height = 220, labels, label1 = 'Skatījumi', label2 = 'Klipi' }) {
  const w = 760, h = height, pad = 8;
  const series = (Array.isArray(data) && data.length > 1) ? data : [0, 0];
  const has2 = Array.isArray(data2) && data2.length === series.length;
  const max = Math.max(1, Math.max(...series, ...(has2 ? data2 : [])) * 1.1);
  const stepX = (w - pad * 2) / (series.length - 1);
  const toPts = (arr) => arr.map((v, i) => [pad + i * stepX, h - pad - ((v || 0) / max) * (h - pad * 2)]);
  const pts = toPts(series);
  const line = pts.map((p, i) => (i ? 'L' : 'M') + p[0].toFixed(1) + ' ' + p[1].toFixed(1)).join(' ');
  const area = line + ` L ${pts[pts.length - 1][0].toFixed(1)} ${h - pad} L ${pad} ${h - pad} Z`;
  const pts2 = has2 ? toPts(data2) : null;
  const line2 = pts2 ? pts2.map((p, i) => (i ? 'L' : 'M') + p[0].toFixed(1) + ' ' + p[1].toFixed(1)).join(' ') : '';
  const [hover, setHover] = React.useState(null); // index
  const onMove = (e) => {
    const r = e.currentTarget.getBoundingClientRect();
    const relX = (e.clientX - r.left) / r.width;
    let i = Math.round(relX * (series.length - 1));
    i = Math.max(0, Math.min(series.length - 1, i));
    setHover(i);
  };
  // Default day labels: last N days ending today.
  const dayLabel = (i) => {
    if (labels && labels[i]) return labels[i];
    const d = new Date(); d.setDate(d.getDate() - (series.length - 1 - i));
    return d.toLocaleDateString('lv-LV', { day: 'numeric', month: 'short' });
  };
  const hx = hover != null ? (pts[hover][0] / w) * 100 : 0;
  return (
    <div style={{ position: 'relative', width: '100%' }}>
      <svg viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ width: '100%', height, display: 'block' }}>
        <defs>
          <linearGradient id="kfill" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="#2563EB" stopOpacity="0.20" />
            <stop offset="100%" stopColor="#2563EB" stopOpacity="0" />
          </linearGradient>
        </defs>
        {[0.25, 0.5, 0.75, 1].map((g, i) => (
          <line key={i} x1={pad} x2={w - pad} y1={(h - pad * 2) * g + pad} y2={(h - pad * 2) * g + pad} stroke="#EEF1F5" strokeWidth="1" />
        ))}
        <path d={area} fill="url(#kfill)" />
        <path d={line} fill="none" stroke="#2563EB" strokeWidth="2.4" strokeLinejoin="round" strokeLinecap="round" />
        {line2 && <path d={line2} fill="none" stroke="#D97706" strokeWidth="2.2" strokeDasharray="5 4" strokeLinejoin="round" strokeLinecap="round" />}
        {hover != null && <line x1={pts[hover][0]} x2={pts[hover][0]} y1={pad} y2={h - pad} stroke="#CBD5E1" strokeWidth="1" strokeDasharray="3 3" />}
        <circle cx={pts[pts.length - 1][0]} cy={pts[pts.length - 1][1]} r="4" fill="#2563EB" stroke="#fff" strokeWidth="2" />
      </svg>
      {/* Hover dots (non-distorted, DOM-positioned) */}
      {[series, has2 ? data2 : null].filter(Boolean).map((arr, si) => (
        <React.Fragment key={si}>
          {arr.map((v, i) => (
            hover === i ? <span key={i} style={{ position: 'absolute', left: (pts[i][0] / w * 100) + '%', top: (toPts(arr)[i][1] / h * 100) + '%', width: 9, height: 9, borderRadius: 999, background: si ? '#D97706' : '#2563EB', border: '2px solid #fff', boxShadow: 'var(--sh-sm)', transform: 'translate(-50%,-50%)', pointerEvents: 'none' }} /> : null
          ))}
        </React.Fragment>
      ))}
      {/* Mouse-tracking overlay */}
      <div onMouseMove={onMove} onMouseLeave={() => setHover(null)} style={{ position: 'absolute', inset: 0, cursor: 'crosshair' }} />
      {hover != null && (
        <div style={{ position: 'absolute', left: `calc(${hx}% )`, top: -8, transform: 'translate(-50%,-100%)', background: 'var(--text)', color: '#fff', borderRadius: 8, padding: '7px 10px', fontSize: 12, lineHeight: 1.5, whiteSpace: 'nowrap', boxShadow: 'var(--sh-lg)', pointerEvents: 'none', zIndex: 5 }}>
          <div style={{ fontWeight: 600, marginBottom: 2 }}>{dayLabel(hover)}</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}><span style={{ width: 8, height: 8, borderRadius: 999, background: '#3B82F6' }} /> {label1}: <strong className="tnum">{numLv(series[hover] || 0)}</strong></div>
          {has2 && <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}><span style={{ width: 8, height: 8, borderRadius: 999, background: '#D97706' }} /> {label2}: <strong className="tnum">{numLv(data2[hover] || 0)}</strong></div>}
        </div>
      )}
    </div>
  );
}

/* ---------- public top nav ---------- */
function PublicNav({ go, route, aud, setAud, lang, setLang }) {
  return (
    <PublicNavInner go={go} route={route} aud={aud} setAud={setAud} lang={lang} setLang={setLang} />
  );
}

function PublicNavInner({ go, route, aud, setAud, lang, setLang }) {
  const [auth, setAuth] = React.useState(null);
  React.useEffect(() => {
    let unsub = null;
    (window.__firebaseReady || Promise.resolve(window.KlipzyFirebase)).then((fb) => {
      if (fb) unsub = fb.onAuth((r) => setAuth(r && r.user ? r : null));
    });
    return () => { if (unsub) unsub(); };
  }, []);
  const role = auth && auth.profile && auth.profile.role;
  const signOut = async () => {
    try { if (window.KlipzyFirebase) await window.KlipzyFirebase.signOutUser(); } catch (_) {}
    setAuth(null);
    go('landing');
  };
  return (
    <header style={{
      position: 'sticky', top: 0, zIndex: 40, background: 'rgba(255,255,255,0.82)',
      backdropFilter: 'blur(12px)', borderBottom: '1px solid var(--border)',
    }}>
      <div className="container nav-bar" style={{ height: 64, display: 'flex', alignItems: 'center', gap: 18 }}>
        <Logo size={20} onClick={() => go('landing')} />
        {setAud && <AudienceSwitch aud={aud} setAud={setAud} lang={lang} />}
        <div style={{ flex: 1 }} />
        <div className="nav-lang"><LangSwitch lang={lang} setLang={setLang} langs={['lv', 'en']} /></div>
        {auth ? (
          <>
            <button className="btn btn-primary nav-btn" onClick={() => go(homeForRole(role), { tab: 'panel' })}><Icon d={I.grid} size={16} /> <span className="nav-btn-label">{tr('Panelis', lang)}</span></button>
            <button className="btn btn-secondary nav-btn" onClick={signOut} style={{ gap: 7 }}>
              <Icon d={I.logout} size={16} /> <span className="nav-btn-label">{tr('Iziet', lang)}</span>
            </button>
          </>
        ) : (
          <>
            <button className="btn btn-secondary nav-btn" onClick={() => go('auth', { mode: 'login' })}><Icon d={I.login} size={16} /> <span className="nav-btn-label">{tr('Pieslēgties', lang)}</span></button>
            <button className="btn btn-primary nav-btn" onClick={() => go('auth', { mode: 'register' })}><Icon d={I.userPlus} size={16} /> <span className="nav-btn-label">{tr('Reģistrēties', lang)}</span></button>
          </>
        )}
      </div>
    </header>
  );
}

function AudienceSwitch({ aud, setAud, lang }) {
  const opts = [['clipper', lang === 'en' ? 'Clippers' : 'Kliperiem', I.play], ['brand', lang === 'en' ? 'Brands' : 'Zīmoliem', I.building]];
  return (
    <div className="aud-switch" style={{ display: 'inline-flex', gap: 3, padding: 3, background: '#F1F5F9', border: '1px solid var(--border)', borderRadius: 999 }}>
      {opts.map(([key, label, ic]) => {
        const on = aud === key;
        return (
          <button key={key} onClick={() => setAud(key)} className="aud-btn" style={{
            height: 32, padding: '0 16px', borderRadius: 999, border: 'none', cursor: 'pointer',
            fontSize: 13.5, fontWeight: 560, transition: 'background .14s, color .14s, box-shadow .14s',
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            background: on ? '#fff' : 'transparent',
            color: on ? 'var(--accent-700)' : 'var(--text-2)',
            boxShadow: on ? 'var(--sh-sm)' : 'none',
          }}>
            <span className="aud-icon"><Icon d={ic} size={16} /></span>
            <span className="aud-label">{label}</span>
          </button>
        );
      })}
    </div>
  );
}

function LangSwitch({ lang, setLang, langs = ['lv', 'en'] }) {
  const [local, setLocal] = React.useState(() => { try { return localStorage.getItem('klipzy_lang') || 'lv'; } catch (_) { return 'lv'; } });
  const cur = lang || local;
  const set = (l) => {
    try { localStorage.setItem('klipzy_lang', l); window.dispatchEvent(new CustomEvent('klipzy-lang', { detail: l })); } catch (_) {}
    // Persist to the profile so the choice follows the user across devices and
    // drives which language their emails are sent in.
    try {
      const uid = window.KlipzyFirebase && window.KlipzyFirebase.auth && window.KlipzyFirebase.auth.currentUser && window.KlipzyFirebase.auth.currentUser.uid;
      if (uid && window.KlipzyFirebase.setUserLang) window.KlipzyFirebase.setUserLang(uid, l);
    } catch (_) {}
    (setLang || setLocal)(l);
  };
  return (
    <div style={{ display: 'inline-flex', gap: 2, padding: 3, background: '#F1F5F9', border: '1px solid var(--border)', borderRadius: 999 }}>
      {langs.map((l) => {
        const on = cur === l;
        return (
          <button key={l} onClick={() => set(l)} style={{
            height: 30, padding: '0 14px', borderRadius: 999, border: 'none', cursor: 'pointer',
            fontSize: 13, fontWeight: 600, letterSpacing: '0.02em', transition: 'background .14s, color .14s, box-shadow .14s',
            background: on ? '#fff' : 'transparent',
            color: on ? 'var(--accent-700)' : 'var(--text-2)',
            boxShadow: on ? 'var(--sh-sm)' : 'none',
          }}>
            {l.toUpperCase()}
          </button>
        );
      })}
    </div>
  );
}

/* ---------- dashboard sidebar ---------- */
function Sidebar({ items, active, onNav, role, go, user }) {
  const lang = useLang();
  const profile = (user && user.profile) || {};
  const fbUser = (user && user.user) || {};
  const displayName = profile.displayName || fbUser.displayName || (role === 'brand' ? 'Rīga Energy' : 'Jānis B.');
  const email = profile.email || fbUser.email || '';
  const photoURL = profile.photoURL || fbUser.photoURL || '';
  const initials = (displayName || '?').trim().split(/\s+/).map((w) => w[0]).slice(0, 2).join('').toUpperCase();
  const roleLabel = role === 'brand' ? tr('Zīmols', lang) : role === 'admin' ? tr('Administrators', lang) : tr('Klipotājs', lang);
  const [menuOpen, setMenuOpen] = React.useState(false);
  const [collapsed, setCollapsed] = React.useState(false);
  const signOut = async () => {
    try { if (window.KlipzyFirebase) await window.KlipzyFirebase.signOutUser(); } catch (_) {}
    go('landing');
  };
  const pick = (k) => { onNav(k); setMenuOpen(false); };
  return (
    <aside className={'dash-sidebar' + (collapsed ? ' collapsed' : '')} style={{
      width: 248, flex: 'none', background: '#fff', borderRight: '1px solid var(--border)',
      display: 'flex', flexDirection: 'column', height: '100%',
    }}>
      <div className="dash-bar" style={{ padding: '18px 18px 14px' }}>
        <span className="dash-logo-full"><Logo size={19} onClick={() => go('landing')} /></span>
        <span className="dash-logo-icon" onClick={() => go('landing')} aria-label="Klipzy" style={{ cursor: 'pointer', display: 'none' }}><img src="assets/klipzy-icon.svg" alt="Klipzy" style={{ height: 22, width: 'auto', display: 'block' }} /></span>
        <button className="dash-collapse btn btn-ghost btn-sm" aria-label="Sakļaut izvēlni" onClick={() => setCollapsed((c) => !c)} style={{ padding: 8 }}>
          <Icon d={collapsed ? I.arrowR : I.arrowL} size={18} />
        </button>
        <button className="dash-burger btn btn-ghost btn-sm" aria-label="Izvēlne" aria-expanded={menuOpen}
          onClick={() => setMenuOpen((o) => !o)} style={{ padding: 8 }}>
          <Icon d={menuOpen ? I.x : I.menu} size={20} />
        </button>
      </div>

      <div className={'dash-menu' + (menuOpen ? ' open' : '')}>
        <button className="dash-menu-panel btn btn-primary" onClick={() => pick('panel')} style={{ width: '100%', justifyContent: 'flex-start', gap: 10 }}>
          <Icon d={I.grid} size={17} /> {tr('Panelis', lang)}
        </button>

        <nav style={{ padding: '4px 12px', display: 'flex', flexDirection: 'column', gap: 2, flex: 1 }}>
          {items.map((it) => {
            const on = active === it.key;
            return (
              <button key={it.key} onClick={() => pick(it.key)} title={it.label} className={'dash-navitem' + (it.key === 'panel' ? ' dash-navitem-panel' : '')} style={{
                display: 'flex', alignItems: 'center', gap: 11, height: 40, padding: '0 12px',
                borderRadius: 8, border: 'none', textAlign: 'left', width: '100%',
                background: on ? 'var(--accent-tint)' : 'transparent',
                color: on ? 'var(--accent-700)' : 'var(--text-2)',
                fontWeight: on ? 560 : 500, fontSize: 14, transition: 'background .12s',
              }}
                onMouseEnter={(e) => { if (!on) e.currentTarget.style.background = '#F4F6F9'; }}
                onMouseLeave={(e) => { if (!on) e.currentTarget.style.background = 'transparent'; }}>
                <Icon d={I[it.icon]} size={18} style={{ opacity: on ? 1 : .75, flex: 'none' }} />
                <span className="nav-label">{it.label}</span>
                {it.badge ? <span className="nav-badge" style={{ marginLeft: 'auto', background: 'var(--accent)', color: '#fff', fontSize: 11, fontWeight: 600, borderRadius: 999, minWidth: 18, height: 18, display: 'grid', placeItems: 'center', padding: '0 5px' }}>{it.badge}</span> : null}
              </button>
            );
          })}
        </nav>

        <div className="dash-foot" style={{ padding: 12, borderTop: '1px solid var(--border)' }}>
          <div className="dash-lang" style={{ display: 'flex', justifyContent: 'center', marginBottom: 10 }}>
            <LangSwitch langs={['lv', 'en']} />
          </div>
          <div className="dash-user" style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 10px', borderRadius: 8 }}>
            {photoURL
              ? <img src={photoURL} alt="" referrerPolicy="no-referrer" style={{ width: 34, height: 34, borderRadius: 9, objectFit: 'cover', flex: 'none' }} />
              : <BrandLogo initials={initials} grad={role === 'brand' ? ['#F43F5E', '#FB7185'] : role === 'admin' ? ['#F59E0B', '#FBBF24'] : ['#2563EB', '#3B82F6']} size={34} radius={9} />}
            <div className="dash-userinfo" style={{ minWidth: 0, flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
              <div className="dash-name-line" style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <span style={{ fontSize: 13.5, fontWeight: 560, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', flex: 1, minWidth: 0 }}>{displayName}</span>
              </div>
              <div className="dash-role muted" style={{ fontSize: 11.5, fontWeight: 540, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', marginTop: 1 }}>{roleLabel}</div>
              {email && <div className="dash-email muted" style={{ fontSize: 11, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', marginTop: 1, opacity: .8 }}>{email}</div>}
            </div>
            <div className="dash-lang-inline" style={{ flex: 'none' }}><LangSwitch langs={['lv', 'en']} /></div>
            <button className="btn btn-ghost btn-sm dash-signout-icon" style={{ padding: 6 }} title={tr('Iziet', lang)} onClick={signOut}><Icon d={I.logout} size={16} /></button>
          </div>
          <button className="dash-menu-signout btn btn-secondary" onClick={signOut} style={{ width: '100%', gap: 8, marginTop: 4 }}>
            <Icon d={I.logout} size={16} /> {tr('Iziet', lang)}
          </button>
        </div>
      </div>
    </aside>
  );
}

/* dashboard top bar */
function TopBar({ title, subtitle, children, notif }) {
  return (
    <div className="spread r-topbar" style={{ padding: '22px 32px', borderBottom: '1px solid var(--border)', background: 'rgba(247,248,250,.7)', backdropFilter: 'blur(8px)', position: 'sticky', top: 0, zIndex: 20 }}>
      <div>
        <h1 style={{ fontSize: 21, fontWeight: 600 }}>{title}</h1>
        {subtitle && <p className="muted" style={{ fontSize: 13.5, marginTop: 3 }}>{subtitle}</p>}
      </div>
      <div className="r-topbar-actions" style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>{children}{notif && <NotifBell notes={notif.notes} onResolve={notif.onResolve} />}</div>
    </div>
  );
}

/* Top-nav notification bell with unread count + dropdown. `notes` are the
   unresolved notifications for the signed-in user; clicking one resolves it. */
function NotifBell({ notes, onResolve }) {
  const lang = (typeof useLang === 'function') ? useLang() : 'lv';
  const [open, setOpen] = React.useState(false);
  const list = Array.isArray(notes) ? notes : [];
  const count = list.length;
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [open]);
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button className="btn btn-secondary" style={{ padding: 9, position: 'relative' }} title={tr('Paziņojumi', lang)} onClick={() => setOpen((o) => !o)}>
        <Icon d={I.bell} size={18} />
        {count > 0 && <span style={{ position: 'absolute', top: -5, right: -5, minWidth: 18, height: 18, padding: '0 5px', borderRadius: 999, background: 'var(--red)', color: '#fff', fontSize: 11, fontWeight: 700, display: 'grid', placeItems: 'center', lineHeight: 1 }}>{count > 9 ? '9+' : count}</span>}
      </button>
      {open && (
        <div className="card fade-in notif-pop" style={{ position: 'absolute', right: 0, top: 'calc(100% + 8px)', width: 320, maxWidth: 'calc(100vw - 24px)', maxHeight: 400, overflowY: 'auto', padding: 0, zIndex: 40, boxShadow: 'var(--sh-lg, 0 12px 40px rgba(0,0,0,.14))' }}>
          <div className="spread" style={{ padding: '13px 16px', borderBottom: '1px solid var(--border)' }}>
            <span style={{ fontSize: 14, fontWeight: 600 }}>{tr('Paziņojumi', lang)}</span>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              {count > 0 && <span className="muted" style={{ fontSize: 12.5 }}>{count}</span>}
              <button className="btn btn-ghost btn-sm" style={{ padding: 4 }} title={tr('Aizvērt', lang)} onClick={() => setOpen(false)}><Icon d={I.x} size={16} /></button>
            </div>
          </div>
          {count === 0 ? (
            <div className="muted" style={{ padding: '24px 16px', textAlign: 'center', fontSize: 13.5 }}>{tr('Nav jaunu paziņojumu.', lang)}</div>
          ) : list.map((n) => (
            <div key={n.id} style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)', display: 'flex', gap: 10, alignItems: 'flex-start' }}>
              <span style={{ width: 8, height: 8, borderRadius: 999, marginTop: 6, flex: 'none', background: n.severity === 'critical' ? 'var(--red)' : 'var(--amber, #D97706)' }} />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 13, lineHeight: 1.45, color: 'var(--text)' }}>{n.message}</div>
                <button className="btn-link" style={{ marginTop: 6, background: 'none', border: 'none', color: 'var(--accent-700)', cursor: 'pointer', padding: 0, font: 'inherit', fontSize: 12.5 }} onClick={() => onResolve && onResolve(n)}>{tr('Atzīmēt kā izlasītu', lang)}</button>
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

/* Build + open a printable PDF invoice (browser print → Save as PDF).
   Only brand info, dates, and amounts vary; Klipzy issuer block is fixed. */
function klipzyInvoice(txn, profile, lang) {
  const en = lang === 'en';
  const brand = (profile && (profile.company || profile.displayName)) || (en ? 'Brand' : 'Zīmols');
  const email = (profile && profile.email) || '';
  const gross = Number(txn.amount) || 0;
  const net = +(gross / 1.21).toFixed(2);
  const vat = +(gross - net).toFixed(2);
  const d = txn.createdAt && txn.createdAt.seconds ? new Date(txn.createdAt.seconds * 1000) : new Date();
  const fmtD = d.toLocaleDateString(en ? 'en-GB' : 'lv-LV', { day: '2-digit', month: '2-digit', year: 'numeric' });
  const no = 'KZ-' + d.getFullYear() + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(txn.id || '').slice(-6).toUpperCase();
  const m = (n) => (en ? '\u20ac' + n.toFixed(2) : n.toFixed(2).replace('.', ',') + ' \u20ac');
  const t = en
    ? { inv: 'Invoice', no: 'Invoice no.', date: 'Date', from: 'From', to: 'Bill to', desc: 'Description', net: 'Subtotal', vat: 'VAT 21%', total: 'Total', item: 'Klipzy account top-up', paid: 'Paid', foot: 'Thank you for using Klipzy.' }
    : { inv: 'R\u0113\u0137ins', no: 'R\u0113\u0137ina nr.', date: 'Datums', from: 'No', to: 'Maks\u0101t\u0101js', desc: 'Apraksts', net: 'Summa bez PVN', vat: 'PVN 21%', total: 'Kop\u0101', item: 'Klipzy konta papildin\u0101jums', paid: 'Apmaks\u0101ts', foot: 'Paldies, ka izmanto Klipzy.' };
  const html = '<!DOCTYPE html><html><head><meta charset="utf-8"><title>' + no + '</title><style>'
    + 'body{font-family:-apple-system,Segoe UI,Roboto,sans-serif;color:#0F172A;max-width:720px;margin:40px auto;padding:0 32px}'
    + 'h1{font-size:26px;letter-spacing:-.02em;margin:0}.muted{color:#64748B}.accent{color:#2563EB}'
    + '.row{display:flex;justify-content:space-between;gap:24px}.mt{margin-top:34px}'
    + 'table{width:100%;border-collapse:collapse;margin-top:26px}td,th{padding:11px 0;border-bottom:1px solid #E2E8F0;text-align:left;font-size:14px}'
    + 'th:last-child,td:last-child{text-align:right}.tot td{border:none;font-weight:700;font-size:16px}.badge{display:inline-block;background:#DCFCE7;color:#166534;font-size:12px;font-weight:600;padding:4px 10px;border-radius:999px}'
    + '</style></head><body>'
    + '<div class="row"><div><div style="font-size:20px;font-weight:700" class="accent">Klipzy</div><div class="muted" style="font-size:13px;margin-top:4px">SIA SERPA Media Group<br>Latvija<br>support@klipzy.lv</div></div>'
    + '<div style="text-align:right"><h1>' + t.inv + '</h1><div class="muted" style="font-size:13px;margin-top:6px">' + t.no + ' ' + no + '<br>' + t.date + ': ' + fmtD + '</div><div style="margin-top:8px"><span class="badge">' + t.paid + '</span></div></div></div>'
    + '<div class="row mt"><div><div class="muted" style="font-size:12px;text-transform:uppercase;letter-spacing:.05em">' + t.to + '</div><div style="font-weight:600;margin-top:4px">' + brand + '</div><div class="muted" style="font-size:13px">' + email + '</div></div></div>'
    + '<table><thead><tr><th>' + t.desc + '</th><th>' + t.total + '</th></tr></thead><tbody>'
    + '<tr><td>' + t.item + '</td><td>' + m(net) + '</td></tr>'
    + '<tr><td class="muted">' + t.vat + '</td><td class="muted">' + m(vat) + '</td></tr>'
    + '<tr class="tot"><td>' + t.total + '</td><td>' + m(gross) + '</td></tr>'
    + '</tbody></table>'
    + '<p class="muted mt" style="font-size:13px">' + t.foot + '</p>'
    + '<script>window.onload=function(){window.print()}<\/script></body></html>';
  const w = window.open('', '_blank');
  if (!w) return;
  w.document.write(html);
  w.document.close();
}

Object.assign(window, {
  useState, useRef, useEffect, useMemo,
  eur, eur0, views, numLv, Icon, I, Logo, GradTile, BrandLogo, Platform,
  StatusBadge, StatCard, Budget, AreaChart, PublicNav, AudienceSwitch, Sidebar, TopBar, STATUS, campaignState, clipState,
  LangSwitch, useLang, AuthLoading, tr, homeForRole, PasswordField, NotifBanner, NotifBell, klipzyInvoice,
  getVerify, setVerifyFlag, accountVerified, useVerify,
});
