// RiftInfra.jsx — Домени (DomainsPage) + Технології (TechPage)

const T_DOM = {
  uk: {
    eyebrow: 'Доменні зони',
    h1a: 'Регіональні домени',
    h1b: 'Рівненщини',
    sub: 'РІФТ адмініструє три публічні географічні зони Рівненської області. Кожна має власне призначення, історію та статус. Реєстрація — через акредитованих реєстраторів.',
    zonesTitle: 'Огляд зон',
    zoneCta: 'Знайти реєстратора →',
    histTitle: 'Хронологія доменів регіону',
    histSub: 'Коротка історія боротьби за українську адресу Рівного.',
    pivot: 'Поворотний момент',
    regionTitle: 'Регіон, який ми обслуговуємо',
    regionSub: 'Рівненська область — 20 047 км², чотири укрупнені райони, понад мільйон мешканців. Кожна громада може мати власну адресу в зоні rv.ua.',
    facts: [['Площа', '20 047 км²'], ['Райони', '4'], ['Громади', '64'], ['Адмінцентр', 'Рівне']],
    history: [
      { y: '1992', t: '.ua делеговано', d: 'ICANN делегує національний домен .ua. Україна отримує власний цифровий простір.' },
      { y: '12.12.1992', t: 'rovno.ua', d: 'Створено найстарішу рівненську зону. Назву зафіксовано в російській транслітерації, успадкованій з радянських часів.' },
      { y: '16.02.1997', t: 'rv.ua відкрито', d: 'Запущено нейтральну зону rv.ua — скорочення для rivne.ua / rovno.ua. Відкрита реєстрація.' },
      { y: '2011', t: 'Засновано РІФТ', d: 'Група технічних фахівців-ентузіастів засновує ТОВ «РІФТ» — професійного адміністратора зон.' },
      { y: '02.02.2015', t: 'rivne.ua', d: 'Делеговано офіційну українську зону rivne.ua. DNSSEC, локальна ідентичність.' },
      { y: '2022', t: 'Закриття rovno.ua', d: 'Після повномасштабного вторгнення РФ зону rovno.ua виведено з обігу. Домени мігрують у rivne.ua / rv.ua.' },
    ],
  },
  en: {
    eyebrow: 'Domain zones',
    h1a: 'Regional domains',
    h1b: 'of Rivne region',
    sub: 'RIFT administers three public geographic zones of the Rivne region. Each has its own purpose, history and status. Registration is via accredited registrars.',
    zonesTitle: 'Zones overview',
    zoneCta: 'Find a registrar →',
    histTitle: 'Regional domain chronology',
    histSub: 'A short history of the fight for a Ukrainian address for Rivne.',
    pivot: 'Turning point',
    regionTitle: 'The region we serve',
    regionSub: 'Rivne Oblast — 20,047 km², four enlarged raions, over a million residents. Every community can have its own address in the rv.ua zone.',
    facts: [['Area', '20,047 km²'], ['Raions', '4'], ['Communities', '64'], ['Capital', 'Rivne']],
    history: [
      { y: '1992', t: '.ua delegated', d: 'ICANN delegates the national .ua domain. Ukraine gains its own digital space.' },
      { y: '12.12.1992', t: 'rovno.ua', d: 'The oldest Rivne zone is created. The name fixed in Russian transliteration inherited from Soviet times.' },
      { y: '16.02.1997', t: 'rv.ua launched', d: 'Neutral rv.ua zone launched — a short alias for rivne.ua / rovno.ua. Open registration.' },
      { y: '2011', t: 'RIFT founded', d: 'A group of technical enthusiasts founds RIFT Ltd. — a professional zone administrator.' },
      { y: '02.02.2015', t: 'rivne.ua', d: 'The official Ukrainian zone rivne.ua is delegated. DNSSEC, local identity.' },
      { y: '2022', t: 'rovno.ua closed', d: 'After Russia\'s full-scale invasion, the rovno.ua zone is retired. Domains migrate to rivne.ua / rv.ua.' },
    ],
  },
};

const DomainsPage = ({ lang, setPage }) => {
  const t = T_DOM[lang];
  const ZONES = window.RIFT_ZONES || [];
  return (
    <main className="rb-page">
      <section className="rb-pagehead rb-pagehead--manifesto">
        <div className="rb-eyebrow"><span className="rb-eyebrow__dot" />{t.eyebrow}</div>
        <h1 className="rb-h1 rb-h1--page">
          <span className="rb-h1__a">{t.h1a}</span>
          <span className="rb-h1__b">{t.h1b}</span>
        </h1>
        <p className="rb-lead">{t.sub}</p>
        <div className="rb-flag" aria-hidden><div className="rb-flag__blue" /><div className="rb-flag__yellow" /></div>
      </section>

      <section className="rb-section">
        <div className="rb-section__head">
          <h2 className="rb-h2">{t.zonesTitle}</h2>
        </div>
        <div className="rb-zonegrid" style={{ gridTemplateColumns: 'repeat(3, 1fr)' }}>
          {ZONES.map(z => (
            <article className={`rb-zonecard ${z.status === 'retired' ? 'rb-zonecard--retired' : ''}`} key={z.tld}>
              <div className="rb-zonecard__head">
                <span className={`rb-zonecard__tag rb-zonecard__tag--${z.status}`}>{z.tag[lang]}</span>
                <span style={{ fontFamily: 'var(--rb-font-mono)', fontSize: 12, color: 'var(--rb-muted)' }}>{z.year}</span>
              </div>
              <div className="rb-zonecard__tld">.{z.tld}</div>
              <div className="rb-zonecard__short">{z.short[lang]}</div>
              <p className="rb-zonecard__long">{z.long[lang]}</p>
              {z.status === 'open'
                ? <button className="rb-zonecard__cta" onClick={() => setPage('registrars')}>{t.zoneCta}</button>
                : <button className="rb-zonecard__cta" onClick={() => setPage('docs')}>{lang === 'uk' ? 'Регламент →' : 'Regulation →'}</button>}
            </article>
          ))}
        </div>
      </section>

      <section className="rb-section rb-section--alt">
        <div className="rb-section__head">
          <h2 className="rb-h2">{t.histTitle}</h2>
          <p className="rb-sub">{t.histSub}</p>
        </div>
        <div className="rb-dhistory" style={{ gridTemplateColumns: 'repeat(3, 1fr)' }}>
          {t.history.map(e => (
            <article className={`rb-dhist ${e.y === '2022' ? 'is-pivot' : ''}`} key={e.y}>
              <div className="rb-dhist__y">{e.y}</div>
              <div className="rb-dhist__t">{e.t}</div>
              <div className="rb-dhist__d">{e.d}</div>
              {e.y === '2022' && <div className="rb-dhist__badge">{t.pivot}</div>}
            </article>
          ))}
        </div>
      </section>

      <section className="rb-section">
        <div className="rb-section__head">
          <h2 className="rb-h2">{t.regionTitle}</h2>
          <p className="rb-sub">{t.regionSub}</p>
        </div>
        <div className="rift-region">
          <figure className="rift-region__map">
            <div className="rift-region__mapclip">
              <RivneMap lang={lang} />
            </div>
            <figcaption>{lang === 'uk' ? 'Рівненська область · зона обслуговування РІФТ' : 'Rivne Oblast · RIFT service area'}</figcaption>
          </figure>
          <div className="rift-region__facts">
            {t.facts.map(([k, v], i) => (
              <div className="rift-region__fact" key={i}>
                <div className="rb-stat__num">{v}</div>
                <div className="rb-stat__lab">{k}</div>
              </div>
            ))}
          </div>
        </div>
      </section>
    </main>
  );
};
window.DomainsPage = DomainsPage;

// ============ TECHNOLOGY ============
const T_TECH = {
  uk: {
    eyebrow: 'Технології та безпека',
    h1a: 'Інфраструктура',
    h1b: 'рівня enterprise',
    sub: 'Регіональна зона відрізняється від будь-якої іншої не назвою, а інженерією під нею. Ось стандарти, на яких працюють рівненські домени.',
    lead: 'Усі рівненські домени працюють на найсучасніших технологіях. Наша мета — зробити їх найбезпечнішими, найстійкішими до зовнішніх загроз та найефективнішими у використанні сучасних рішень.',
    secTitle: 'Стек безпеки',
    secSub: 'Вісім рівнів захисту, які відділяють регіональну зону від звичайного хостингу.',
    security: [
      { t: 'DNSSEC з 2012 року', tag: 'crypto', d: 'РІФТ першим в Україні впровадив DNSSEC для регіональних доменів. Усі зони підписані на рівні .ua TLD: криптографічний підпис захищає від cache poisoning та DNS-спуфінгу — клієнт бачить лише ваш сайт, не підмінений.' },
      { t: 'EPP-протокол передачі', tag: 'RFC 5731', d: 'Міжнародний стандарт. Перехід між реєстраторами — лише за одноразовим кодом, який видає поточний власник. Домен неможливо «вкрасти».' },
      { t: 'Anycast DNS', tag: '6 вузлів', d: 'NS-сервери зон розподілені у мережі anycast у межах України та світу. Запит обслуговує найближчий вузол — стійкість до DDoS та збоїв.' },
      { t: 'Хмарна SaaS-інфраструктура', tag: 'Cloudflare · AWS', d: 'Реєстр і вебсервіси працюють на хмарних платформах світового рівня — Cloudflare та AWS: захист від DDoS, WAF, автомасштабування та TLS-термінація на сотнях точок присутності у світі.' },
      { t: 'Подвійний стек IPv6', tag: 'dual-stack', d: 'Реєстр і DNS доступні через IPv4 та IPv6. Домени готові до інтернету наступного покоління без міграцій.' },
      { t: 'Кириличні домени (IDN)', tag: 'IDNA', d: 'Підтримка інтернаціоналізованих доменних імен українською абеткою за стандартом IDNA. Українська не лише у змісті, а й у самому імені домену.' },
      { t: 'WHOIS-приватність', tag: 'GDPR', d: 'Особисті дані фізичних осіб приховані від відкритого запиту. Юридичні особи — повна прозорість, як вимагає закон.' },
      { t: 'Захист від кіберсквотингу', tag: 'UADRP', d: 'Процедура вирішення спорів про домени за брендами та торговельними марками. Домен можна повернути заявникові протягом 60 днів.' },
    ],
    flowTitle: 'Як домен потрапляє в реєстр',
    partnersTitle: 'Технологічна основа',
    partnersSub: 'Інфраструктура РІФТ побудована на світових SaaS-платформах та у партнерстві з адміністратором домену .UA.',
    partners: [
      { name: 'Cloudflare', role: 'Edge-мережа · DDoS · WAF' },
      { name: 'AWS', role: 'Хмарні обчислення · зберігання' },
      { name: 'Hostmaster.ua', role: 'Адміністратор домену .UA' },
    ],
    flow: [
      { t: 'Заявка', d: 'Клієнт обирає реєстратора, перевіряє вільне імʼя та подає заявку.' },
      { t: 'Перевірка', d: 'Реєстратор валідує дані; для rivne.ua — підтвердження звʼязку з регіоном.' },
      { t: 'Реєстрація в РІФТ', d: 'Реєстратор створює запис у реєстрі зони. Делегування NS, підпис DNSSEC.' },
      { t: 'Активація', d: 'Домен резолвиться у DNS. Видається EPP-код власника та SSL.' },
    ],
    statusTitle: 'Поточні показники',
    faqTitle: 'DNSSEC — поширені питання',
    faq: [
      { q: 'Що таке DNSSEC і навіщо він домену?', a: 'DNSSEC додає до DNS-відповідей криптографічний підпис. Він гарантує, що відвідувач потрапляє саме на ваш сайт, а не на підроблений через підміну DNS (cache poisoning). Для рівненських зон це базовий рівень довіри — РІФТ першим в Україні впровадив DNSSEC для регіональних доменів — ще 2012 року.' },
      { q: 'Як увімкнути DNSSEC для рівненського домену?', a: 'Через вашого реєстратора: він генерує ключі та публікує DS-запис у реєстрі РІФТ. Зони rivne.ua та rv.ua вже підписані на рівні .ua, тож ваш домен входить у безперервний ланцюг довіри аж до кореня DNS.' },
      { q: 'Чим DNSSEC відрізняється від SSL-сертифіката?', a: 'Це різні рівні захисту, що доповнюють одне одного. SSL/TLS шифрує зʼєднання вже із сайтом (https). DNSSEC захищає попередній крок — сам пошук адреси домену в DNS, щоб вас не перенаправили на чужий сервер.' },
      { q: 'Чи може DNSSEC зробити домен недоступним?', a: 'На швидкість DNSSEC впливає мінімально. Але некоректні DS-записи чи зміна DNS в обхід реєстратора можуть розірвати ланцюг підписів і зробити домен недоступним. Тому будь-які зміни DNS виконуйте лише через акредитованого реєстратора.' },
    ],
  },
  en: {
    eyebrow: 'Technology & security',
    h1a: 'Enterprise-grade',
    h1b: 'infrastructure',
    sub: 'A regional zone differs from any other not by its name but by the engineering underneath it. Here are the standards Rivne domains run on.',
    lead: 'All Rivne domains run on the latest technology. Our goal is to make them the most secure, the most resilient to external threats and the most effective in using modern solutions.',
    secTitle: 'Security stack',
    secSub: 'Eight layers of protection separating a regional zone from ordinary hosting.',
    security: [
      { t: 'DNSSEC since 2012', tag: 'crypto', d: 'RIFT was the first in Ukraine to deploy DNSSEC for regional domains. All zones are signed at the .ua TLD level: cryptographic signing protects against cache poisoning and DNS spoofing — clients see only your site, not a forgery.' },
      { t: 'EPP transfer protocol', tag: 'RFC 5731', d: 'An international standard. Switching registrars happens only via a one-time code issued by the current owner. A domain cannot be "stolen".' },
      { t: 'Anycast DNS', tag: '6 nodes', d: 'Zone NS servers are distributed across an anycast network in Ukraine and worldwide. The nearest node serves each query — resilient to DDoS and outages.' },
      { t: 'Cloud SaaS infrastructure', tag: 'Cloudflare · AWS', d: 'The registry and web services run on world-class cloud platforms — Cloudflare and AWS: DDoS protection, WAF, auto-scaling and TLS termination across hundreds of points of presence worldwide.' },
      { t: 'IPv6 dual stack', tag: 'dual-stack', d: 'The registry and DNS are reachable over IPv4 and IPv6. Domains are ready for the next-generation internet with no migration.' },
      { t: 'Cyrillic domains (IDN)', tag: 'IDNA', d: 'Support for internationalised domain names in the Ukrainian alphabet under the IDNA standard. Ukrainian not only in content, but in the domain name itself.' },
      { t: 'WHOIS privacy', tag: 'GDPR', d: 'Personal data of individuals is hidden from public lookups. Legal entities — full transparency, as required by law.' },
      { t: 'Anti-cybersquatting', tag: 'UADRP', d: 'A dispute resolution procedure for brand and trademark domains. A domain can be returned to the claimant within 60 days.' },
    ],
    flowTitle: 'How a domain enters the registry',
    partnersTitle: 'Technology foundation',
    partnersSub: 'RIFT\'s infrastructure is built on world-class SaaS platforms and in partnership with the .UA domain administrator.',
    partners: [
      { name: 'Cloudflare', role: 'Edge network · DDoS · WAF' },
      { name: 'AWS', role: 'Cloud compute · storage' },
      { name: 'Hostmaster.ua', role: '.UA domain administrator' },
    ],
    flow: [
      { t: 'Application', d: 'The client chooses a registrar, checks an available name and applies.' },
      { t: 'Verification', d: 'The registrar validates data; for rivne.ua — proof of regional ties.' },
      { t: 'Registration at RIFT', d: 'The registrar creates a record in the zone registry. NS delegation, DNSSEC signing.' },
      { t: 'Activation', d: 'The domain resolves in DNS. The owner EPP code and SSL are issued.' },
    ],
    statusTitle: 'Current metrics',
    faqTitle: 'DNSSEC — frequently asked questions',
    faq: [
      { q: 'What is DNSSEC and why does a domain need it?', a: 'DNSSEC adds a cryptographic signature to DNS responses. It guarantees a visitor reaches your real site, not a forgery served via DNS cache poisoning. For the Rivne zones it is a baseline of trust — RIFT was the first in Ukraine to deploy DNSSEC for regional domains, back in 2012.' },
      { q: 'How do I enable DNSSEC for a Rivne domain?', a: 'Through your registrar: it generates the keys and publishes the DS record in the RIFT registry. The rivne.ua and rv.ua zones are already signed at the .ua level, so your domain joins an unbroken chain of trust up to the DNS root.' },
      { q: 'How is DNSSEC different from an SSL certificate?', a: 'They are complementary layers. SSL/TLS encrypts the connection to the site itself (https). DNSSEC protects the earlier step — looking up the domain address in DNS — so you are not redirected to someone else\'s server.' },
      { q: 'Can DNSSEC make a domain unreachable?', a: 'DNSSEC has minimal impact on speed. But incorrect DS records or changing DNS bypassing the registrar can break the chain of signatures and make the domain unreachable. Always make DNS changes through an accredited registrar.' },
    ],
  },
};

// Brand marks for technology partners (nominative use — tasteful inline SVG).
const PartnerMark = ({ name }) => {
  if (name === 'Cloudflare') {
    return (
      <svg viewBox="0 0 200 48" height="34" role="img" aria-label="Cloudflare" style={{ display: 'block' }}>
        <path d="M44.5 33.5c1.2-3.4-.6-6.8-4-7.1l-19.8-.25a.5.5 0 01-.38-.2.5.5 0 01-.06-.43.55.55 0 01.46-.36l20-.26c2.37-.18 4.94-2.1 5.84-4.46l1.14-3a.65.65 0 00.03-.36A13.1 13.1 0 0023.6 16.4 6.1 6.1 0 0014 22.2a6.6 6.6 0 00.16 2.07 8.66 8.66 0 00-8.4 8.6c0 .43.03.86.1 1.3a.4.4 0 00.4.34h36.8a.5.5 0 00.48-.36z" fill="#F6821F"/>
        <path d="M51 19.7l-.55.02a.33.33 0 00-.3.23l-.78 2.7c-1.2 3.4.6 6.8 4 7.1l4.2.26a.5.5 0 01.38.2.5.5 0 01.06.44.55.55 0 01-.46.36l-4.37.26c-2.38.18-4.94 2.1-5.84 4.46l-.32.83a.32.32 0 00.28.43H62a.42.42 0 00.4-.3 10.8 10.8 0 00.4-2.9A10.74 10.74 0 0051 19.7z" fill="#FBAD41"/>
        <text x="78" y="31" fontFamily="var(--rb-font-sans)" fontSize="18" fontWeight="700" fill="currentColor">Cloudflare</text>
      </svg>
    );
  }
  if (name === 'AWS') {
    return (
      <svg viewBox="0 0 120 60" height="38" role="img" aria-label="Amazon Web Services" style={{ display: 'block' }}>
        <text x="60" y="30" textAnchor="middle" fontFamily="var(--rb-font-sans)" fontSize="30" fontWeight="800" letterSpacing="1" fill="currentColor">aws</text>
        <path d="M30 42 q30 14 60 0" stroke="#FF9900" strokeWidth="4" fill="none" strokeLinecap="round"/>
        <path d="M84 41.5 l8 1 -3.5 7z" fill="#FF9900"/>
      </svg>
    );
  }
  // Hostmaster.ua — офіційний логотип (ccTLD .UA)
  return <img src="assets/hostmaster-logo.png" alt="Hostmaster.ua" height="48" loading="lazy" decoding="async" style={{ display: 'block', height: 48, width: 'auto' }} />;
};

// RivneMap — clean Rivne-oblast silhouette (brand blue) with a gold marker on Rivne.
const RIVNE_OBLAST_PATH = "M 25.79 4.23 L 26.99 4.9 L 29.45 7.79 L 30.02 14.11 L 26.2 19.19 L 26.61 22.46 L 26.16 24.86 L 28.69 29.05 L 32.81 32.19 L 37.18 35.7 L 39.52 39.06 L 41.35 42.43 L 37.99 46.12 L 41.75 49.32 L 39.31 53.91 L 36.71 57.71 L 35.06 64.38 L 33.13 66.23 L 30.47 64.98 L 27.53 63.07 L 24.13 64.53 L 20.76 65.22 L 19.02 67.04 L 14.53 70.51 L 13.19 74.5 L 12.52 74.89 L 12.48 75.31 L 14.82 78.32 L 13.4 81.2 L 11.11 80.52 L 9.08 79.29 L 11.68 82.2 L 15.76 84.85 L 15.85 89.08 L 19.48 96 L 22.22 93.72 L 22.74 90.14 L 26.13 89.81 L 30.32 88.62 L 34.01 88.08 L 36.91 84.66 L 40.94 84.27 L 44.45 84.45 L 45.67 86.37 L 46.86 88.47 L 47.05 91.38 L 47.54 88.77 L 52.55 84.66 L 55.05 82.59 L 59.03 78.47 L 60.83 75.9 L 62.52 73.09 L 65.36 72.1 L 70.11 70.45 L 72.88 69.25 L 74.74 70.45 L 75.62 66.2 L 77.24 62.75 L 76.17 54.75 L 74.87 48.59 L 76.46 47.18 L 79.67 42.95 L 81.97 37.72 L 82.59 33.29 L 84.4 26.99 L 87.95 24.6 L 89.7 20.81 L 89.84 18.75 L 85.16 18.2 L 83.91 20.09 L 79.95 19.83 L 75.83 20.24 L 75.7 16.77 L 71.94 11.34 L 63.84 12.18 L 59.05 9.55 L 51.07 8.81 L 47.67 7.25 L 42.07 5.6 L 38.2 4.97 L 33.44 4.51 L 25.79 4.23 Z";
const RIVNE_CITY = { x: 38.5, y: 62 };
// Райцентри / міста області — вузли регіональної доменної мережі.
const RIVNE_TOWNS = [
  { x: 44, y: 17, uk: 'Дубровиця', en: 'Dubrovytsia' },
  { x: 52, y: 30, uk: 'Сарни', en: 'Sarny' },
  { x: 62, y: 40, uk: 'Рокитне', en: 'Rokytne' },
  { x: 47, y: 50, uk: 'Костопіль', en: 'Kostopil' },
  { x: 56, y: 55, uk: 'Березне', en: 'Berezne' },
  { x: 30, y: 70, uk: 'Дубно', en: 'Dubno' },
  { x: 47, y: 73, uk: 'Острог', en: 'Ostroh' },
  { x: 24, y: 85, uk: 'Радивилів', en: 'Radyvyliv' },
];
const RivneMap = ({ lang }) => (
  <svg viewBox="0 0 100 100" role="img" aria-label={lang === 'uk' ? 'Карта Рівненської області з доменною мережею' : 'Map of Rivne Oblast with the domain network'} className="rift-oblast">
    <defs>
      <pattern id="rift-oblast-grid" width="5" height="5" patternUnits="userSpaceOnUse">
        <circle cx="0.7" cy="0.7" r="0.5" fill="var(--rb-blue)" opacity="0.12" />
      </pattern>
    </defs>
    <path d={RIVNE_OBLAST_PATH} className="rift-oblast__shape" />
    <path d={RIVNE_OBLAST_PATH} fill="url(#rift-oblast-grid)" stroke="none" />
    {/* регіональна доменна мережа: лінії від райцентрів до Рівного-хабу */}
    {RIVNE_TOWNS.map((c, i) => (
      <line key={'l' + i} x1={RIVNE_CITY.x} y1={RIVNE_CITY.y} x2={c.x} y2={c.y} className="rift-oblast__link" />
    ))}
    {RIVNE_TOWNS.map((c, i) => (
      <circle key={'c' + i} cx={c.x} cy={c.y} r="1.3" className="rift-oblast__town" />
    ))}
    <g className="rift-oblast__pin">
      <circle cx={RIVNE_CITY.x} cy={RIVNE_CITY.y} r="6" className="rift-oblast__halo" />
      <circle cx={RIVNE_CITY.x} cy={RIVNE_CITY.y} r="2.6" className="rift-oblast__dot" />
    </g>
    <text x={RIVNE_CITY.x + 5.5} y={RIVNE_CITY.y + 1.6} className="rift-oblast__lbl">{lang === 'uk' ? 'Рівне' : 'Rivne'}</text>
  </svg>
);

// AnycastDiagram — anycast = a request from anywhere reaches the NEAREST node
// with minimal latency. Inbound arrows from users → closest PoP; same zones everywhere.
const AnycastDiagram = ({ lang }) => {
  const NAVY = '#1f3a76', GOLD = '#c9a227';
  const popY = 250;
  const pops = [
    { x: 120, ua: 1, uk: 'Рівне', en: 'Rivne' },
    { x: 250, ua: 1, uk: 'Київ', en: 'Kyiv' },
    { x: 380, ua: 1, uk: 'Львів', en: 'Lviv' },
    { x: 520, ua: 0, uk: 'Варшава', en: 'Warsaw' },
    { x: 650, ua: 0, uk: 'Франкфурт', en: 'Frankfurt' },
    { x: 780, ua: 0, uk: 'Амстердам', en: 'Amsterdam' },
  ];
  const userY = 70;
  const users = [
    { x: 250, uk: 'Запит · Київ', en: 'Query · Kyiv', target: 1, ms: '6' },
    { x: 520, uk: 'Запит · Варшава', en: 'Query · Warsaw', target: 3, ms: '9' },
    { x: 780, uk: 'Запит · Амстердам', en: 'Query · Amsterdam', target: 5, ms: '4' },
  ];
  return (
    <svg viewBox="0 0 900 430" role="img"
         aria-label={lang === 'uk' ? 'Схема anycast: запит потрапляє на найближчий вузол' : 'Anycast diagram: a query reaches the nearest node'}>
      <defs>
        <pattern id="rift-grid" width="26" height="26" patternUnits="userSpaceOnUse">
          <circle cx="1.3" cy="1.3" r="1.3" fill="var(--rb-ink)" opacity="0.05" />
        </pattern>
        <marker id="rift-arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
          <path d="M0 0 L10 5 L0 10 z" fill={GOLD} />
        </marker>
      </defs>
      <rect x="0" y="0" width="900" height="430" fill="url(#rift-grid)" />

      {/* network backbone — every node carries the same zones */}
      <line x1={pops[0].x} y1={popY} x2={pops[pops.length - 1].x} y2={popY} stroke={NAVY} strokeOpacity="0.22" strokeWidth="1.4" />

      {/* inbound: each user routed to its NEAREST node */}
      {users.map((u, i) => {
        const p = pops[u.target];
        const my = (userY + popY) / 2;
        return (
          <g key={'u' + i}>
            <path d={`M${u.x} ${userY + 14} C ${u.x} ${my}, ${p.x} ${my}, ${p.x} ${popY - 16}`}
              fill="none" stroke={GOLD} strokeWidth="1.8" markerEnd="url(#rift-arrow)" />
            <circle cx={u.x} cy={userY} r="6" fill="var(--rb-ink)" />
            <text x={u.x} y={userY - 14} textAnchor="middle" fontFamily="var(--rb-font-mono)" fontSize="12" fill="var(--rb-ink)">{lang === 'uk' ? u.uk : u.en}</text>
            <g transform={`translate(${(u.x + p.x) / 2}, ${my})`}>
              <rect x="-30" y="-12" width="60" height="24" rx="12" fill="var(--rb-paper)" stroke={GOLD} strokeWidth="1" />
              <text x="0" y="4" textAnchor="middle" fontFamily="var(--rb-font-mono)" fontSize="12" fontWeight="600" fill={NAVY}>{'< ' + u.ms + ' ms'}</text>
            </g>
          </g>
        );
      })}

      {/* PoP nodes — each a full replica of the zones */}
      {pops.map((p, i) => {
        const col = p.ua ? GOLD : NAVY;
        return (
          <g key={'p' + i}>
            <circle cx={p.x} cy={popY} r="14" fill={col} opacity="0.1" className="rift-pop__halo" />
            <circle cx={p.x} cy={popY} r="9" fill="var(--rb-paper)" stroke={col} strokeWidth="1.8" />
            <circle cx={p.x} cy={popY} r="3.6" fill={col} />
            <text x={p.x} y={popY + 30} textAnchor="middle" fontFamily="var(--rb-font-mono)" fontSize="12" fill="var(--rb-ink)">{lang === 'uk' ? p.uk : p.en}</text>
          </g>
        );
      })}

      {/* zones replicated note */}
      <g transform={`translate(450, ${popY + 64})`}>
        <text textAnchor="middle" fontFamily="var(--rb-font-mono)" fontSize="12" fill="var(--rb-muted)">
          {lang === 'uk' ? 'кожен вузол — повна копія зон ' : 'every node — a full replica of '}
          <tspan fill={NAVY} fontWeight="600">rivne.ua · rv.ua</tspan>
        </text>
      </g>

      {/* legend */}
      <g transform="translate(330, 400)">
        <circle cx="6" cy="-4" r="5" fill={GOLD} />
        <text x="18" y="0" fontFamily="var(--rb-font-mono)" fontSize="12" fill="var(--rb-muted)">{lang === 'uk' ? 'вузли в Україні' : 'nodes in Ukraine'}</text>
        <circle cx="180" cy="-4" r="5" fill={NAVY} />
        <text x="192" y="0" fontFamily="var(--rb-font-mono)" fontSize="12" fill="var(--rb-muted)">{lang === 'uk' ? 'вузли у світі' : 'nodes worldwide'}</text>
      </g>
    </svg>
  );
};

const TechPage = ({ lang }) => {
  const t = T_TECH[lang];
  const [faqOpen, setFaqOpen] = React.useState(0);
  return (
    <main className="rb-page">
      <section className="rb-pagehead rb-pagehead--whois">
        <div className="rb-eyebrow"><span className="rb-eyebrow__dot" />{t.eyebrow}</div>
        <h1 className="rb-h1 rb-h1--page">
          <span className="rb-h1__a">{t.h1a}</span>
          <span className="rb-h1__b">{t.h1b}</span>
        </h1>
        <p className="rb-lead">{t.sub}</p>
      </section>

      <section className="rb-section" style={{ paddingBottom: 0 }}>
        <div className="rift-prose">
          <p className="rift-prose__lead">{t.lead}</p>
        </div>
      </section>

      <section className="rb-section" style={{ paddingTop: 'clamp(28px,4vw,48px)' }}>
        <div className="rift-anycast">
          <AnycastDiagram lang={lang} />
        </div>
        <p className="rift-anycast__cap">{lang === 'uk'
          ? 'Реєстр і DNS-зони обслуговуються мережею anycast-вузлів у межах України та світу — запит завжди потрапляє на найближчий вузол.'
          : 'The registry and DNS zones are served by an anycast network of nodes in Ukraine and worldwide — every query reaches the nearest node.'}</p>
      </section>

      <section className="rb-section">
        <div className="rb-section__head">
          <h2 className="rb-h2">{t.secTitle}</h2>
          <p className="rb-sub">{t.secSub}</p>
        </div>
        <div className="rb-secgrid">
          {t.security.map((s, i) => (
            <article className="rb-seccard" key={i}>
              <div className="rb-seccard__head">
                <span className="rb-seccard__num">{String(i + 1).padStart(2, '0')}</span>
                <span className="rb-seccard__tag">{s.tag}</span>
              </div>
              <div className="rb-seccard__t">{s.t}</div>
              <div className="rb-seccard__d">{s.d}</div>
            </article>
          ))}
        </div>
      </section>

      <section className="rb-section">
        <div className="rb-section__head">
          <h2 className="rb-h2">{t.partnersTitle}</h2>
          <p className="rb-sub">{t.partnersSub}</p>
        </div>
        <div className="rift-partners">
          {t.partners.map((p, i) => (
            <div className="rift-partner" key={i}>
              <div className="rift-partner__logo"><PartnerMark name={p.name} /></div>
              <div className="rift-partner__role">{p.role}</div>
            </div>
          ))}
        </div>
      </section>

      <section className="rb-section rb-section--alt">
        <div className="rb-section__head">
          <h2 className="rb-h2">{t.flowTitle}</h2>
        </div>
        <div className="rb-flow">
          {t.flow.map((f, i) => (
            <div className="rb-flow__step" key={i}>
              <div className="rb-flow__n">{String(i + 1).padStart(2, '0')}</div>
              <div className="rb-flow__t">{f.t}</div>
              <div className="rb-flow__d">{f.d}</div>
              {i < t.flow.length - 1 && <div className="rb-flow__line" aria-hidden>→</div>}
            </div>
          ))}
        </div>
      </section>

      <section className="rb-section">
        <div className="rb-section__head">
          <h2 className="rb-h2">{t.statusTitle}</h2>
        </div>
        <LiveStatus lang={lang} fb={{
          live: lang === 'uk' ? 'Усі системи в нормі' : 'All systems operational',
          uptime: '99.98%',
          cap: lang === 'uk' ? 'доступність реєстру за 90 днів' : 'registry availability over 90 days',
          cells: [
            { n: '3', l: lang === 'uk' ? 'глобальних сервісів DNS' : 'global DNS services', sub: 'rivne.ua · rv.ua' },
            { n: '< 25 ms', l: lang === 'uk' ? 'медіанна відповідь DNS' : 'median DNS response', sub: lang === 'uk' ? 'у межах України' : 'within Ukraine' },
            { n: 'DNSSEC', l: lang === 'uk' ? 'підпис усіх зон' : 'all zones signed', sub: lang === 'uk' ? 'з 2012' : 'since 2012' },
            { n: 'IPv4 / IPv6', l: lang === 'uk' ? 'подвійний стек' : 'dual stack', sub: 'dual-stack' },
          ],
        }} />
      </section>
    </main>
  );
};
window.TechPage = TechPage;
