xander 1 周之前
父节点
当前提交
8d97d6722d
共有 72 个文件被更改,包括 3595 次插入 和 2033 次删除
  1. 8 1
      astro.config.mjs
  2. 二进制
      public/videos/hero-background.mp4
  3. 二进制
      public/videos/tg-106.mp4
  4. 二进制
      public/videos/tg-107.mp4
  5. 二进制
      public/videos/tg-41.mp4
  6. 二进制
      public/videos/tg-50.mp4
  7. 二进制
      public/videos/tg-51.mp4
  8. 二进制
      public/videos/tg-91.mp4
  9. 19 1
      scripts/fetch-telegram.mjs
  10. 21 14
      src/components/CTAForm.astro
  11. 26 24
      src/components/Footer.astro
  12. 44 16
      src/components/Header.astro
  13. 63 12
      src/components/TelegramWidget.astro
  14. 200 0
      src/components/pages/AboutPage.astro
  15. 209 0
      src/components/pages/DiggerPage.astro
  16. 57 0
      src/components/pages/DiggerslopeUpdatesPage.astro
  17. 172 0
      src/components/pages/EducationPage.astro
  18. 111 0
      src/components/pages/EmergencyCarePage.astro
  19. 192 0
      src/components/pages/GeodesyPage.astro
  20. 308 0
      src/components/pages/HomePage.astro
  21. 88 0
      src/components/pages/JointExplorerPage.astro
  22. 138 0
      src/components/pages/MagicorePage.astro
  23. 145 0
      src/components/pages/NurPage.astro
  24. 59 0
      src/components/pages/PersonalDataPage.astro
  25. 122 0
      src/components/pages/ProrockFeaturesPage.astro
  26. 199 0
      src/components/pages/ProrockPage.astro
  27. 57 0
      src/components/pages/ProrockUpdatesPage.astro
  28. 100 0
      src/components/pages/ScientiaJointsPage.astro
  29. 98 0
      src/components/pages/SubscribePage.astro
  30. 37 17
      src/data/digger-updates.ts
  31. 303 150
      src/data/personal-data.ts
  32. 117 57
      src/data/products.ts
  33. 145 74
      src/data/prorock-updates.ts
  34. 59 27
      src/data/publications.ts
  35. 192 94
      src/data/services.ts
  36. 50 23
      src/data/site.ts
  37. 0 0
      src/data/telegram-news.json
  38. 106 0
      src/i18n.ts
  39. 12 4
      src/layouts/Base.astro
  40. 26 5
      src/pages/404.astro
  41. 2 141
      src/pages/about.astro
  42. 2 172
      src/pages/digger.astro
  43. 2 32
      src/pages/diggerslope_updates.astro
  44. 2 104
      src/pages/education.astro
  45. 2 65
      src/pages/emergency_care.astro
  46. 2 113
      src/pages/geodesy.astro
  47. 2 240
      src/pages/index.astro
  48. 2 64
      src/pages/joint_explorer.astro
  49. 2 100
      src/pages/magicore.astro
  50. 2 92
      src/pages/nur.astro
  51. 2 36
      src/pages/personal_data.astro
  52. 2 128
      src/pages/prorock.astro
  53. 2 32
      src/pages/prorock_updates.astro
  54. 2 62
      src/pages/prorockfeatures.astro
  55. 5 0
      src/pages/ru/about.astro
  56. 5 0
      src/pages/ru/digger.astro
  57. 5 0
      src/pages/ru/diggerslope_updates.astro
  58. 5 0
      src/pages/ru/education.astro
  59. 5 0
      src/pages/ru/emergency_care.astro
  60. 5 0
      src/pages/ru/geodesy.astro
  61. 5 0
      src/pages/ru/index.astro
  62. 5 0
      src/pages/ru/joint_explorer.astro
  63. 5 0
      src/pages/ru/magicore.astro
  64. 5 0
      src/pages/ru/nur.astro
  65. 5 0
      src/pages/ru/personal_data.astro
  66. 5 0
      src/pages/ru/prorock.astro
  67. 5 0
      src/pages/ru/prorock_updates.astro
  68. 5 0
      src/pages/ru/prorockfeatures.astro
  69. 5 0
      src/pages/ru/scientiajoints.astro
  70. 5 0
      src/pages/ru/subscribe.astro
  71. 2 69
      src/pages/scientiajoints.astro
  72. 2 64
      src/pages/subscribe.astro

+ 8 - 1
astro.config.mjs

@@ -3,7 +3,14 @@ import { defineConfig } from "astro/config";
 import tailwindcss from "@tailwindcss/vite";
 
 export default defineConfig({
-  site: "https://scientia.ru",
+  site: "https://scientia.tkachenkoalexander.ru",
+  i18n: {
+    defaultLocale: "en",
+    locales: ["en", "ru"],
+    routing: {
+      prefixDefaultLocale: false,
+    },
+  },
   vite: {
     plugins: [tailwindcss()],
   },

二进制
public/videos/hero-background.mp4


二进制
public/videos/tg-106.mp4


二进制
public/videos/tg-107.mp4


二进制
public/videos/tg-41.mp4


二进制
public/videos/tg-50.mp4


二进制
public/videos/tg-51.mp4


二进制
public/videos/tg-91.mp4


+ 19 - 1
scripts/fetch-telegram.mjs

@@ -48,7 +48,7 @@ for (let page = 0; page < MAX_PAGES; page++) {
     const photoStyle = $el.find(".tgme_widget_message_photo_wrap").first().attr("style") || "";
     let photo = photoStyle.match(/url\('([^']+)'\)/)?.[1]?.split("?")[0] || "";
     const video = $el.find(".tgme_widget_message_video_wrap, .tgme_widget_message_video_player").length > 0;
-    // direct mp4 (tokenized URL — expires after a while; re-run fetch-news to refresh)
+    // tokenized CDN url; downloaded to public/videos/ after the scrape (see below)
     const videoSrc = video ? $el.find("video").first().attr("src") || "" : "";
     // video posts carry a full-size preview frame in .tgme_widget_message_video_thumb
     if (video && !photo) {
@@ -70,6 +70,24 @@ for (let page = 0; page < MAX_PAGES; page++) {
 // newest first
 posts.sort((a, b) => b.id - a.id);
 
+// telesco.pe video tokens expire within hours — persist the mp4s locally
+await mkdir("public/videos", { recursive: true });
+for (const post of posts) {
+  if (!post.videoSrc) continue;
+  const res = await fetch(post.videoSrc, { headers: { "User-Agent": UA } });
+  if (!res.ok) {
+    console.log(`video ${post.id}: HTTP ${res.status}, keeping poster only`);
+    post.videoSrc = "";
+    continue;
+  }
+  const buf = Buffer.from(await res.arrayBuffer());
+  const file = `tg-${post.id}.mp4`;
+  await writeFile(path.join("public/videos", file), buf);
+  post.videoSrc = `/videos/${file}`;
+  console.log(`video ${post.id}: saved ${(buf.length / 1e6).toFixed(1)} MB`);
+  await sleep(300);
+}
+
 await mkdir(path.dirname("src/data/telegram-news.json"), { recursive: true });
 await writeFile("src/data/telegram-news.json", JSON.stringify(posts, null, 2));
 console.log(`saved ${posts.length} posts`);

+ 21 - 14
src/components/CTAForm.astro

@@ -1,15 +1,17 @@
 ---
 import { site } from "../data/site";
+import { type Locale, getLocale, localePath, translator } from "../i18n";
 
 interface Props {
   title?: string;
   subtitle?: string;
+  locale?: Locale;
 }
 
-const {
-  title = "Обсудим вашу задачу",
-  subtitle = "Мы свяжемся с вами в течение рабочего дня, чтобы ответить на вопросы и обсудить дальнейший план действий.",
-} = Astro.props;
+const locale = Astro.props.locale ?? getLocale(Astro.url);
+const t = translator(locale);
+const title = Astro.props.title ?? t("cta.title");
+const subtitle = Astro.props.subtitle ?? t("cta.subtitle");
 ---
 
 <section id="contacts" class="scroll-mt-20 bg-night-950 text-white">
@@ -31,10 +33,10 @@ const {
       </div>
 
       <!-- Static hosting: the form composes an email instead of posting to a backend. -->
-      <form id="contact-form" class="space-y-8">
+      <form id="contact-form" data-locale={locale} class="space-y-8">
         <div class="grid gap-8 sm:grid-cols-2">
           <label class="block">
-            <span class="mb-2 block text-xs font-semibold uppercase tracking-widest text-white/50">Имя</span>
+            <span class="mb-2 block text-xs font-semibold uppercase tracking-widest text-white/50">{t("cta.name")}</span>
             <input
               required
               type="text"
@@ -44,7 +46,7 @@ const {
             />
           </label>
           <label class="block">
-            <span class="mb-2 block text-xs font-semibold uppercase tracking-widest text-white/50">Телефон</span>
+            <span class="mb-2 block text-xs font-semibold uppercase tracking-widest text-white/50">{t("cta.phone")}</span>
             <input
               type="tel"
               name="phone"
@@ -64,7 +66,7 @@ const {
           />
         </label>
         <label class="block">
-          <span class="mb-2 block text-xs font-semibold uppercase tracking-widest text-white/50">Сообщение</span>
+          <span class="mb-2 block text-xs font-semibold uppercase tracking-widest text-white/50">{t("cta.message")}</span>
           <textarea
             name="message"
             rows="3"
@@ -75,12 +77,12 @@ const {
             type="submit"
             class="group flex items-center gap-3 rounded-full bg-accent-300 py-3 pl-8 pr-3 font-semibold text-night-950 transition-colors hover:bg-accent-200"
           >
-            Отправить
+            {t("cta.submit")}
             <span class="flex h-8 w-8 items-center justify-center rounded-full bg-night-950 text-accent-300" aria-hidden="true">→</span>
           </button>
           <p class="max-w-xs text-xs leading-relaxed text-white/40">
-            Нажимая на кнопку, вы даёте согласие на обработку персональных данных и соглашаетесь с
-            <a href="/personal_data" class="underline hover:text-white/70">политикой конфиденциальности</a>.
+            {t("cta.consent")}
+            <a href={localePath(locale, "/personal_data")} class="underline hover:text-white/70">{t("cta.consentLink")}</a>.
           </p>
         </div>
       </form>
@@ -92,17 +94,22 @@ const {
   const form = document.getElementById("contact-form") as HTMLFormElement | null;
   form?.addEventListener("submit", (e) => {
     e.preventDefault();
+    const locale = form.dataset.locale === "ru" ? "ru" : "en";
+    const labels =
+      locale === "ru"
+        ? { name: "Имя", phone: "Телефон", subject: "Запрос с сайта scientia.ru" }
+        : { name: "Name", phone: "Phone", subject: "Website inquiry — scientia.ru" };
     const data = new FormData(form);
     const body = [
-      `Имя: ${data.get("name") ?? ""}`,
-      `Телефон: ${data.get("phone") ?? ""}`,
+      `${labels.name}: ${data.get("name") ?? ""}`,
+      `${labels.phone}: ${data.get("phone") ?? ""}`,
       `E-mail: ${data.get("email") ?? ""}`,
       "",
       `${data.get("message") ?? ""}`,
     ].join("\n");
     window.location.href =
       "mailto:info@scientia.ru?subject=" +
-      encodeURIComponent("Запрос с сайта scientia.ru") +
+      encodeURIComponent(labels.subject) +
       "&body=" +
       encodeURIComponent(body);
   });

+ 26 - 24
src/components/Footer.astro

@@ -1,58 +1,60 @@
 ---
 import { site } from "../data/site";
 import { products } from "../data/products";
+import { type Locale, getLocale, localePath, translator } from "../i18n";
 import Logo from "./Logo.astro";
 
+const locale = Astro.props.locale ?? getLocale(Astro.url);
+const t = translator(locale);
+const lp = (path: string) => localePath(locale, path);
 const year = new Date().getFullYear();
+const address = locale === "ru" ? site.addressRu : site.address;
 ---
 
 <footer class="border-t border-white/10 bg-night-950 text-white">
   <div class="mx-auto max-w-[1400px] px-5 py-16 sm:px-8 lg:py-20">
     <div class="grid gap-12 lg:grid-cols-[1.4fr_1fr_1fr_1.3fr]">
       <div>
-        <a href="/" class="flex items-center gap-3" aria-label={site.name}>
+        <a href={lp("/")} class="flex items-center gap-3" aria-label={site.name}>
           <Logo class="h-12 w-auto" />
           <span class="text-2xl font-medium tracking-tight" style="font-family: var(--font-display)">Scientia</span>
         </a>
-        <p class="mt-5 max-w-xs text-sm leading-relaxed text-white/50">{site.tagline}.</p>
-        <p class="mt-8 text-xs leading-relaxed text-white/35">
-          Лицензия на производство маркшейдерских работ<br />
-          Член СРО в области инженерных изысканий
-        </p>
+        <p class="mt-5 max-w-xs text-sm leading-relaxed text-white/50">{site.tagline[locale]}.</p>
+        <p class="mt-8 text-xs leading-relaxed text-white/35" set:html={t("footer.license")} />
       </div>
 
-      <nav aria-label="Разработки">
-        <h3 class="text-xs font-semibold uppercase tracking-[0.25em] text-white/40">Разработки</h3>
+      <nav aria-label={t("header.products")}>
+        <h3 class="text-xs font-semibold uppercase tracking-[0.25em] text-white/40">{t("header.products")}</h3>
         <ul class="mt-5 space-y-3 text-sm">
-          {products.map((p) => (
+          {products[locale].map((p) => (
             <li>
-              <a href={p.href} class="text-white/75 transition-colors hover:text-accent-300">{p.name}</a>
+              <a href={lp(p.href)} class="text-white/75 transition-colors hover:text-accent-300">{p.name}</a>
             </li>
           ))}
         </ul>
       </nav>
 
-      <nav aria-label="Информация">
-        <h3 class="text-xs font-semibold uppercase tracking-[0.25em] text-white/40">Информация</h3>
+      <nav aria-label={t("header.information")}>
+        <h3 class="text-xs font-semibold uppercase tracking-[0.25em] text-white/40">{t("header.information")}</h3>
         <ul class="mt-5 space-y-3 text-sm">
-          <li><a href="/about" class="text-white/75 transition-colors hover:text-accent-300">Об организации</a></li>
-          <li><a href="/about#publications" class="text-white/75 transition-colors hover:text-accent-300">Публикации</a></li>
-          <li><a href="/about#licenses" class="text-white/75 transition-colors hover:text-accent-300">Лицензии</a></li>
-          <li><a href="/education" class="text-white/75 transition-colors hover:text-accent-300">Образование</a></li>
-          <li><a href="/subscribe" class="text-white/75 transition-colors hover:text-accent-300">Рассылка</a></li>
+          <li><a href={lp("/about")} class="text-white/75 transition-colors hover:text-accent-300">{t("footer.about")}</a></li>
+          <li><a href={lp("/about#publications")} class="text-white/75 transition-colors hover:text-accent-300">{t("footer.publications")}</a></li>
+          <li><a href={lp("/about#licenses")} class="text-white/75 transition-colors hover:text-accent-300">{t("footer.licenses")}</a></li>
+          <li><a href={lp("/education")} class="text-white/75 transition-colors hover:text-accent-300">{t("footer.education")}</a></li>
+          <li><a href={lp("/subscribe")} class="text-white/75 transition-colors hover:text-accent-300">{t("footer.subscribe")}</a></li>
           <li>
             <a href={site.external.wiki} target="_blank" rel="noopener" class="text-white/75 transition-colors hover:text-accent-300">Wiki ↗</a>
           </li>
           <li>
-            <a href={site.external.blog} target="_blank" rel="noopener" class="text-white/75 transition-colors hover:text-accent-300">Блог ↗</a>
+            <a href={site.external.blog} target="_blank" rel="noopener" class="text-white/75 transition-colors hover:text-accent-300">{t("footer.blog")} ↗</a>
           </li>
         </ul>
       </nav>
 
       <div>
-        <h3 class="text-xs font-semibold uppercase tracking-[0.25em] text-white/40">Контакты</h3>
+        <h3 class="text-xs font-semibold uppercase tracking-[0.25em] text-white/40">{t("header.contacts")}</h3>
         <ul class="mt-5 space-y-3 text-sm text-white/75">
-          <li>{site.address}</li>
+          <li>{address}</li>
           <li>
             <a href={site.phoneHref} class="font-medium text-white transition-colors hover:text-accent-300">{site.phone}</a>
           </li>
@@ -62,14 +64,14 @@ const year = new Date().getFullYear();
           <li class="text-white/40">ИНН {site.inn} · КПП {site.kpp}</li>
         </ul>
         <div class="mt-6 flex flex-wrap gap-2">
-          {site.telegram.map((t) => (
+          {site.telegram.map((tg) => (
             <a
-              href={t.href}
+              href={tg.href}
               target="_blank"
               rel="noopener"
               class="rounded-full border border-white/20 px-4 py-1.5 text-xs text-white/75 transition-colors hover:border-accent-300 hover:text-accent-300"
             >
-              {t.name}
+              {locale === "en" && tg.nameEn ? tg.nameEn : tg.name}
             </a>
           ))}
         </div>
@@ -80,7 +82,7 @@ const year = new Date().getFullYear();
   <div class="border-t border-white/10">
     <div class="mx-auto flex max-w-[1400px] flex-col gap-2 px-5 py-6 text-xs text-white/35 sm:flex-row sm:items-center sm:justify-between sm:px-8">
       <p>© {year} {site.legalName}</p>
-      <p><a href="/personal_data" class="transition-colors hover:text-white">Политика обработки персональных данных</a></p>
+      <p><a href={lp("/personal_data")} class="transition-colors hover:text-white">{t("footer.privacy")}</a></p>
     </div>
   </div>
 </footer>

+ 44 - 16
src/components/Header.astro

@@ -1,16 +1,28 @@
 ---
 import { nav, site } from "../data/site";
+import { type Locale, getLocale, localePath, otherLocalePath, translator } from "../i18n";
 import Logo from "./Logo.astro";
 
 interface Props {
   /** Float transparently over a full-bleed hero (home page) */
   floating?: boolean;
+  locale?: Locale;
 }
 
 const { floating = false } = Astro.props;
+const locale = Astro.props.locale ?? getLocale(Astro.url);
+const t = translator(locale);
+const lp = (path: string) => localePath(locale, path);
+const items = nav[locale].map((item) => ({
+  ...item,
+  href: lp(item.href),
+  children: item.children?.map((child) => ({ ...child, href: lp(child.href) })),
+}));
 const current = Astro.url.pathname;
 const isActive = (href: string) =>
-  !href.startsWith("http") && (href === current || (href !== "/" && current.startsWith(href)));
+  !href.startsWith("http") && (href === current || (href !== "/" && !href.startsWith("/ru") && current.startsWith(href)) || (href.startsWith("/ru") && current.startsWith(href)));
+const switchHref = otherLocalePath(locale, Astro.url.pathname);
+const switchLabel = locale === "en" ? "RU" : "EN";
 ---
 
 <header
@@ -22,12 +34,12 @@ const isActive = (href: string) =>
   ]}
 >
   <div class="mx-auto flex h-20 max-w-[1400px] items-center justify-between gap-4 px-5 sm:px-8">
-    <a href="/" class="flex shrink-0 items-center gap-3" aria-label={site.name}>
+    <a href={lp("/")} class="flex shrink-0 items-center gap-3" aria-label={site.name}>
       <Logo class="h-30 w-auto" />
     </a>
 
-    <nav class="hidden items-center gap-1 lg:flex" aria-label="Основная навигация">
-      {nav.map((item) => (
+    <nav class="hidden items-center gap-1 lg:flex" aria-label={t("nav.primary")}>
+      {items.map((item) => (
         <div class="group relative" data-dropdown={item.children ? true : undefined}>
           <a
             href={item.href}
@@ -63,24 +75,34 @@ const isActive = (href: string) =>
       ))}
     </nav>
 
-    <a
-      href="/about#contacts"
-      class="hidden items-center gap-2 rounded-full bg-accent-300 px-6 py-2.5 text-sm font-semibold text-night-950 transition-colors hover:bg-accent-200 lg:flex"
-    >
-      Связаться
-      <span aria-hidden="true">→</span>
-    </a>
+    <div class="hidden items-center gap-3 lg:flex">
+      <a
+        href={switchHref}
+        class="rounded-full border border-white/30 px-4 py-2 text-sm font-semibold text-white/85 transition-colors hover:border-accent-300 hover:text-accent-300"
+        aria-label={locale === "en" ? "Switch to Russian" : "Переключить на английский"}
+        hreflang={locale === "en" ? "ru" : "en"}
+      >
+        {switchLabel}
+      </a>
+      <a
+        href={lp("/about#contacts")}
+        class="flex items-center gap-2 rounded-full bg-accent-300 px-6 py-2.5 text-sm font-semibold text-night-950 transition-colors hover:bg-accent-200"
+      >
+        {t("nav.contact")}
+        <span aria-hidden="true">→</span>
+      </a>
+    </div>
 
     <!-- Mobile menu -->
     <details class="relative lg:hidden">
       <summary class="flex cursor-pointer list-none items-center rounded-full p-2 hover:bg-white/10 [&::-webkit-details-marker]:hidden">
-        <span class="sr-only">Меню</span>
+        <span class="sr-only">{t("nav.menu")}</span>
         <svg class="h-7 w-7" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
           <path stroke-linecap="round" d="M4 6h16M4 12h16M4 18h16" />
         </svg>
       </summary>
       <div class="absolute right-0 top-full mt-2 max-h-[80vh] w-72 overflow-y-auto bg-night-950/95 p-3 text-white shadow-2xl backdrop-blur">
-        {nav.map((item) => (
+        {items.map((item) => (
           <div>
             <a
               href={item.href}
@@ -97,10 +119,16 @@ const isActive = (href: string) =>
           </div>
         ))}
         <a
-          href="/about#contacts"
-          class="mt-3 flex items-center justify-center gap-2 rounded-full bg-accent-300 px-5 py-3 text-sm font-semibold text-night-950 hover:bg-accent-200"
+          href={switchHref}
+          class="mt-2 block rounded-full border border-white/30 px-5 py-2.5 text-center text-sm font-semibold text-white/85 hover:border-accent-300 hover:text-accent-300"
+        >
+          {switchLabel}
+        </a>
+        <a
+          href={lp("/about#contacts")}
+          class="mt-2 flex items-center justify-center gap-2 rounded-full bg-accent-300 px-5 py-3 text-sm font-semibold text-night-950 hover:bg-accent-200"
         >
-          Связаться <span aria-hidden="true">→</span>
+          {t("nav.contact")} <span aria-hidden="true">→</span>
         </a>
       </div>
     </details>

+ 63 - 12
src/components/TelegramWidget.astro

@@ -1,9 +1,16 @@
 ---
 // Telegram-style chat window with the latest posts from t.me/scientia_ru.
-// Posts are fetched at build time by `npm run fetch-news`.
+// Posts are fetched at build time by `npm run fetch-news`. Post content stays
+// in Russian (live channel feed); only the widget chrome is localized.
 import telegramNews from "../data/telegram-news.json";
+import { type Locale, getLocale, translator } from "../i18n";
 
-const fmt = new Intl.DateTimeFormat("ru-RU", { day: "numeric", month: "long", hour: "2-digit", minute: "2-digit" });
+interface Props {
+  locale?: Locale;
+}
+const locale = Astro.props.locale ?? getLocale(Astro.url);
+const t = translator(locale);
+const fmt = new Intl.DateTimeFormat(locale === "ru" ? "ru-RU" : "en-GB", { day: "numeric", month: "long", hour: "2-digit", minute: "2-digit" });
 ---
 
 <div id="tg-widget" class="w-[380px]">
@@ -15,7 +22,7 @@ const fmt = new Intl.DateTimeFormat("ru-RU", { day: "numeric", month: "long", ho
         <p class="truncate text-sm font-semibold text-night-950">Scientia</p>
         <p class="flex items-center gap-1.5 text-xs text-slate-400">
           <span class="inline-block h-1.5 w-1.5 rounded-full bg-emerald-500"></span>
-          канал · @scientia_ru
+          {t("tg.channel")} · @scientia_ru
         </p>
       </div>
     </div>
@@ -30,12 +37,12 @@ const fmt = new Intl.DateTimeFormat("ru-RU", { day: "numeric", month: "long", ho
             )}
             {post.video && post.videoSrc ? (
               <video
-                controls
-                preload="none"
+                muted
                 playsinline
+                preload="none"
                 poster={post.photo || undefined}
                 src={post.videoSrc}
-                class="mb-2 w-full rounded-lg bg-night-950"
+                class="mb-2 w-full cursor-pointer rounded-lg bg-night-950"
               ></video>
             ) : post.video && post.photo ? (
               <span class="relative mb-2 block overflow-hidden rounded-lg">
@@ -53,7 +60,7 @@ const fmt = new Intl.DateTimeFormat("ru-RU", { day: "numeric", month: "long", ho
                 <svg class="h-8 w-8" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
                   <path d="M8 5.14v14l11-7-11-7z" />
                 </svg>
-                Видео
+                {t("tg.video")}
               </span>
             ) : null}
             {post.text && (
@@ -61,14 +68,14 @@ const fmt = new Intl.DateTimeFormat("ru-RU", { day: "numeric", month: "long", ho
                 <Fragment set:html={post.text} />
               </div>
             )}
-            {!post.text && !(post.photo || post.video) && <p class="text-[13px] text-slate-500">Фото</p>}
+            {!post.text && !(post.photo || post.video) && <p class="text-[13px] text-slate-500">{t("tg.photo")}</p>}
             <a
               href={post.link}
               target="_blank"
               rel="noopener"
               class="mt-1 block text-right text-[11px] text-slate-400 transition-colors hover:text-[#2AABEE]"
             >
-              {post.datetime ? fmt.format(new Date(post.datetime)) : "Открыть пост"}
+              {post.datetime ? fmt.format(new Date(post.datetime)) : t("tg.openPost")}
             </a>
           </div>
         ))}
@@ -77,7 +84,7 @@ const fmt = new Intl.DateTimeFormat("ru-RU", { day: "numeric", month: "long", ho
           data-tg-more
           class="mx-auto block rounded-full bg-white px-5 py-2 text-xs font-semibold text-[#2AABEE] shadow-sm transition-colors hover:bg-[#2AABEE] hover:text-white"
         >
-          Показать ещё
+          {t("tg.more")}
         </button>
       </div>
       <!-- soft fade over the scroll area -->
@@ -91,7 +98,7 @@ const fmt = new Intl.DateTimeFormat("ru-RU", { day: "numeric", month: "long", ho
       rel="noopener"
       class="group flex items-center justify-center gap-2 bg-[#2AABEE] px-4 py-3 text-sm font-semibold text-white transition-colors hover:bg-[#229ED9]"
     >
-      Перейти в телеграм
+      {t("tg.open")}
       <svg class="h-4 w-4 transition-transform group-hover:translate-x-0.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
         <path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5L21 12l-7.5 7.5M21 12H3" />
       </svg>
@@ -149,7 +156,51 @@ const fmt = new Intl.DateTimeFormat("ru-RU", { day: "numeric", month: "long", ho
   const more = document.querySelector("[data-tg-more]");
   more?.addEventListener("click", () => {
     const hidden = [...document.querySelectorAll("#tg-widget .tg-bubble.hidden")];
-    hidden.slice(0, 8).forEach((el) => el.classList.remove("hidden"));
+    const chunk = hidden.slice(0, 8);
+    chunk.forEach((el) => el.classList.remove("hidden"));
+    chunk.forEach((el) => el.querySelectorAll("video").forEach(wireVideo));
     if (hidden.length <= 8) more.remove();
   });
+
+  // Videos: start buffering before they enter the visible area (preload="none"
+  // is upgraded on approach), then autoplay muted while in view and pause when
+  // scrolled away. Browsers only allow autoplay without a gesture when muted.
+  // No native controls — like Telegram, click toggles sound instead.
+  const feed = document.querySelector(".tg-body");
+  const allVideos = () => [...document.querySelectorAll("#tg-widget video")];
+
+  const preloader = new IntersectionObserver(
+    (entries, obs) => {
+      for (const e of entries) {
+        if (!e.isIntersecting) continue;
+        e.target.preload = "auto";
+        e.target.load();
+        obs.unobserve(e.target);
+      }
+    },
+    { root: feed, rootMargin: "600px 0px 600px 0px" }
+  );
+
+  const player = new IntersectionObserver(
+    (entries) => {
+      for (const e of entries) {
+        if (e.isIntersecting) {
+          for (const v of allVideos()) if (v !== e.target) v.pause(); // one at a time
+          e.target.play().catch(() => {});
+        } else {
+          e.target.pause();
+        }
+      }
+    },
+    { root: feed, threshold: 0.5 }
+  );
+
+  function wireVideo(video) {
+    preloader.observe(video);
+    player.observe(video);
+    video.addEventListener("click", () => {
+      video.muted = !video.muted;
+    });
+  }
+  allVideos().forEach(wireVideo);
 </script>

+ 200 - 0
src/components/pages/AboutPage.astro

@@ -0,0 +1,200 @@
+---
+import Base from "../../layouts/Base.astro";
+import PageHero from "../PageHero.astro";
+import { site } from "../../data/site";
+import { publications, licenseDocs } from "../../data/publications";
+import { type Locale, localePath, translator } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+const t = translator(locale);
+const lp = (path: string) => localePath(locale, path);
+
+const copy = {
+  en: {
+    title: "About us",
+    metaDescription: "Scientia is a research and consulting company specializing in mining geomechanics",
+    heroTitle: "About us",
+    heroSubtitle: "Scientia LLC — research and consulting in mining geomechanics",
+    p1: "Scientia specializes in research and consulting in mining geomechanics, offering solutions from the leading edge of science. Scientia carries out comprehensive geomechanical studies of mineral deposits, seeking opportunities to improve the safety and economic efficiency of mining operations.",
+    p2: "The company develops specialized instruments and software, including:",
+    products: [
+      "Magicore — a service for automatic core documentation from photographs",
+      "Digger Slope — software for open-pit slope optimization",
+      "Prorock — numerical modeling software",
+      "the NUR automated extensometer",
+      "the Joint Explorer electronic geological compass",
+    ],
+    scienceTitle: "Science and education",
+    scienceText: "Our team is engaged in science and the growth of the professional community. We share our findings and discoveries in scientific papers, at conferences, in our social media, and in our",
+    scienceTraining: "We also provide",
+    scienceTrainingSuffix: "in our fields of expertise.",
+    publicationsTitle: "Publications",
+    licensesTitle: "Licenses",
+    licensesText:
+      "We are a member of an SRO (self-regulatory organization) for engineering surveys and design documentation, and hold licenses for mine surveying operations and educational activities.",
+    contactsTitle: "Contacts",
+    address: "Address",
+    phoneRegion: "(Russia)",
+    tgHeading: "Our Telegram channels",
+    educationInfo: "Educational organization information",
+    privacy: "Personal data processing policy",
+    wiki: "Wiki",
+    trainingLink: "training",
+  },
+  ru: {
+    title: "Об организации",
+    metaDescription: "Компания Scientia специализируется на научных исследованиях и консалтинге в сфере горной геомеханики",
+    heroTitle: "Об организации",
+    heroSubtitle: "ООО «Скиентия» — научные исследования и консалтинг в сфере горной геомеханики",
+    p1: "Компания Scientia специализируется на научных исследованиях и консалтинге в сфере горной геомеханики, предлагая решения с передового края науки. Scientia выполняет комплексные геомеханические исследования месторождений, изыскивая возможности для повышения безопасности и экономической эффективности горных работ.",
+    p2: "Компания является разработчиком специализированных приборов и программного обеспечения, такого как:",
+    products: [
+      "сервис для автоматического документирования керна по фото Magicore",
+      "программа для оптимизации бортов карьера Digger Slope",
+      "программа для численного моделирования Prorock",
+      "автоматизированный экстензометр NUR",
+      "электронный горный компас Joint Explorer",
+    ],
+    scienceTitle: "Наука и образование",
+    scienceText: "Наша команда занимается наукой и развитием профессионального сообщества. Делимся своими наработками и открытиями в научных статьях, на конференциях, в своих соцсетях и в нашей",
+    scienceTraining: "Занимаемся",
+    scienceTrainingSuffix: "по направлениям нашей деятельности.",
+    publicationsTitle: "Публикации",
+    licensesTitle: "Лицензии",
+    licensesText:
+      "Мы являемся членом СРО в области инженерных изысканий и подготовки проектной документации, а также имеем лицензию на производство маркшейдерских работ и образовательную деятельность.",
+    contactsTitle: "Контакты",
+    address: "Адрес",
+    phoneRegion: "(Россия)",
+    tgHeading: "Наши Телеграм-каналы",
+    educationInfo: "Сведения об образовательной организации",
+    privacy: "Политика обработки персональных данных",
+    wiki: "Wiki",
+    trainingLink: "обучением",
+  },
+}[locale];
+
+const address = locale === "ru" ? site.addressRu : site.address;
+const pubList = publications[locale];
+const docs = licenseDocs[locale];
+---
+
+<Base title={copy.title} description={copy.metaDescription} locale={locale}>
+  <PageHero title={copy.heroTitle} subtitle={copy.heroSubtitle} />
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
+      <p class="text-lg leading-relaxed text-slate-700">{copy.p1}</p>
+      <p class="mt-5 text-lg leading-relaxed text-slate-700">{copy.p2}</p>
+      <ul class="mt-4 space-y-2 text-lg text-slate-700">
+        {copy.products.map((item) => (
+          <li class="flex gap-3"><span class="mt-3 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />{item}</li>
+        ))}
+      </ul>
+
+      <div class="mt-10 rounded-2xl bg-slate-50 p-6 text-slate-700">
+        <h2 class="text-xl font-semibold text-night-950">{site.legalName}</h2>
+        <p class="mt-2 text-sm leading-relaxed">{copy.address}: {address}<br />ИНН: {site.inn} · КПП: {site.kpp} · ОГРН: {site.ogrn}</p>
+      </div>
+
+      <div class="mt-10 rounded-2xl border border-slate-200 p-6">
+        <h2 class="text-xl font-semibold text-night-950">{copy.scienceTitle}</h2>
+        <p class="mt-3 leading-relaxed text-slate-600">
+          {copy.scienceText}
+          <a href={site.external.wiki} target="_blank" rel="noopener" class="font-medium text-accent-600 hover:text-accent-700">{copy.wiki}</a>.
+          {copy.scienceTraining}
+          <a href={site.external.education} target="_blank" rel="noopener" class="font-medium text-accent-600 hover:text-accent-700">{copy.trainingLink}</a>
+          {copy.scienceTrainingSuffix}
+        </p>
+      </div>
+    </div>
+  </section>
+
+  <!-- Publications -->
+  <section id="publications" class="scroll-mt-20 bg-slate-50">
+    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
+      <h2 class="text-3xl font-bold tracking-tight text-night-950">{copy.publicationsTitle}</h2>
+      <ol class="mt-8 space-y-4">
+        {pubList.map((p, i) => (
+          <li class="text-sm leading-relaxed text-slate-700">
+            <span class="font-semibold text-night-950">{i + 1})</span>{" "}
+            {p.href ? (
+              <a href={p.href} target="_blank" rel="noopener" class="hover:text-accent-700 hover:underline">
+                {p.text}
+              </a>
+            ) : (
+              p.text
+            )}
+          </li>
+        ))}
+      </ol>
+    </div>
+  </section>
+
+  <!-- Licenses -->
+  <section id="licenses" class="scroll-mt-20 bg-white">
+    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
+      <h2 class="text-3xl font-bold tracking-tight text-night-950">{copy.licensesTitle}</h2>
+      <p class="mt-3 text-slate-600">{copy.licensesText}</p>
+      <ul class="mt-8 grid gap-4 sm:grid-cols-2">
+        {docs.map((l) => (
+          <li>
+            <a
+              href={l.href}
+              target="_blank"
+              rel="noopener"
+              class="flex items-center gap-3 rounded-xl border border-slate-200 p-4 text-sm font-medium text-night-900 transition-colors hover:border-accent-400 hover:bg-accent-50"
+            >
+              <svg class="h-6 w-6 shrink-0 text-accent-500" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true">
+                <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" />
+              </svg>
+              {l.title}
+            </a>
+          </li>
+        ))}
+      </ul>
+    </div>
+  </section>
+
+  <!-- Contacts -->
+  <section id="contacts" class="scroll-mt-20 bg-night-900 text-white">
+    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:py-20">
+      <h2 class="text-3xl font-bold tracking-tight sm:text-4xl">{copy.contactsTitle}</h2>
+      <div class="mt-8 grid gap-10 md:grid-cols-2">
+        <div class="space-y-3 text-lg text-slate-300">
+          <p class="text-xl font-semibold text-white">{site.legalName}</p>
+          <p>{copy.address}: {address}</p>
+          <p>ИНН: {site.inn} · КПП: {site.kpp}</p>
+          <p>
+            {locale === "ru" ? "Телефон" : "Phone"}:
+            <a href={site.phoneHref} class="font-semibold text-accent-300 hover:text-accent-200">{site.phone}</a>
+            {copy.phoneRegion}
+          </p>
+          <p>
+            E-mail:
+            <a href={`mailto:${site.email}`} class="font-semibold text-accent-300 hover:text-accent-200">{site.email}</a>
+          </p>
+        </div>
+        <div>
+          <h3 class="font-semibold uppercase tracking-wider text-slate-400">{copy.tgHeading}</h3>
+          <ul class="mt-4 space-y-3">
+            {site.telegram.map((tg) => (
+              <li>
+                <a href={tg.href} target="_blank" rel="noopener" class="text-lg font-medium text-accent-300 hover:text-accent-200">
+                  {locale === "en" && tg.nameEn ? tg.nameEn : tg.name} ↗
+                </a>
+              </li>
+            ))}
+          </ul>
+          <div class="mt-6 space-y-2 text-sm text-slate-400">
+            <p><a href={lp("/personal_data")} class="underline hover:text-white">{copy.privacy}</a></p>
+            <p><a href={lp("/education")} class="underline hover:text-white">{copy.educationInfo}</a></p>
+          </div>
+        </div>
+      </div>
+    </div>
+  </section>
+</Base>

+ 209 - 0
src/components/pages/DiggerPage.astro

@@ -0,0 +1,209 @@
+---
+import Base from "../../layouts/Base.astro";
+import PageHero from "../PageHero.astro";
+import CTAForm from "../CTAForm.astro";
+import { type Locale, localePath } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+const lp = (path: string) => localePath(locale, path);
+
+const copy = {
+  en: {
+    description:
+      "Software for calculating the stability safety factor of open-pit slopes and waste dumps, for assessing actual risks and reducing operating costs in deposit mining",
+    heroSubtitle:
+      "A software suite for slope stability analysis and open-pit slope optimization that assesses actual risks and minimizes operating costs when mining a deposit",
+    updates: "Release history",
+    notice:
+      "All calculations in the software strictly follow the Federal Norms and Rules for Industrial Safety \"Rules for Ensuring the Stability of Pit Slopes, Benches and Dump Slopes\" (2020). The software is certified by ROSSTANDART (registry entry No. 24973 dated 27.11.2024).",
+    kinematicTitle: "Comprehensive kinematic analysis",
+    kinematicIntro:
+      "The software implements comprehensive kinematic slope stability analysis based on deterministic and probabilistic approaches, taking into account:",
+    analysis: [
+      "Pit slope domaining (structural zoning and lithological structure of the deposit)",
+      "Hydrogeological conditions",
+      "Seismic activity of the area",
+      "External loading",
+    ],
+    kinematicText2:
+      "Stability is calculated automatically over a defined grid of slope positions (dip angle and dip azimuth with a given step). The software builds the Kinematic Map of the Pit (3K), which includes the results of calculating:",
+    knnResults: [
+      "Recommended slope configuration: slope angle, berm width",
+      "Slope stability assessment: stability safety factor, failure probability, risk level",
+      "Predicted failure volume",
+    ],
+    detailedTitle: "Detailed calculation settings",
+    detailedP1:
+      "The software provides detailed settings for safety berm calculations based on deterministic and probabilistic approaches, including slope surface properties, berm service life, effective width depending on equipment, statistical trimming of failure volume distributions (cutting off a percentage of the smallest and largest values), and reduction of the rock spread radius based on field data and empirical relationships.",
+    detailedP2:
+      "Beyond the main failure modes (planar, wedge, toppling), the software performs an automated search for tension cracks with detailed configuration and calculation of the critical distance of the tension crack from the slope crest.",
+    detailedP3:
+      "The scale of each failure mode is configured on both sides — minimum and maximum limits for the selected parameters (failure height, width, volume and weight, joint and face lengths), plus filtering of results by failure mode and stability safety factor range.",
+    backTitle: "Back-analysis",
+    backText:
+      "To calibrate calculations against actual mining data, the software implements back-analysis, which extracts practically valuable geomechanical information from recorded failures — cohesion and friction angle data for the weak surfaces of the rock mass.",
+    resultsTitle: "Results for engineering decisions",
+    resultsText:
+      "The Kinematic Map of the Pit can be presented as a 3D pit wireframe, a stereogram, or a table by slope orientation sector. Automatic sub-domaining of the pit by stability and definition of response measures for predicted failures against a defined risk matrix are supported. Empirical analysis based on the Q-Slope, SMR, and MRMR rating classifications and assessment of the overall ultimate stable slope angle using the Fisenko and Hoek methods are implemented. The plan-view curvature of the slope is taken into account.",
+    galleryAlt: "Digger Slope — kinematic map of a pit",
+    docsTitle: "Demo materials",
+    sysreq: "System requirements:",
+    sysreqText:
+      "OS: Windows 11, 10, 7 · CPU clock speed: at least 2 GHz · RAM: at least 4 GB · Free disk space: at least 1 GB · Screen resolution: at least 1024×768.",
+    ctaTitle: "To request a demo version, please fill in the form",
+    ctaSubtitle: "We will contact you and arrange a demonstration of the Digger Slope software suite.",
+  },
+  ru: {
+    description:
+      "Программа для расчётов коэффициента обеспечения устойчивости бортов карьера и отвалов, грунтового откоса уступов, оценки фактических рисков и снижения технологических затрат при отработке месторождения",
+    heroSubtitle:
+      "Программный комплекс для анализа устойчивости и оптимизации бортов карьера, позволяющий оценить фактические риски и минимизировать технологические затраты при отработке месторождения",
+    updates: "История обновлений",
+    notice:
+      "Все расчёты в программе выполняются в строгом соответствии с Федеральными нормами и правилами в области промышленной безопасности «Правила обеспечения устойчивости бортов и уступов карьеров, разрезов и откосов отвалов» 2020 г. Программа сертифицирована в РОССТАНДАРТе (реестровая запись №24973 от 27.11.2024).",
+    kinematicTitle: "Комплексный кинематический анализ",
+    kinematicIntro:
+      "В программе реализован комплексный кинематический анализ устойчивости откосов на основании детерминированного и вероятностного подходов с учётом:",
+    analysis: [
+      "Доменизация бортов карьера (структурное районирование и литологическое строение месторождения)",
+      "Гидрогеологические условия",
+      "Сейсмическая активность района",
+      "Действия внешних нагрузок",
+    ],
+    kinematicText2:
+      "Расчёт устойчивости производится автоматизировано по заданной сетке положения откоса (угол и азимут падения с заданным шагом). Программный комплекс позволяет выполнить построение Кинематической Карты Карьера (3К), включающей в себя результаты расчёта:",
+    knnResults: [
+      "Рекомендованная конфигурация откоса: угол откоса, ширина бермы",
+      "Оценка устойчивости откоса: коэффициент запаса устойчивости, вероятность обрушения, уровень риска",
+      "Прогнозный объём обрушений",
+    ],
+    detailedTitle: "Детальная настройка расчётов",
+    detailedP1:
+      "В программе реализована детальная настройка расчётов предохранительной бермы на основе детерминированного и вероятностного подходов с учётом задания свойств поверхности откоса, срока службы бермы, эффективной ширины в зависимости от оборудования, корректировки статистического распределения объёмов обрушений путём отсечения процента самых малых и самых больших значений, снижения радиуса развала пород за счёт опытных данных и эмпирических зависимостей.",
+    detailedP2:
+      "Помимо основных видов обрушений (плоское, клиновидное, опрокидывание) программа позволяет выполнить автоматизированный поиск трещины отрыва с детальной настройкой и расчётом критичной дистанции трещины отрыва от бровки откоса.",
+    detailedP3:
+      "Масштабируемость каждого вида обрушений задаётся в программе с обеих сторон — ограничения минимальных и максимальных значений выбранных параметров (высота, ширина, объём и вес обрушения, длина трещин и граней), а также фильтр результатов для определённого режима обрушения и диапазона коэффициента запаса устойчивости.",
+    backTitle: "Обратные расчёты",
+    backText:
+      "Для калибровки расчётов по фактическим данным отработки месторождения в программном комплексе реализовано проведение обратных расчётов, которые позволяют извлечь практически ценную геомеханическую информацию из фактов происшедших вывалов — данные о сцеплении и угле внутреннего трения по поверхностям ослабления породного массива.",
+    resultsTitle: "Результаты для инженерных решений",
+    resultsText:
+      "Кинематическая Карта Карьера представима в виде 3D-каркаса карьера, стереограммы или таблицы по секторам ориентации откосов. Предусмотрена автоматическая субдоменизация карьера по устойчивости и определение мер реагирования на прогнозируемые обрушения по заданной матрице рисков. Реализован эмпирический анализ на основе рейтинговых классификаций Q-Slope, SMR, MRMR и оценка предельного устойчивого генерального угла борта по методикам Фисенко и Хука. При расчётах учитывается криволинейность борта в плане.",
+    galleryAlt: "Digger Slope — кинематическая карта карьера",
+    docsTitle: "Демонстрационные материалы",
+    sysreq: "Системные требования:",
+    sysreqText:
+      "Операционная система — Windows 11, 10, 7 · Частота процессора — не ниже 2 GHz · Объём оперативной памяти — не менее 4 Gb · Свободное место на диске — не менее 1 Gb · Разрешение экрана — не менее 1024×768.",
+    ctaTitle: "Для заказа демо-версии, пожалуйста, заполните форму",
+    ctaSubtitle: "Мы свяжемся с вами и организуем демонстрацию программного комплекса Digger Slope.",
+  },
+}[locale];
+
+const gallery = ["/images/_2-1zwkuo.jpg", "/images/1-axy1h6.jpg", "/images/2.jpg", "/images/3.jpg"];
+
+const docs = {
+  en: [
+    { title: "Digger Slope — Booklet (Russia)", href: "https://download.scientia.ru/Digger_Slope/Documents/Digger_Slope_Буклет_(Россия).pdf" },
+    { title: "Digger Slope — Presentation at the MineDigital Minex 2022 competition", href: "https://download.scientia.ru/Digger_Slope/Documents/Digger_Slope_программный_комплекс_для_оптимизации_бортов_карьера_МАЙНЕКС_Россия_2022.pdf" },
+    { title: "Digger Slope — Presentation \"Comprehensive kinematic analysis in the software\"", href: "https://download.scientia.ru/Digger_Slope/Documents/Digger_Slope_Компл" },
+  ],
+  ru: [
+    { title: "Digger Slope — Буклет (Россия)", href: "https://download.scientia.ru/Digger_Slope/Documents/Digger_Slope_Буклет_(Россия).pdf" },
+    { title: "Digger Slope — Презентация на конкурсе МайнДиджитал Майнекс 2022", href: "https://download.scientia.ru/Digger_Slope/Documents/Digger_Slope_программный_комплекс_для_оптимизации_бортов_карьера_МАЙНЕКС_Россия_2022.pdf" },
+    { title: "Digger Slope — Презентация «Комплексный кинематический анализ в программе»", href: "https://download.scientia.ru/Digger_Slope/Documents/Digger_Slope_Компл" },
+  ],
+}[locale];
+---
+
+<Base title="Digger Slope" description={copy.description} locale={locale}>
+  <PageHero title="Digger Slope" subtitle={copy.heroSubtitle} image="/images/20200629_203443.jpg">
+    <a href={lp("/diggerslope_updates")} class="mt-6 inline-block rounded-lg bg-accent-300 px-5 py-2.5 font-semibold text-night-950 transition-colors hover:bg-accent-400">
+      {copy.updates}
+    </a>
+  </PageHero>
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
+      <div class="rounded-2xl border-l-4 border-accent-400 bg-accent-50 p-6 text-sm leading-relaxed text-slate-700">
+        {copy.notice}
+      </div>
+
+      <h2 class="mt-12 text-3xl font-bold tracking-tight text-night-950">{copy.kinematicTitle}</h2>
+      <p class="mt-4 leading-relaxed text-slate-700">{copy.kinematicIntro}</p>
+      <ul class="mt-4 space-y-2">
+        {copy.analysis.map((a) => (
+          <li class="flex gap-3 text-slate-700">
+            <span class="mt-2.5 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
+            {a}
+          </li>
+        ))}
+      </ul>
+      <p class="mt-4 leading-relaxed text-slate-700">{copy.kinematicText2}</p>
+      <ul class="mt-4 space-y-2">
+        {copy.knnResults.map((a) => (
+          <li class="flex gap-3 text-slate-700">
+            <span class="mt-2.5 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
+            {a}
+          </li>
+        ))}
+      </ul>
+    </div>
+  </section>
+
+  <section class="bg-slate-50">
+    <div class="mx-auto grid max-w-7xl gap-8 px-4 py-16 sm:px-6 lg:grid-cols-2">
+      <div class="rounded-2xl border border-slate-200 bg-white p-8">
+        <h2 class="text-2xl font-bold text-night-950">{copy.detailedTitle}</h2>
+        <p class="mt-4 text-sm leading-relaxed text-slate-700">{copy.detailedP1}</p>
+        <p class="mt-4 text-sm leading-relaxed text-slate-700">{copy.detailedP2}</p>
+        <p class="mt-4 text-sm leading-relaxed text-slate-700">{copy.detailedP3}</p>
+      </div>
+      <div class="space-y-8">
+        <div class="rounded-2xl border border-slate-200 bg-white p-8">
+          <h2 class="text-2xl font-bold text-night-950">{copy.backTitle}</h2>
+          <p class="mt-4 text-sm leading-relaxed text-slate-700">{copy.backText}</p>
+        </div>
+        <div class="rounded-2xl border border-slate-200 bg-white p-8">
+          <h2 class="text-2xl font-bold text-night-950">{copy.resultsTitle}</h2>
+          <p class="mt-4 text-sm leading-relaxed text-slate-700">{copy.resultsText}</p>
+        </div>
+      </div>
+    </div>
+  </section>
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
+      <div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
+        {gallery.map((src) => (
+          <img src={src} alt={copy.galleryAlt} class="aspect-[4/3] w-full rounded-xl border border-slate-200 object-cover" loading="lazy" />
+        ))}
+      </div>
+
+      <h2 class="mt-14 text-2xl font-bold text-night-950">{copy.docsTitle}</h2>
+      <ul class="mt-5 grid gap-3 sm:grid-cols-2">
+        {docs.map((d) => (
+          <li>
+            <a href={d.href} target="_blank" rel="noopener" class="flex items-center gap-3 rounded-xl border border-slate-200 p-4 text-sm font-medium text-night-900 transition-colors hover:border-accent-400 hover:bg-accent-50">
+              <svg class="h-5 w-5 shrink-0 text-accent-500" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+                <path d="M10.75 2.75a.75.75 0 00-1.5 0v8.614L6.295 8.235a.75.75 0 10-1.09 1.03l4.25 4.5a.75.75 0 001.09 0l4.25-4.5a.75.75 0 00-1.09-1.03l-2.955 3.129V2.75z" />
+                <path d="M3.5 12.75a.75.75 0 00-1.5 0v2.5A2.75 2.75 0 004.75 18h10.5A2.75 2.75 0 0018 15.25v-2.5a.75.75 0 00-1.5 0v2.5c0 .69-.56 1.25-1.25 1.25H4.75c-.69 0-1.25-.56-1.25-1.25v-2.5z" />
+              </svg>
+              {d.title}
+            </a>
+          </li>
+        ))}
+      </ul>
+
+      <div class="mt-12 rounded-2xl bg-slate-50 p-6 text-sm leading-relaxed text-slate-700">
+        <strong class="font-semibold text-night-950">{copy.sysreq}</strong>
+        {copy.sysreqText}
+      </div>
+    </div>
+  </section>
+
+  <CTAForm title={copy.ctaTitle} subtitle={copy.ctaSubtitle} locale={locale} />
+</Base>

+ 57 - 0
src/components/pages/DiggerslopeUpdatesPage.astro

@@ -0,0 +1,57 @@
+---
+import Base from "../../layouts/Base.astro";
+import PageHero from "../PageHero.astro";
+import { diggerReleases } from "../../data/digger-updates";
+import { type Locale } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+const releases = diggerReleases[locale];
+
+const copy = {
+  en: {
+    title: "Digger Slope updates",
+    description: "Release history of the Digger Slope software suite",
+    heroTitle: "Digger Slope updates",
+    heroSubtitle: "Changelog of the Digger Slope software suite",
+  },
+  ru: {
+    title: "Обновления Digger Slope",
+    description: "История обновлений программного комплекса Digger Slope",
+    heroTitle: "Обновления Digger Slope",
+    heroSubtitle: "История изменений программного комплекса Digger Slope",
+  },
+}[locale];
+---
+
+<Base title={copy.title} description={copy.description} locale={locale}>
+  <PageHero title={copy.heroTitle} subtitle={copy.heroSubtitle} />
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
+      {releases.map((r) => (
+        <article class="rounded-2xl border border-slate-200 p-8">
+          <header class="flex flex-wrap items-baseline justify-between gap-2 border-b border-slate-200 pb-5">
+            <h2 class="text-2xl font-bold text-night-950">Release {r.version}</h2>
+            <time class="text-sm font-medium text-slate-500">{r.date}</time>
+          </header>
+          {r.sections.map((s) => (
+            <div class="mt-7">
+              <h3 class="text-lg font-semibold text-accent-600">{s.title}</h3>
+              <ul class="mt-3 space-y-2.5">
+                {s.items.map((item) => (
+                  <li class="flex gap-3 text-sm leading-relaxed text-slate-700">
+                    <span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
+                    {item}
+                  </li>
+                ))}
+              </ul>
+            </div>
+          ))}
+        </article>
+      ))}
+    </div>
+  </section>
+</Base>

+ 172 - 0
src/components/pages/EducationPage.astro

@@ -0,0 +1,172 @@
+---
+import Base from "../../layouts/Base.astro";
+import PageHero from "../PageHero.astro";
+import { site } from "../../data/site";
+import { type Locale } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+
+const copy = {
+  en: {
+    title: "Educational organization information",
+    description: "Information about the educational activities of Scientia LLC",
+    generalTitle: "General information",
+    info: [
+      ["Full name of the organization", `Limited Liability Company Scientia (INN ${site.inn}, OGRN ${site.ogrn})`],
+      ["Short name of the organization", "Scientia LLC"],
+      ["Date of foundation", "January 18, 2023"],
+      ["Location of the organization", site.address],
+      ["Contact phone", site.phone],
+      ["Email address", site.email],
+    ],
+    docsTitle: "Documents",
+    docs: [
+      ["Charter of the organization", "6a941e28dfb5"],
+      ["On approval of local regulatory acts for organizing and conducting educational activities under additional professional programs", "ccb8f9a9ee7e"],
+      ["Regulations on educational activities", "493c011f8e72"],
+      ["Rules for student admission", "e4acecb8c65c"],
+      ["Regulations on the schedule of classes", "a2aa79f58d92"],
+      ["Regulations on assessment", "fa6b65f46d20"],
+      ["Regulations on transfer", "6776c55b9f29"],
+      ["Regulations on educational relations", "b7f876c117a6"],
+      ["Additional professional continuing education program", "6139a79df404"],
+    ],
+    educationTitle: "Education",
+    educationP1: [
+      "Scientia LLC delivers an additional professional continuing education program ",
+      "GEOMECHANICS AND THE BASICS OF HYDROGEOLOGY",
+      ". The educational process runs throughout the calendar year, and instruction is in Russian.",
+    ],
+    educationP2:
+      "Training is delivered in a distance-learning format, using e-learning and distance education technologies. The program aims to advance competencies in geomechanics and hydrogeology — including rock mechanics and granular and structurally heterogeneous media — required for the students' professional activities, and to raise their professional level within their existing qualification.",
+    educationP3:
+      "The program is designed for managers and specialists of mining companies responsible for the safety of mining operations — the enterprise's chief geotechnical service, the rockburst prediction and prevention service, and geomechanical engineers.",
+    educationP4: "Issued document: ",
+    educationP4Doc: "a state-standard continuing education certificate.",
+    placesTitle: "Places where educational activities are carried out",
+    place1Pre: "At the educational organization's location: ",
+    place2: "Using e-learning and distance education technologies — via the Internet",
+    portalTitle: "Distance learning portal",
+    portalText: "Training takes place on our education portal.",
+    portalButton: "Go to the portal ↗",
+  },
+  ru: {
+    title: "Сведения об образовательной организации",
+    description: "Сведения об образовательной организации ООО «Скиентия»",
+    generalTitle: "Основные сведения",
+    info: [
+      ["Полное наименование организации", `Общество с ограниченной ответственностью «Скиентия» (ИНН ${site.inn}, ОГРН ${site.ogrn})`],
+      ["Краткое наименование организации", "ООО «Скиентия»"],
+      ["Дата создания организации", "18 января 2023 года"],
+      ["Место нахождения организации", site.addressRu],
+      ["Контактные телефоны организации", site.phone],
+      ["Адрес электронной почты организации", site.email],
+    ],
+    docsTitle: "Документы",
+    docs: [
+      ["Устав организации", "6a941e28dfb5"],
+      ["Об утверждении локальных нормативных актов по организации и осуществлению образовательной деятельности по дополнительным профессиональным программам", "ccb8f9a9ee7e"],
+      ["Положение об образовательной деятельности", "493c011f8e72"],
+      ["Правила приема обучающихся", "e4acecb8c65c"],
+      ["Положение о режиме занятий", "a2aa79f58d92"],
+      ["Положение о контроле", "fa6b65f46d20"],
+      ["Положение о переводе", "6776c55b9f29"],
+      ["Положение об образовательных отношениях", "b7f876c117a6"],
+      ["Дополнительная профессиональная программа повышения квалификации", "6139a79df404"],
+    ],
+    educationTitle: "Образование",
+    educationP1: [
+      "ООО «Скиентия» реализует дополнительную профессиональную программу повышения квалификации ",
+      "«ГЕОМЕХАНИКА И ОСНОВЫ ГИДРОГЕОЛОГИИ»",
+      ". Учебный процесс осуществляется в течение всего календарного года, обучение ведётся на русском языке.",
+    ],
+    educationP2:
+      "Обучение проводится по заочной форме обучения. При реализации образовательной программы используются электронное обучение и дистанционные образовательные технологии. Целью программы является совершенствование компетенций в области геомеханики и гидрогеологии, в том числе в области механики горных пород, сыпучих и структурно-неоднородных сред, необходимых для профессиональной деятельности обучающихся, и повышение профессионального уровня в рамках имеющейся квалификации.",
+    educationP3:
+      "Программа рассчитана на руководителей и специалистов горнодобывающих предприятий, занимающихся обеспечением безопасности ведения горных работ — служба главного геотехника предприятия, служба прогнозирования и предупреждения горных ударов, специалисты-геомеханики.",
+    educationP4: "Выдаваемый документ: ",
+    educationP4Doc: "удостоверение о повышении квалификации установленного образца.",
+    placesTitle: "Места осуществления образовательной деятельности",
+    place1Pre: "По адресу места нахождения образовательной организации: ",
+    place2: "С применением электронного обучения и дистанционных образовательных технологий — посредством информационно-телекоммуникационной сети «Интернет»",
+    portalTitle: "Портал дистанционного обучения",
+    portalText: "Обучение проводится на нашем образовательном портале.",
+    portalButton: "Перейти на портал ↗",
+  },
+}[locale];
+
+const address = locale === "ru" ? site.addressRu : site.address;
+const docs = copy.docs.map(([title, hash]) => ({ title, href: `https://files.scientia.ru/public/${hash}` }));
+---
+
+<Base title={copy.title} description={copy.description} locale={locale}>
+  <PageHero title={copy.title} />
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-4xl space-y-10 px-4 py-16 sm:px-6">
+      <div class="rounded-2xl border border-slate-200 p-8">
+        <h2 class="text-2xl font-bold text-night-950">{copy.generalTitle}</h2>
+        <dl class="mt-5 divide-y divide-slate-100">
+          {copy.info.map(([k, v]) => (
+            <div class="grid gap-1 py-3.5 sm:grid-cols-3 sm:gap-6">
+              <dt class="text-sm font-medium text-slate-500">{k}</dt>
+              <dd class="text-sm font-medium text-night-950 sm:col-span-2">{v}</dd>
+            </div>
+          ))}
+        </dl>
+      </div>
+
+      <div class="rounded-2xl border border-slate-200 p-8">
+        <h2 class="text-2xl font-bold text-night-950">{copy.docsTitle}</h2>
+        <ul class="mt-5 grid gap-3">
+          {docs.map((d) => (
+            <li>
+              <a href={d.href} target="_blank" rel="noopener" class="flex items-center gap-3 rounded-xl border border-slate-200 p-4 text-sm font-medium text-night-900 transition-colors hover:border-accent-400 hover:bg-accent-50">
+                <svg class="h-5 w-5 shrink-0 text-accent-500" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+                  <path d="M3 3.5A1.5 1.5 0 014.5 2h6.879a1.5 1.5 0 011.06.44l4.122 4.12A1.5 1.5 0 0117 7.622V16.5a1.5 1.5 0 01-1.5 1.5h-11A1.5 1.5 0 013 16.5v-13z" />
+                </svg>
+                {d.title}
+              </a>
+            </li>
+          ))}
+        </ul>
+      </div>
+
+      <div class="rounded-2xl border border-slate-200 p-8">
+        <h2 class="text-2xl font-bold text-night-950">{copy.educationTitle}</h2>
+        <div class="mt-4 space-y-4 text-sm leading-relaxed text-slate-700">
+          <p>
+            {copy.educationP1[0]}<strong>{copy.educationP1[1]}</strong>{copy.educationP1[2]}
+          </p>
+          <p>{copy.educationP2}</p>
+          <p>{copy.educationP3}</p>
+          <p><strong>{copy.educationP4}</strong>{copy.educationP4Doc}</p>
+        </div>
+      </div>
+
+      <div class="rounded-2xl border border-slate-200 p-8">
+        <h2 class="text-2xl font-bold text-night-950">{copy.placesTitle}</h2>
+        <ol class="mt-4 list-decimal space-y-2 pl-5 text-sm leading-relaxed text-slate-700">
+          <li>{copy.place1Pre}{address}</li>
+          <li>{copy.place2}</li>
+        </ol>
+      </div>
+
+      <div class="rounded-2xl bg-night-900 p-8 text-white">
+        <h2 class="text-2xl font-bold">{copy.portalTitle}</h2>
+        <p class="mt-3 text-slate-300">{copy.portalText}</p>
+        <a
+          href={site.external.education}
+          target="_blank"
+          rel="noopener"
+          class="mt-5 inline-block rounded-lg bg-accent-300 px-6 py-3 font-semibold text-night-950 transition-colors hover:bg-accent-400"
+        >
+          {copy.portalButton}
+        </a>
+      </div>
+    </div>
+  </section>
+</Base>

+ 111 - 0
src/components/pages/EmergencyCarePage.astro

@@ -0,0 +1,111 @@
+---
+import Base from "../../layouts/Base.astro";
+import PageHero from "../PageHero.astro";
+import { site } from "../../data/site";
+import { type Locale, localePath } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+const lp = (path: string) => localePath(locale, path);
+
+const copy = {
+  en: {
+    title: "Geotechnical emergency response",
+    description:
+      "Rapid deployment of continuous monitoring over potential collapses in open pits and waste dumps, with response measure recommendations",
+    heroSubtitle:
+      "Rapid deployment of continuous monitoring over potential collapses in open pits and waste dumps, with response measure recommendations. We will take control of the rock spalling you have discovered on pit slopes and dumps. In the shortest possible time",
+    howTitle: "How we work",
+    moreLink: " (more about the extensometer)",
+    notes: "Notes:",
+    notesText:
+      "The service is available only if we have extensometers in stock, there is mobile coverage at the site, and an extensometer can be installed to monitor the deformation. The service includes the installation of one extensometer and six months of monitoring with it.",
+    callTitle: "To get this service as soon as possible, call us",
+    regions: "(Russia, Kazakhstan, Uzbekistan)",
+  },
+  ru: {
+    title: "Скорая геотехническая помощь",
+    description:
+      "Быстрый запуск непрерывного мониторинга потенциальных обрушений на карьерах и отвалах с выработкой рекомендаций по мерам реагирования",
+    heroSubtitle:
+      "Быстрый запуск непрерывного мониторинга потенциальных обрушений на карьерах и отвалах с выработкой рекомендаций по мерам реагирования. Возьмём под контроль обнаруженные вами заколы на бортах карьеров и на отвалах. В кратчайшие сроки",
+    howTitle: "Как мы работаем",
+    moreLink: " (подробнее об экстензометре)",
+    notes: "Примечания:",
+    notesText:
+      "Предоставление услуги возможно только в случае наличия у нас экстензометров, наличия мобильной связи на объекте и возможности установки экстензометра для мониторинга деформации. Услуга включает установку одного экстензометра и полгода мониторинга им.",
+    callTitle: "Чтобы получить данную услугу как можно быстрее, звоните",
+    regions: "(Россия, Казахстан, Узбекистан)",
+  },
+}[locale];
+
+const steps = {
+  en: [
+    { n: 1, text: "We provide a commercial proposal", time: "day of inquiry" },
+    { n: 2, text: "Our specialists travel to the site against a letter of guarantee (after contractor verification)", time: "2–3 d" },
+    { n: 3, text: "Monitoring is launched with automated mobile NUR extensometers", time: "3–4 d", href: "/nur" },
+    { n: 4, text: "We carry out a geomechanical deformation survey and fill in the deformation passport", time: "3–4 d" },
+    { n: 5, text: "We determine the potential causes of the deformation and identify gaps in the study of the deforming area", time: "3–4 d" },
+    { n: 6, text: "We conduct additional field investigations", time: "3–5 d" },
+    { n: 7, text: "Together with the customer, we hold a video conference with our experienced specialists to develop response measures and design measures to minimize the consequences of a potential collapse", time: "4–5 d" },
+    { n: 8, text: "Forecasting the development of the deformation process. Justification of critical deformation parameters", time: "4–5 d" },
+    { n: 9, text: "Preparing the final report describing points 2–8", time: "2 wk" },
+    { n: 10, text: "Monitoring support: configuring alerts for exceeding critical parameters, predicting the time of collapse, reporting on the deformation process dynamics, and providing online access to displacement and velocity charts", time: "six months" },
+  ],
+  ru: [
+    { n: 1, text: "Предоставляем коммерческое предложение", time: "день обращения" },
+    { n: 2, text: "Наши специалисты выезжают на объект по гарантийному письму (после проверки контрагента)", time: "2–3 д." },
+    { n: 3, text: "Запуск мониторинга автоматизированными мобильными экстензометрами NUR", time: "3–4 д.", href: "/nur" },
+    { n: 4, text: "Проводим геомеханическое обследование деформации, заполняем паспорт деформации", time: "3–4 д." },
+    { n: 5, text: "Определяем потенциальные причины деформации и находим пробелы в изученности деформирующегося участка", time: "3–4 д." },
+    { n: 6, text: "Проводим дополнительные полевые исследования", time: "3–5 д." },
+    { n: 7, text: "Совместно с заказчиком проводим ВКС с нашими опытными специалистами по выработке мер реагирования, разрабатываем меры по минимизации последствий потенциального обрушения", time: "4–5 д." },
+    { n: 8, text: "Составление прогноза развития деформационного процесса. Обоснование критических параметров деформации", time: "4–5 д." },
+    { n: 9, text: "Составление итоговой записки с описанием пп. 2–8", time: "2 нед." },
+    { n: 10, text: "Сопровождение мониторинга: настройка оповещений по превышению критических параметров, прогнозирование времени обрушения, отчётность о динамике деформационного процесса, предоставление онлайн-доступа к графикам смещений и скоростей", time: "полгода" },
+  ],
+}[locale];
+---
+
+<Base title={copy.title} description={copy.description} locale={locale}>
+  <PageHero title={copy.title} subtitle={copy.heroSubtitle} image="/images/0c243b47-f913-4e05-8.jpeg" />
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
+      <h2 class="text-3xl font-bold tracking-tight text-night-950">{copy.howTitle}</h2>
+      <ol class="mt-10 space-y-0">
+        {steps.map((s) => (
+          <li class="relative flex gap-5 pb-8 last:pb-0">
+            {s.n !== steps.length && <span class="absolute left-5 top-12 h-full w-px bg-slate-200" aria-hidden="true" />}
+            <span class="z-10 flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-accent-300 font-bold text-night-950">{s.n}</span>
+            <div class="flex-1 rounded-2xl border border-slate-200 p-5">
+              <p class="text-sm leading-relaxed text-slate-700">
+                {s.text}
+                {s.href && (
+                  <a href={lp(s.href)} class="font-medium text-accent-600 hover:text-accent-700">{copy.moreLink}</a>
+                )}
+              </p>
+              <span class="mt-2 inline-block rounded-full bg-slate-100 px-3 py-1 text-xs font-semibold text-slate-500">{s.time}</span>
+            </div>
+          </li>
+        ))}
+      </ol>
+
+      <div class="mt-12 rounded-2xl bg-slate-50 p-6 text-sm leading-relaxed text-slate-700">
+        <strong class="font-semibold text-night-950">{copy.notes}</strong>
+        {copy.notesText}
+      </div>
+
+      <div class="mt-10 rounded-2xl bg-night-900 p-8 text-white">
+        <h2 class="text-2xl font-bold">{copy.callTitle}</h2>
+        <div class="mt-5 flex flex-wrap gap-x-10 gap-y-3">
+          <a href="tel:+79222032460" class="text-2xl font-bold text-accent-300 hover:text-accent-200">{site.phone}</a>
+          <a href="tel:+79826356310" class="text-2xl font-bold text-accent-300 hover:text-accent-200">+7 (982) 635-63-10</a>
+        </div>
+        <p class="mt-2 text-sm text-slate-400">{copy.regions}</p>
+      </div>
+    </div>
+  </section>
+</Base>

+ 192 - 0
src/components/pages/GeodesyPage.astro

@@ -0,0 +1,192 @@
+---
+import Base from "../../layouts/Base.astro";
+import PageHero from "../PageHero.astro";
+import { type Locale } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+
+const copy = {
+  en: {
+    title: "Geodetic surveying",
+    description:
+      "Deformation observation and geodetic monitoring of open-pit slopes, geodetic and construction work design. Aerial laser scanning, engineering geodetic surveys, mine surveying support for mining operations",
+    heroSubtitle:
+      "A full scope of topographic, geodetic and mine surveying services, including aerial laser scanning (ALS), aerial photography, and terrestrial photogrammetry",
+    intro:
+      "We specialize in creating high-precision digital terrain models and analyzing geospatial data — particularly relevant in mining, construction, design, and monitoring.",
+    directionsTitle: "Key services",
+    directions: [
+      {
+        title: "Aerial laser scanning",
+        points: [
+          "Producing a detailed point cloud followed by 3D terrain and digital elevation models",
+          "Measuring hidden or hard-to-reach areas, including vegetated zones and waste dumps",
+          "Using laser scanners for deformation control and early detection of potential landslides",
+        ],
+      },
+      {
+        title: "Geodetic monitoring",
+        points: [
+          "Continuous or periodic monitoring of movements and deformations of buildings, structures, and open-pit slopes",
+          "High-precision instrumental methods",
+          "Real-time monitoring of settlements and tilts for timely detection and prevention of accidents",
+          "Data analysis to adjust design decisions with geomechanical factors in mind",
+        ],
+      },
+      {
+        title: "Mine surveying",
+        points: [
+          "Determining reserves and extracted rock volumes",
+          "Preparing mine surveying documentation in accordance with Rostechnadzor requirements",
+          "Monitoring the dynamics of mining operations and collapse risk assessment",
+        ],
+      },
+      {
+        title: "Topographic and geodetic surveys",
+        points: [
+          "Surveying and producing topographic plans for planning and design",
+          "Establishing horizontal and vertical control networks",
+          "Monitoring structure displacements and open-pit slope deformation",
+        ],
+      },
+      {
+        title: "Aerial photography",
+        points: [
+          "Photographing large areas in a short time",
+          "Building orthophotomaps and 3D models for precise terrain analysis, mapping and topographic plans, as well as volume calculations",
+          "Improved accuracy when planning mining operations and reclamation work",
+        ],
+      },
+      {
+        title: "Terrestrial photogrammetry",
+        points: [
+          "Highly detailed surveys of individual objects, open-pit slopes, structures and more",
+          "Combining terrestrial and aerial survey data for a more complete picture",
+        ],
+      },
+    ],
+    examplesTitle: "Real-world examples",
+    example1:
+      "Mine surveying support at one of the ore deposits in Sverdlovsk Oblast helped resolve disputes between the subsurface user and the stripping contractor.",
+    example2:
+      "Regular aerial laser scanning of a reclaiming coal mine in Chelyabinsk Oblast makes it possible to analyze all ongoing deformations over a large area (over 700 ha) in office mode.",
+    galleryAlt: "Geodetic surveying — field work",
+  },
+  ru: {
+    title: "Геодезические работы",
+    description:
+      "Наблюдения за деформацией и геодезический мониторинг борта карьеров, проектирование геодезических и строительных работ. Воздушное лазерное сканирование, инженерно геодезические изыскания, маркшейдерское обеспечение горных работ",
+    heroSubtitle:
+      "Комплекс работ по топографии, геодезии и маркшейдерскому сопровождению, включая воздушное лазерное сканирование (ВЛС), аэрофотосъёмку, наземную фотограмметрию",
+    intro:
+      "Мы специализируемся на создании высокоточных цифровых моделей рельефа и анализе геопространственных данных, что особенно актуально в горном деле, строительстве, проектировании и мониторинге.",
+    directionsTitle: "Ключевые направления",
+    directions: [
+      {
+        title: "Воздушное лазерное сканирование",
+        points: [
+          "Получение детализированного облака точек с последующим построением трехмерной модели местности и цифровой модели рельефа",
+          "Измерение скрытых или труднодоступных участков, включая зону растительности и отвалы",
+          "Использование лазерных сканнеров для контроля деформаций и раннего выявления потенциальных оползней",
+        ],
+      },
+      {
+        title: "Геодезический мониторинг",
+        points: [
+          "Постоянное или периодическое наблюдение за подвижками и деформациями зданий, сооружений, бортов карьеров",
+          "Использование высокоточных инструментальных методов",
+          "Мониторинг осадок и кренов в реальном времени для своевременного выявления и предотвращения аварийных ситуаций",
+          "Анализ полученных данных для корректировки проектных решений с учётом геомеханических факторов",
+        ],
+      },
+      {
+        title: "Маркшейдерские работы",
+        points: [
+          "Определение запасов и объёмов добытых горных пород",
+          "Подготовка маркшейдерской документации в соответствии с требованиями Ростехнадзора",
+          "Мониторинг динамики горных выработок и оценка рисков обрушений",
+        ],
+      },
+      {
+        title: "Топографические и геодезические изыскания",
+        points: [
+          "Съёмка и построение топопланов для планирования и проектирования",
+          "Создание планово-высотного обоснования (ПВО)",
+          "Контроль смещений сооружений и деформации бортов карьеров",
+        ],
+      },
+      {
+        title: "Аэрофотосъёмка",
+        points: [
+          "Съёмка крупной площади за короткие сроки",
+          "Построение ортофотопланов и 3D-моделей для точного анализа рельефа, построения карт и топопланов, а также подсчёта объёмов",
+          "Повышенная точность при планировании горно-технических мероприятий и рекультивационных работ",
+        ],
+      },
+      {
+        title: "Наземная фотограмметрия",
+        points: [
+          "Высокодетализированная съемка отдельных объектов, откосов карьера, строительных конструкций и прочее",
+          "Объединение данных наземной и воздушной съёмки для более полной картины",
+        ],
+      },
+    ],
+    examplesTitle: "Реальные примеры применения",
+    example1:
+      "Маркшейдерское сопровождение на одном из рудных месторождений Свердловской области позволило урегулировать споры между пользователем недр и подрядчиком по вскрышным работам.",
+    example2:
+      "Регулярное воздушное лазерное сканирование рекультивируемого угольного карьера в Челябинской области позволяет анализировать в камеральном режиме все протекающие деформации на значительной площади (более 700 Га).",
+    galleryAlt: "Геодезические работы — полевые съёмки",
+  },
+}[locale];
+
+const gallery = ["/images/3.jpg", "/images/4.jpg", "/images/5.jpg", "/images/1-2ab29z.jpg", "/images/6.JPG", "/images/PXL_20240515_0620422-fsrmkv.jpg"];
+---
+
+<Base title={copy.title} description={copy.description} locale={locale}>
+  <PageHero title={copy.title} subtitle={copy.heroSubtitle} image="/images/PXL_20240515_0620422.jpg" />
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
+      <p class="max-w-4xl text-lg leading-relaxed text-slate-700">{copy.intro}</p>
+      <h2 class="mt-12 text-3xl font-bold tracking-tight text-night-950">{copy.directionsTitle}</h2>
+      <div class="mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
+        {copy.directions.map((d) => (
+          <div class="rounded-2xl border border-slate-200 p-6">
+            <h3 class="text-lg font-semibold text-night-950">{d.title}</h3>
+            <ul class="mt-4 space-y-2.5">
+              {d.points.map((p) => (
+                <li class="flex gap-2.5 text-sm leading-relaxed text-slate-600">
+                  <span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
+                  {p}
+                </li>
+              ))}
+            </ul>
+          </div>
+        ))}
+      </div>
+    </div>
+  </section>
+
+  <section class="bg-slate-50">
+    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
+      <h2 class="text-3xl font-bold tracking-tight text-night-950">{copy.examplesTitle}</h2>
+      <div class="mt-8 grid gap-6 lg:grid-cols-2">
+        <div class="rounded-2xl border border-slate-200 bg-white p-8 text-sm leading-relaxed text-slate-700">
+          {copy.example1}
+        </div>
+        <div class="rounded-2xl border border-slate-200 bg-white p-8 text-sm leading-relaxed text-slate-700">
+          {copy.example2}
+        </div>
+      </div>
+      <div class="mt-10 grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-6">
+        {gallery.map((src) => (
+          <img src={src} alt={copy.galleryAlt} class="aspect-square w-full rounded-xl border border-slate-200 object-cover" loading="lazy" />
+        ))}
+      </div>
+    </div>
+  </section>
+</Base>

+ 308 - 0
src/components/pages/HomePage.astro

@@ -0,0 +1,308 @@
+---
+import Base from "../../layouts/Base.astro";
+import CTAForm from "../CTAForm.astro";
+import TelegramWidget from "../TelegramWidget.astro";
+import { services } from "../../data/services";
+import { products } from "../../data/products";
+import { site } from "../../data/site";
+import { type Locale, translator } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+const t = translator(locale);
+const lp = (path: string) => (locale === "ru" ? (path === "/" ? "/ru/" : `/ru${path}`) : path);
+
+const copy = {
+  en: {
+    title: "Geomechanical modeling and software. Mining geomechanics — Scientia",
+    description:
+      "The Institute of Geomechanics assesses geomechanical risks, runs geotechnical monitoring, kinematic analysis, strength and stability calculations for mining operations, open-pit slope monitoring, engineering geological surveying, and geomechanical modeling",
+    h1: "Engineering, innovation and&nbsp;openness",
+    subtitle:
+      "For the efficiency of the mining industry: comprehensive geomechanical studies, in-house software and hardware.",
+    ctaProducts: "Our products",
+    ctaServices: "Services",
+    servicesTitle: "Services",
+    servicesSubtitle:
+      "Full cycle: from structural-geological mapping to deformation monitoring and analytical studies.",
+    whyTitle: "Why choose us",
+  },
+  ru: {
+    title: "Геомеханическое моделирование и ПО. Горная геомеханика — Scientia",
+    description:
+      "Институт геомеханики оценивает геомеханические риски, ведёт геотехнический мониторинг, кинематический анализ, расчет прочности и устойчивости горных работ, мониторинг бортов карьера, инженерно геологическая съемка, геомеханическая модель",
+    h1: "Разработки, инновации и&nbsp;открытость",
+    subtitle:
+      "Для эффективности горной промышленности: комплексные геомеханические исследования, собственное ПО и аппаратура.",
+    ctaProducts: "Наши разработки",
+    ctaServices: "Услуги",
+    servicesTitle: "Услуги",
+    servicesSubtitle:
+      "Полный цикл: от структурно-геологического картирования до мониторинга деформаций и аналитических исследований.",
+    whyTitle: "Почему выбирают нас",
+  },
+}[locale];
+
+const whyUs = {
+  en: [
+    {
+      title: "Products",
+      text: "Our in-house software and hardware solutions solve problems others consider impossible. The team includes not only engineers but also programmers.",
+    },
+    {
+      title: "Innovation",
+      text: "We regularly test and adopt new technology, keeping our services up to date.",
+    },
+    {
+      title: "Openness",
+      text: "Our reports describe all parameters, decisions and assumptions in detail. Clients receive thorough consultations.",
+    },
+    {
+      title: "Efficiency",
+      text: "Safety is not the only concern — the economics of solutions matter too. Finding cost-saving potential is one of a geomechanical engineer's tasks.",
+    },
+  ],
+  ru: [
+    {
+      title: "Разработки",
+      text: "Собственные программные и аппаратные решения позволяют решать задачи, которые другие считают невозможными. В команде работают не только инженеры, но и программисты.",
+    },
+    {
+      title: "Инновации",
+      text: "Регулярно тестируем и внедряем технические новшества, что поддерживает актуальность наших услуг.",
+    },
+    {
+      title: "Открытость",
+      text: "В отчётах подробно описываются все параметры, решения и допущения. Клиенты получают развёрнутые консультации.",
+    },
+    {
+      title: "Эффективность",
+      text: "Важна не только безопасность, но и экономика решений. Поиск потенциала для экономии — одна из задач геомеханика.",
+    },
+  ],
+}[locale];
+
+const community = {
+  en: {
+    tgTitle: "Telegram channel",
+    tgText: "News, discoveries and recommendations — shared on the company channel",
+    blogTitle: "Blog",
+    blogText: "Latest posts and articles — on the Teletype platform",
+  },
+  ru: {
+    tgTitle: "Телеграм-канал",
+    tgText: "Новости, открытия и рекомендации — делимся в канале компании",
+    blogTitle: "Блог",
+    blogText: "Последние записи и статьи — на платформе Teletype",
+  },
+}[locale];
+
+const serviceList = services[locale];
+const productList = products[locale].map((p) => ({ ...p, href: lp(p.href) }));
+
+// Client logos, arranged checkerboard: heavy dark logos alternate with light ones.
+// `big` — logos with lots of internal whitespace, render larger to match the others optically
+const clients = [
+  { file: "___1.png" },                         // УГМК — heavy
+  { file: "unnamed.jpg", big: true },           // Атлас Майнинг — light
+  { file: "c5aa9760-2920-4b4d-b.png" },         // ВНИМИ — heavy
+  { file: "29595058_20159791717.jpg", big: true }, // Норникель — light
+  { file: "9f97a370e8530d40a0ff.jpg" },         // РМК — heavy
+  { file: "_2.jpg" },                           // Полюс — light
+  { file: "evraz.jpg" },                        // Евраз — medium
+  { file: "17304586690.jpg", big: true },       // УГХ — light
+  { file: "photo-610z4l.jpg" },                 // Алроса — medium
+].map((c) => ({ ...c, src: "/images/" + c.file }));
+---
+
+<Base title={copy.title} description={copy.description} locale={locale}>
+  <!-- Cinematic full-viewport hero -->
+  <section class="relative flex h-[100svh] min-h-[640px] items-end overflow-hidden bg-night-950 text-white">
+    <video
+      src="/videos/hero-background.mp4"
+      class="absolute inset-0 h-full w-full object-cover"
+      autoplay
+      muted
+      loop
+      playsinline
+      poster="/images/1655676643_10-kartin.jpg"
+      aria-hidden="true"
+    ></video>
+    <div class="absolute inset-0 bg-gradient-to-t from-black/80 via-black/25 to-black/40"></div>
+
+    <div class="relative mx-auto w-full max-w-[1400px] px-5 pb-28 sm:px-8">
+      <p class="text-xs font-semibold uppercase tracking-[0.25em] text-accent-300">{site.tagline[locale]}</p>
+      <h1 class="display mt-5 max-w-4xl text-5xl sm:text-7xl lg:text-8xl">
+        <Fragment set:html={copy.h1} /><span class="dot">.</span>
+      </h1>
+      <p class="mt-6 max-w-xl text-lg leading-relaxed text-white/75">
+        {copy.subtitle}
+      </p>
+      <div class="mt-9 flex flex-wrap items-center gap-4">
+        <a
+          href="#razrabotki"
+          class="group flex items-center gap-3 rounded-full bg-accent-300 py-3.5 pl-7 pr-4 font-semibold text-night-950 transition-colors hover:bg-accent-200"
+        >
+          {copy.ctaProducts}
+          <span class="flex h-8 w-8 items-center justify-center rounded-full bg-night-950 text-accent-300" aria-hidden="true">→</span>
+        </a>
+        <a
+          href="#uslugi"
+          class="rounded-full border border-white/40 px-7 py-3.5 font-semibold text-white transition-colors hover:border-white hover:bg-white/10"
+        >
+          {copy.ctaServices}
+        </a>
+      </div>
+    </div>
+
+    <!-- Telegram news window (right side) -->
+    <div class="absolute bottom-24 right-20 z-10 hidden xl:block">
+      <TelegramWidget locale={locale} />
+    </div>
+  </section>
+
+  <!-- Services — Rocscience-style section header + card deck -->
+  <section id="uslugi" class="scroll-mt-20 bg-white">
+    <div class="mx-auto max-w-[1400px] px-5 py-24 sm:px-8 lg:py-32">
+      <div class="flex flex-wrap items-end justify-between gap-6">
+        <h2 class="display text-5xl sm:text-6xl">{copy.servicesTitle}<span class="dot">.</span></h2>
+        <p class="max-w-md text-slate-500">
+          {copy.servicesSubtitle}
+        </p>
+      </div>
+
+      <div class="mt-14 grid gap-x-8 gap-y-14 sm:grid-cols-2 lg:grid-cols-4">
+        {serviceList.map((s) => (
+          <a
+            href={s.href ? (s.external ? s.href : lp(s.href)) : "#contacts"}
+            class="group block"
+            {...s.external ? { target: "_blank", rel: "noopener" } : {}}
+          >
+            <div class="relative aspect-[4/3] overflow-hidden">
+              <img
+                src={s.image}
+                alt={s.title}
+                class="h-full w-full object-cover transition-transform duration-700 group-hover:scale-105"
+                loading="lazy"
+              />
+              {"tag" in s && s.tag && (
+                <span class="absolute left-4 top-4 bg-accent-300 px-2.5 py-1 text-xs font-bold text-night-950">{s.tag}</span>
+              )}
+            </div>
+            <div class="mt-5">
+              <h3 class="display text-2xl">{s.title}</h3>
+              {s.items && (
+                <p class="mt-2 line-clamp-2 text-sm leading-relaxed text-slate-500">{s.items[0]}</p>
+              )}
+              {s.description && (
+                <p class="mt-2 line-clamp-2 text-sm leading-relaxed text-slate-500">{s.description}</p>
+              )}
+            </div>
+          </a>
+        ))}
+      </div>
+    </div>
+  </section>
+
+  <!-- Products — Porsche-style full-bleed stages -->
+  <section id="razrabotki" class="scroll-mt-20 bg-night-950 text-white">
+    {productList.map((p) => (
+      <a href={p.href} class="group relative block h-[82svh] min-h-[560px] overflow-hidden border-t border-white/10">
+        <img
+          src={p.image}
+          alt={p.name}
+          class="absolute inset-0 h-full w-full object-cover opacity-80 transition-all duration-700 group-hover:scale-[1.03] group-hover:opacity-100"
+          loading="lazy"
+        />
+        <div class="absolute inset-0 bg-gradient-to-t from-black/85 via-black/20 to-black/30"></div>
+        <div class="relative mx-auto flex h-full max-w-[1400px] items-end px-5 pb-16 sm:px-8">
+          <div class="w-full">
+            <p class="text-xs font-semibold uppercase tracking-[0.25em] text-accent-300">{p.tagline}</p>
+            <div class="mt-3 flex flex-wrap items-end justify-between gap-6">
+              <div class="max-w-2xl">
+                <h3 class="display text-5xl sm:text-6xl lg:text-7xl">{p.name}<span class="dot">.</span></h3>
+                <p class="mt-4 max-w-xl text-white/75">{p.description}</p>
+              </div>
+              <span class="chip-arrow" aria-hidden="true">
+                <svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
+                  <path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5L21 12l-7.5 7.5M21 12H3" />
+                </svg>
+              </span>
+            </div>
+          </div>
+        </div>
+      </a>
+    ))}
+  </section>
+
+  <!-- Why us — editorial dark numbers -->
+  <section class="bg-white">
+    <div class="mx-auto max-w-[1400px] px-5 py-24 sm:px-8 lg:py-32">
+      <h2 class="display max-w-3xl text-5xl sm:text-6xl">
+        {copy.whyTitle}<span class="dot">.</span>
+      </h2>
+
+      <!-- Client logos -->
+      <div class="mt-12">
+        <div class="grid grid-cols-2 items-center justify-items-center gap-x-10 gap-y-8 sm:grid-cols-3">
+          {clients.map((c) => (
+            <span class="flex h-36 w-full items-center justify-center">
+              <img
+                src={c.src}
+                alt={t("tg.logoAlt")}
+                class:list={["w-auto object-contain", c.big ? "max-h-36 max-w-[300px]" : "max-h-24 max-w-[220px]"]}
+                loading="lazy"
+              />
+            </span>
+          ))}
+        </div>
+      </div>
+
+      <div class="mt-16 grid gap-x-8 gap-y-12 sm:grid-cols-2 lg:grid-cols-4">
+        {whyUs.map((w, i) => (
+          <div class="border-t-2 border-night-950 pt-6">
+            <span class="display text-6xl text-accent-300">{String(i + 1).padStart(2, "0")}</span>
+            <h3 class="display mt-4 text-2xl">{w.title}</h3>
+            <p class="mt-3 text-sm leading-relaxed text-slate-500">{w.text}</p>
+          </div>
+        ))}
+      </div>
+    </div>
+  </section>
+
+  <!-- Community — Porsche-style tiles -->
+  <section class="bg-night-950 text-white">
+    <div class="mx-auto grid max-w-[1400px] gap-px px-0 sm:grid-cols-2">
+      <a href="https://t.me/scientia_ru" target="_blank" rel="noopener" class="group relative block min-h-[420px] overflow-hidden">
+        <img src="/images/20200629_141121.jpg" alt="" class="absolute inset-0 h-full w-full object-cover opacity-40 transition-all duration-700 group-hover:scale-[1.03] group-hover:opacity-60" loading="lazy" />
+        <div class="absolute inset-0 bg-gradient-to-t from-black/85 to-transparent"></div>
+        <div class="relative flex h-full flex-col justify-end p-10">
+          <h3 class="display text-4xl">{community.tgTitle}<span class="dot">.</span></h3>
+          <p class="mt-3 max-w-sm text-white/70">{community.tgText}</p>
+          <span class="chip-arrow mt-8" aria-hidden="true">
+            <svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
+              <path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5L21 12l-7.5 7.5M21 12H3" />
+            </svg>
+          </span>
+        </div>
+      </a>
+      <a href={site.external.blog} target="_blank" rel="noopener" class="group relative block min-h-[420px] overflow-hidden border-l border-white/10">
+        <img src="/images/photo_2022-09-19_06-.jpg" alt="" class="absolute inset-0 h-full w-full object-cover opacity-40 transition-all duration-700 group-hover:scale-[1.03] group-hover:opacity-60" loading="lazy" />
+        <div class="absolute inset-0 bg-gradient-to-t from-black/85 to-transparent"></div>
+        <div class="relative flex h-full flex-col justify-end p-10">
+          <h3 class="display text-4xl">{community.blogTitle}<span class="dot">.</span></h3>
+          <p class="mt-3 max-w-sm text-white/70">{community.blogText}</p>
+          <span class="chip-arrow mt-8" aria-hidden="true">
+            <svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
+              <path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5L21 12l-7.5 7.5M21 12H3" />
+            </svg>
+          </span>
+        </div>
+      </a>
+    </div>
+  </section>
+
+  <CTAForm locale={locale} />
+</Base>

+ 88 - 0
src/components/pages/JointExplorerPage.astro

@@ -0,0 +1,88 @@
+---
+import Base from "../../layouts/Base.astro";
+import PageHero from "../PageHero.astro";
+import CTAForm from "../CTAForm.astro";
+import { site } from "../../data/site";
+import { type Locale } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+
+const copy = {
+  en: {
+    description: "An electronic geological compass for measuring dip azimuths and dip angles of jointing and tectonic structures",
+    heroSubtitle:
+      "An electronic geological compass for measuring dip azimuths and dip angles of jointing and tectonic structures. Unlike an analog compass, it allows more measurements in less time",
+    softwareTitle: "Software",
+    softwareText:
+      "A dedicated JointExplorer mobile app enables preliminary field analysis of the data collected by the device and generates export files as tables for each survey point.",
+    tgChannel: "Joint Explorer Telegram channel ↗",
+    galleryTitle: "The instrument in the field",
+    galleryAlt: "Joint Explorer — field measurements",
+    ctaTitle: "For any questions or suggestions",
+    ctaSubtitle: `Please email us at ${site.email} or fill in the form below.`,
+  },
+  ru: {
+    description: "Электронный горный компас для определения азимутов и углов падения трещиноватости и тектонических нарушений",
+    heroSubtitle:
+      "Электронный горный компас, предназначенный для определения азимутов и углов падения трещиноватости, тектонических нарушений. В отличие от аналогового компаса позволяет выполнять большее количество замеров за меньшее количество времени",
+    softwareTitle: "Программное обеспечение",
+    softwareText:
+      "Разработано специальное ПО JointExplorer для мобильных устройств, позволяющее проводить предварительный полевой анализ данных, полученных с устройства, а также формировать файлы экспорта в виде таблиц по каждой точке съемки.",
+    tgChannel: "Телеграм-канал Joint Explorer ↗",
+    galleryTitle: "Прибор в работе",
+    galleryAlt: "Joint Explorer — полевые замеры",
+    ctaTitle: "По всем вопросам или предложениям",
+    ctaSubtitle: `Просьба писать на почту ${site.email} или заполнить форму, представленную ниже.`,
+  },
+}[locale];
+
+const gallery = [
+  "/images/IMG_20230712_205454.jpg",
+  "/images/IMG_20230712_205500.jpg",
+  "/images/IMG_20230712_205505.jpg",
+  "/images/IMG_20230712_205512.jpg",
+  "/images/IMG_20230712_205533.jpg",
+  "/images/IMG_20230712_205542.jpg",
+  "/images/IMG_20230712_205551.jpg",
+  "/images/IMG_20230712_205557.jpg",
+  "/images/IMG_20230712_205602.jpg",
+  "/images/IMG_20230712_205615.jpg",
+];
+---
+
+<Base title="Joint Explorer" description={copy.description} locale={locale}>
+  <PageHero title="Joint Explorer" subtitle={copy.heroSubtitle} image="/images/photo_2022-08-25_21-.jpg" />
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
+      <div class="rounded-2xl border border-slate-200 bg-slate-50 p-8">
+        <h2 class="text-2xl font-bold text-night-950">{copy.softwareTitle}</h2>
+        <p class="mt-4 leading-relaxed text-slate-700">{copy.softwareText}</p>
+        <a
+          href="https://t.me/jointexplorer"
+          target="_blank"
+          rel="noopener"
+          class="mt-5 inline-block rounded-lg bg-accent-300 px-5 py-2.5 text-sm font-semibold text-night-950 transition-colors hover:bg-accent-400"
+        >
+          {copy.tgChannel}
+        </a>
+      </div>
+    </div>
+  </section>
+
+  <section class="bg-slate-50">
+    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
+      <h2 class="text-3xl font-bold tracking-tight text-night-950">{copy.galleryTitle}</h2>
+      <div class="mt-8 columns-2 gap-4 sm:columns-3 lg:columns-5 [&>img]:mb-4">
+        {gallery.map((src) => (
+          <img src={src} alt={copy.galleryAlt} class="w-full rounded-xl border border-slate-200" loading="lazy" />
+        ))}
+      </div>
+    </div>
+  </section>
+
+  <CTAForm title={copy.ctaTitle} subtitle={copy.ctaSubtitle} locale={locale} />
+</Base>

+ 138 - 0
src/components/pages/MagicorePage.astro

@@ -0,0 +1,138 @@
+---
+import Base from "../../layouts/Base.astro";
+import PageHero from "../PageHero.astro";
+import CTAForm from "../CTAForm.astro";
+import { site } from "../../data/site";
+import { type Locale } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+
+const copy = {
+  en: {
+    description: "A service that automatically generates geomechanical core documentation from photographs using neural networks",
+    heroSubtitle: "A service for automatic generation of geomechanical core documentation from photographs",
+    purposeTitle: "Purpose",
+    purpose: [
+      "Verification of structural descriptions from field work",
+      "Processing of wells without structural documentation",
+      "Processing of archived materials",
+    ],
+    featuresTitle: "Features",
+    features: [
+      "Ties core photographs to depth",
+      "Identifies geomechanical intervals",
+      "Calculates RQD and FF/m",
+    ],
+    usageTitle: "How to use",
+    steps: [
+      { n: 1, text: `Visit ${site.external.magicoreApp}` },
+      { n: 2, text: "Upload an image" },
+      { n: 3, text: "Get documentation for your photograph" },
+    ],
+    try: "Try Magicore ↗",
+    exampleTitle: "Example of geomechanical documentation",
+    exampleAlt: "Magicore geomechanical documentation example",
+    registry: "The service is listed in the Russian software registry. Registry entry No. 28251 dated 19.05.2025.",
+    ctaTitle: `Call us at ${site.phone}`,
+    ctaSubtitle: "We will tell you all about the service and give you a video-call presentation.",
+  },
+  ru: {
+    description: "Сервис для автоматической генерации геомеханической документации керна по фотографии с применением нейросетей",
+    heroSubtitle: "Сервис для автоматической генерации геомеханической документации керна по фотографии",
+    purposeTitle: "Предназначение",
+    purpose: [
+      "Проверка структурного описания полевых работ",
+      "Обработка скважин без структурной документации",
+      "Обработка архивных материалов",
+    ],
+    featuresTitle: "Возможности",
+    features: [
+      "Привязывает фотографии керна по глубине",
+      "Выделяет геомеханические интервалы",
+      "Рассчитывает RQD и FF/m",
+    ],
+    usageTitle: "Использование",
+    steps: [
+      { n: 1, text: `Зайдите на сайт ${site.external.magicoreApp}` },
+      { n: 2, text: "Загрузите изображение" },
+      { n: 3, text: "Получите документацию по вашей фотографии" },
+    ],
+    try: "Попробовать Magicore ↗",
+    exampleTitle: "Пример геомеханической документации",
+    exampleAlt: "Пример геомеханической документации Magicore",
+    registry: "Сервис внесён в реестр российского ПО. Реестровая запись №28251 от 19.05.2025.",
+    ctaTitle: `Звоните по номеру ${site.phone}`,
+    ctaSubtitle: "Мы подробно расскажем Вам о данном сервисе, проведем для Вас презентацию в формате видео-звонка.",
+  },
+}[locale];
+---
+
+<Base title="Magicore" description={copy.description} locale={locale}>
+  <PageHero title="Magicore" subtitle={copy.heroSubtitle} image="/images/image.png" />
+
+  <section class="bg-white">
+    <div class="mx-auto grid max-w-7xl gap-10 px-4 py-16 sm:px-6 lg:grid-cols-2">
+      <div class="rounded-2xl border border-slate-200 p-8">
+        <h2 class="text-2xl font-bold text-night-950">{copy.purposeTitle}</h2>
+        <ul class="mt-5 space-y-3">
+          {copy.purpose.map((p) => (
+            <li class="flex gap-3 text-slate-700">
+              <svg class="mt-0.5 h-5 w-5 shrink-0 text-accent-500" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+                <path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z" clip-rule="evenodd" />
+              </svg>
+              {p}
+            </li>
+          ))}
+        </ul>
+      </div>
+      <div class="rounded-2xl border border-slate-200 p-8">
+        <h2 class="text-2xl font-bold text-night-950">{copy.featuresTitle}</h2>
+        <ul class="mt-5 space-y-3">
+          {copy.features.map((p) => (
+            <li class="flex gap-3 text-slate-700">
+              <svg class="mt-0.5 h-5 w-5 shrink-0 text-accent-500" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+                <path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z" clip-rule="evenodd" />
+              </svg>
+              {p}
+            </li>
+          ))}
+        </ul>
+      </div>
+    </div>
+  </section>
+
+  <section class="bg-slate-50">
+    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
+      <h2 class="text-3xl font-bold tracking-tight text-night-950">{copy.usageTitle}</h2>
+      <div class="mt-8 grid gap-6 sm:grid-cols-3">
+        {copy.steps.map((s) => (
+          <div class="rounded-2xl bg-white p-6 shadow-sm">
+            <span class="flex h-10 w-10 items-center justify-center rounded-full bg-accent-300 font-bold text-night-950">{s.n}</span>
+            <p class="mt-4 text-sm leading-relaxed text-slate-700">{s.text}</p>
+          </div>
+        ))}
+      </div>
+      <a
+        href={site.external.magicoreApp}
+        target="_blank"
+        rel="noopener"
+        class="mt-8 inline-block rounded-lg bg-accent-300 px-6 py-3 font-semibold text-night-950 transition-colors hover:bg-accent-400"
+      >
+        {copy.try}
+      </a>
+    </div>
+  </section>
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
+      <h2 class="text-3xl font-bold tracking-tight text-night-950">{copy.exampleTitle}</h2>
+      <img src="/images/image-y390se.png" alt={copy.exampleAlt} class="mt-8 w-full rounded-2xl border border-slate-200" loading="lazy" />
+      <p class="mt-6 text-sm text-slate-500">{copy.registry}</p>
+    </div>
+  </section>
+
+  <CTAForm title={copy.ctaTitle} subtitle={copy.ctaSubtitle} locale={locale} />
+</Base>

+ 145 - 0
src/components/pages/NurPage.astro

@@ -0,0 +1,145 @@
+---
+import Base from "../../layouts/Base.astro";
+import PageHero from "../PageHero.astro";
+import { type Locale } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+
+const copy = {
+  en: {
+    title: "NUR Extensometer",
+    description:
+      "An instrument for automated monitoring of rock spalling, joint opening, convergence of underground openings, and failure control on open-pit slopes",
+    heroSubtitle:
+      "An instrument for automated displacement monitoring based on a laser distance sensor. It works by high-frequency measurement of the distance to a reflective surface and transfers the data to a server",
+    specsTitle: "Specifications",
+    applicationsTitle: "Applications",
+    applications: [
+      "The NUR extensometer is designed for monitoring rock spalling, joint opening, convergence of underground openings, and failure control on open-pit slopes and in the walls and backs of underground openings.",
+      "The measurement accuracy is sufficient to capture displacements at early stages of failure. The high measurement frequency allows displacement velocities to be determined, making it possible to predict the time of failure and issue alerts when critical velocities are reached (similar to interferometric radars).",
+      "To date, the instrument has been tested in open pits, where it proved effective. Testing in underground openings has not yet been carried out.",
+    ],
+    installationTitle: "Installation",
+    installation: [
+      "The instrument is mounted on a special bracket that provides fixation and 360° rotation",
+      "A solar panel is connected for continuous, fully automated operation",
+    ],
+    installationAlt: "NUR extensometer installation",
+    bracketAlt: "NUR extensometer mounting bracket",
+    monitoringTitle: "Monitoring",
+    monitoringText:
+      "Extensometer measurements are displayed as charts in our web service. The web service shows distances, displacement velocities and more in real time. Alerts for exceeding critical velocities are configurable.",
+    monitoringAlt: "Displacement monitoring charts",
+  },
+  ru: {
+    title: "Экстензометр NUR",
+    description:
+      "Прибор для автоматизированного мониторинга заколов, раскрытия трещин, конвергенции подземных выработок, контроля вывалов в откосах карьеров",
+    heroSubtitle:
+      "Прибор для автоматизированного мониторинга смещений, использующий лазерный датчик расстояния. Принцип работы заключается в высокочастотном измерении расстояния до отражающей поверхности и передаче данных на сервер",
+    specsTitle: "Характеристики",
+    applicationsTitle: "Применение",
+    applications: [
+      "Экстензометр NUR предназначен для мониторинга заколов, раскрытия трещин, конвергенции подземных выработок, контроля вывалов в откосах карьеров, в боку и кровле подземных выработок.",
+      "Точность измерений прибора достаточна для фиксации смещений на ранних этапах обрушений. Благодаря высокой частоте измерений возможно определение скоростей смещений, что делает возможность прогноза времени обрушений, оповещений по достижению критических скоростей (аналогично интерферометрическим радарам).",
+      "На данный момент прибор был испытан на карьерах, где показал свою эффективность. Испытания в подземных выработках пока не проводились.",
+    ],
+    installationTitle: "Установка",
+    installation: [
+      "Прибор устанавливается на специальное крепление, обеспечивающее фиксацию и поворот на 360°",
+      "Для непрерывной и полностью автоматизированной работы подключается солнечная панель",
+    ],
+    installationAlt: "Установка экстензометра NUR",
+    bracketAlt: "Крепление экстензометра NUR",
+    monitoringTitle: "Мониторинг",
+    monitoringText:
+      "Результаты замеров экстензометром отображаются на графиках в нашем веб-сервисе. Веб-сервис позволяет в режиме реального времени отображать расстояния, скорости смещений и т.д. Настраиваются оповещения по превышению критических скоростей.",
+    monitoringAlt: "Графики мониторинга смещений",
+  },
+}[locale];
+
+const specs = {
+  en: [
+    ["Measurement range", "0–40 m"],
+    ["Measurement accuracy (RMS)", "1 mm"],
+    ["Resolution", "1 mm"],
+    ["Measurement frequency", "configurable, from 1 sec⁻¹"],
+    ["Online displacement monitoring", "with ~1 s latency"],
+    ["Data transfer", "via GSM (radio and other channels planned)"],
+    ["Alerts", "via Telegram bot, SMS, e-mail"],
+    ["Autonomous power supply", "5 V"],
+    ["Autonomy", "when connected to a solar panel"],
+    ["Battery capacity", "38900 mAh (144 Wh)"],
+    ["Moisture and dust protection", "IP65"],
+    ["Laser hazard class", "2"],
+  ],
+  ru: [
+    ["Диапазон измерений", "0–40 м"],
+    ["Точность измерений (СКО)", "1 мм"],
+    ["Разрешающая способность", "1 мм"],
+    ["Частота измерений", "настраиваемая, от 1 сек⁻¹"],
+    ["Мониторинг смещений онлайн", "с задержкой в ~1 сек"],
+    ["Передача данных", "посредством GSM (планируется реализация посредством радиосвязи и др.)"],
+    ["Оповещения", "через телеграм-бот, SMS, e-mail"],
+    ["Источник автономного питания", "5 В"],
+    ["Автономность", "при подключении к солнечной панели"],
+    ["Емкость аккумулятора", "38900 mAh (144 Wh)"],
+    ["Влаго- и пылезащита", "IP65"],
+    ["Класс опасности лазера", "2"],
+  ],
+}[locale];
+---
+
+<Base title={copy.title} description={copy.description} locale={locale}>
+  <PageHero title={copy.title} subtitle={copy.heroSubtitle} image="/images/PXL_20240408_0840372.jpg" />
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
+      <h2 class="text-3xl font-bold tracking-tight text-night-950">{copy.specsTitle}</h2>
+      <dl class="mt-8 grid gap-x-10 gap-y-0 sm:grid-cols-2">
+        {specs.map(([k, v]) => (
+          <div class="flex flex-col gap-1 border-b border-slate-200 py-3.5 sm:flex-row sm:items-baseline sm:justify-between sm:gap-6">
+            <dt class="text-sm font-medium text-slate-500">{k}</dt>
+            <dd class="text-sm font-semibold text-night-950 sm:text-right">{v}</dd>
+          </div>
+        ))}
+      </dl>
+    </div>
+  </section>
+
+  <section class="bg-slate-50">
+    <div class="mx-auto grid max-w-7xl gap-8 px-4 py-16 sm:px-6 lg:grid-cols-2">
+      <div class="rounded-2xl border border-slate-200 bg-white p-8">
+        <h2 class="text-2xl font-bold text-night-950">{copy.applicationsTitle}</h2>
+        {copy.applications.map((p) => (
+          <p class="mt-4 text-sm leading-relaxed text-slate-700">{p}</p>
+        ))}
+      </div>
+      <div class="space-y-8">
+        <div class="rounded-2xl border border-slate-200 bg-white p-8">
+          <h2 class="text-2xl font-bold text-night-950">{copy.installationTitle}</h2>
+          <ul class="mt-4 space-y-3 text-sm leading-relaxed text-slate-700">
+            {copy.installation.map((item) => (
+              <li class="flex gap-3">
+                <span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
+                {item}
+              </li>
+            ))}
+          </ul>
+          <div class="mt-6 grid grid-cols-2 gap-4">
+            <img src="/images/1-2nktvc.png" alt={copy.installationAlt} class="aspect-square w-full rounded-xl object-cover" loading="lazy" />
+            <img src="/images/2.png" alt={copy.bracketAlt} class="aspect-square w-full rounded-xl object-cover" loading="lazy" />
+          </div>
+        </div>
+        <div class="rounded-2xl border border-slate-200 bg-white p-8">
+          <h2 class="text-2xl font-bold text-night-950">{copy.monitoringTitle}</h2>
+          <p class="mt-4 text-sm leading-relaxed text-slate-700">{copy.monitoringText}</p>
+          <img src="/images/321.jpg" alt={copy.monitoringAlt} class="mt-6 w-full rounded-xl border border-slate-200" loading="lazy" />
+        </div>
+      </div>
+    </div>
+  </section>
+</Base>

+ 59 - 0
src/components/pages/PersonalDataPage.astro

@@ -0,0 +1,59 @@
+---
+import Base from "../../layouts/Base.astro";
+import { policySections } from "../../data/personal-data";
+import { type Locale } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+const sections = policySections[locale];
+
+const copy = {
+  en: {
+    title: "Privacy policy",
+    description: "Personal data processing policy of Scientia LLC",
+    h1: "Personal data processing policy",
+  },
+  ru: {
+    title: "Персональные данные",
+    description: "Политика в отношении обработки персональных данных ООО «Скиентия»",
+    h1: "Политика в отношении обработки персональных данных",
+  },
+}[locale];
+---
+
+<Base title={copy.title} description={copy.description} locale={locale}>
+  <section class="bg-white">
+    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
+      <h1 class="text-3xl font-bold tracking-tight text-night-950 sm:text-4xl">
+        {copy.h1}
+      </h1>
+      <div class="mt-10 space-y-10">
+        {sections.map((s) => (
+          <section>
+            <h2 class="text-xl font-bold text-night-950">{s.title}</h2>
+            {s.intro && <p class="mt-3 text-sm leading-relaxed text-slate-700">{s.intro}</p>}
+            {s.items && (
+              <div class="mt-3 space-y-3">
+                {s.items.map((item) => (
+                  <p class="text-sm leading-relaxed text-slate-700">{item}</p>
+                ))}
+              </div>
+            )}
+            {s.table && (
+              <dl class="mt-4 divide-y divide-slate-200 rounded-xl border border-slate-200">
+                {s.table.map(([k, v]) => (
+                  <div class="grid gap-1 p-4 sm:grid-cols-4 sm:gap-6">
+                    <dt class="text-sm font-semibold text-night-950">{k}</dt>
+                    <dd class="text-sm leading-relaxed text-slate-700 sm:col-span-3">{v}</dd>
+                  </div>
+                ))}
+              </dl>
+            )}
+          </section>
+        ))}
+      </div>
+    </div>
+  </section>
+</Base>

+ 122 - 0
src/components/pages/ProrockFeaturesPage.astro

@@ -0,0 +1,122 @@
+---
+import Base from "../../layouts/Base.astro";
+import PageHero from "../PageHero.astro";
+import { type Locale } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+
+const sections = {
+  en: [
+    {
+      title: "High simulation realism",
+      body: [
+        "In contrast to the commonly accepted approaches to solving geomechanics problems, the software's mathematical engine performs explicit modeling of rock failure processes: crack formation is computed explicitly as shape changes and the disappearance of joint elements. Further interaction of the individual elements is computed by mechanical interaction algorithms.",
+        "Rock mass jointing is taken into account. The model can be populated with joint systems of any structure whose mechanical parameters differ from those of the host rock. This captures the significant influence of jointing on geomechanical processes, which is difficult to account for with conventional methods.",
+        "PROROCK accounts for the staged development of excavations, i.e. deformation development can be predicted at each stage of mining.",
+        "Dynamic processes can be analyzed in PROROCK, for example the movement and arrest of collapse bodies.",
+      ],
+    },
+    {
+      title: "Low cost per solution",
+      body: [
+        "PROROCK will be distributed by subscription: users pay for the time they use the software, not for purchasing it. The cost of using it is an order of magnitude below the average contract value for geomechanical justification studies. This makes it affordable for specialists at any company, including young and small ones.",
+        "Calculations use cloud computing. The solver performs computations in the cloud, eliminating the need to purchase expensive computing hardware.",
+      ],
+    },
+    {
+      title: "Convenience and ease of use",
+      body: [
+        "PROROCK's graphical interface is more intuitive and convenient than most existing numerical modeling solutions in geomechanics.",
+        "High-performance GPUs in the cloud make calculations faster than in desktop-only applications.",
+      ],
+    },
+    {
+      title: "Greater completeness of output data",
+      body: [
+        "The numerical mechanical method underlying the solver produces data that cannot be obtained by other means — for example, information on joint opening, spalling magnitude, the size of the failure zone, the safety of undermined water bodies, and more.",
+      ],
+    },
+    {
+      title: "Powerful tools for analyzing calculation results",
+      body: [
+        "For the user's convenience, PROROCK includes built-in tools for building charts and diagrams and many ways to display output data. Intuitive tools for generating reports after calculations will be implemented in PROROCK, minimizing the specialist's work.",
+      ],
+    },
+  ],
+  ru: [
+    {
+      title: "Высокая реалистичность моделирования",
+      body: [
+        "Математический аппарат программы позволяет, в отличие от общепринятых способов расчетов любых задач геомеханики, выполнять явное моделирование процессов разрушения горных пород: образование трещин рассчитывается в явном виде как изменение формы и исчезновение трещинных элементов. Дальнейшее взаимодействие отдельных элементов рассчитывается алгоритмами учета механических взаимодействий.",
+        "Учет трещиноватости массивов горных пород. Модель возможно заселить системами трещин любой структуры с механическими параметрами, отличными от параметров горных пород. Таким образом учитывается значительное влияние трещиноватости на геомеханические процессы, которое сложно учесть традиционными способами.",
+        "Программа PROROCK позволяет учесть стадийность образования выработок, то есть выполнять прогноз развития деформаций на каждом этапе развития горных работ.",
+        "В PROROCK можно анализировать динамические процессы, например перемещение и остановку тел обрушения.",
+      ],
+    },
+    {
+      title: "Низкая стоимость отдельного решения",
+      body: [
+        "Программа PROROCK будет распространяться по подписке, то есть пользователи будут платить за время пользования программой, а не за ее приобретение. Стоимость ее использования на порядок ниже среднего чека по договорам на выполнение геомеханических обоснований. Поэтому позволить себе воспользоваться ею смогут специалисты любых компаний, в том числе молодых и небольших.",
+        "Для выполнения расчетов используются облачные вычисления. Программа-процессор производит вычисления на облаке, благодаря чему отпадает необходимость приобретения дорогостоящих вычислительных устройств.",
+      ],
+    },
+    {
+      title: "Удобство и простота использования",
+      body: [
+        "Графический интерфейс программы PROROCK интуитивно понятнее и удобнее большинства существующих решений для численного моделирования в геомеханике.",
+        "Применение производительных графических процессоров, расположенных в облаке, позволит выполнять расчеты быстрее, чем в приложениях, работающих только на десктопе.",
+      ],
+    },
+    {
+      title: "Большая полнота выходных данных",
+      body: [
+        "Численный метод механики, лежащий в основе программы-процессора, позволяет получать данные, которые невозможно получить другими способами. В качестве примеров можно привести сведения о раскрытии трещин, о величине заколов, о размерах зоны разрушений, о безопасности подрабатываемых водных объектов и т.д.",
+      ],
+    },
+    {
+      title: "Мощный функционал для анализа результатов расчетов",
+      body: [
+        "Для удобства пользователя в программе PROROCK предусмотрены встроенные средства для построения графиков, диаграмм и множество способов отображения выходных данных. В программе PROROCK будут реализованы интуитивно понятные инструменты для генерации отчетов после выполненных расчетов, что будет сводить работу специалиста к минимуму.",
+      ],
+    },
+  ],
+}[locale];
+
+const copy = {
+  en: {
+    title: "Prorock: key features",
+    description: "PROROCK key features: high simulation realism, low cost, ease of use, completeness of output data",
+    heroTitle: "Key features",
+    heroSubtitle: "Below are the characteristics of the version 1.0 service, currently in development",
+  },
+  ru: {
+    title: "Prorock: особенности",
+    description: "Особенности PROROCK: высокая реалистичность моделирования, низкая стоимость, удобство использования, полнота выходных данных",
+    heroTitle: "Ключевые особенности",
+    heroSubtitle: "Далее описаны характеристики сервиса версии 1.0, находящегося в разработке",
+  },
+}[locale];
+---
+
+<Base title={copy.title} description={copy.description} locale={locale}>
+  <PageHero title={copy.heroTitle} subtitle={copy.heroSubtitle} />
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-4xl space-y-8 px-4 py-16 sm:px-6">
+      {sections.map((s, i) => (
+        <article class="rounded-2xl border border-slate-200 p-8">
+          <span class="text-sm font-bold uppercase tracking-wider text-accent-600">{String(i + 1).padStart(2, "0")}</span>
+          <h2 class="mt-2 text-2xl font-bold text-night-950">{s.title}</h2>
+          <div class="mt-4 space-y-4">
+            {s.body.map((p) => (
+              <p class="leading-relaxed text-slate-700">{p}</p>
+            ))}
+          </div>
+        </article>
+      ))}
+    </div>
+  </section>
+</Base>

+ 199 - 0
src/components/pages/ProrockPage.astro

@@ -0,0 +1,199 @@
+---
+import Base from "../../layouts/Base.astro";
+import PageHero from "../PageHero.astro";
+import CTAForm from "../CTAForm.astro";
+import { type Locale, localePath } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+const lp = (path: string) => localePath(locale, path);
+
+const copy = {
+  en: {
+    description: "A new tool for advanced numerical modeling in geomechanics. Simulation of failure and dynamic processes using the combined finite-discrete element method",
+    heroSubtitle: "A new tool for advanced numerical modeling in geomechanics",
+    updates: "Release history",
+    featuresTitle: "Key features",
+    features: [
+      "Interactive definition of lithology, tectonic structures, bolt support, in-situ stresses, boundary conditions and external loads",
+      "Display of point data, principal stress vectors, layer bending",
+      "Import of rasters and DXF",
+      "Generation of discrete fracture networks (DFN)",
+      "Automatic error detection and geometry correction",
+      "FDEM-optimized mesh generation",
+      "Modeling of excavation, property changes, draw",
+      "10 types of result visualization",
+      "Bulk screenshot generation",
+      "Text export of results",
+    ],
+    mathText:
+      "The powerful mathematical engine of the software models deformation processes with arbitrary strain magnitudes — both elastic and those involving loss of continuity, fragmentation, and subsequent movement of the fragmented masses.",
+    applications: "Applications",
+    applicationItems: [
+      "Residual strength assessment",
+      "Slope stability calculation under undermining",
+      "Failures driven by structures and stresses",
+      "Prediction of subsidence and damage zones in the rock mass",
+      "Development of water-conducting fractures and voids",
+    ],
+    advantages: "Advantages",
+    advantageItems: [
+      "One of the fastest FDEM solvers in the world thanks to CUDA and optimization — calculations complete in minutes",
+      "High realism of geomechanical process simulation",
+      "Interface and technical support in Russian",
+      "The interface will feel intuitive to specialists who have worked in similar software",
+    ],
+    keyFeaturesCard: "Key features",
+    keyFeaturesCardText:
+      "High simulation realism: explicit failure modeling and rock mass jointing accounted for",
+    videoTitle: "Videos",
+    videoItems: [
+      "Prorock 2.0 overview: features, advantages, modules",
+      "Prorock 2.0 video tutorial: building a model and viewing calculation results",
+    ],
+    galleryAlt: "Prorock 2.0 — model example",
+    sysreq: "System requirements:",
+    sysreqText:
+      "OS: Windows 7 or later · GPU: NVIDIA with CUDA support (VRAM above 1 GB) · RAM: 4+ GB · Disk space: 1+ GB per project",
+    ctaTitle: "Want to learn more about Prorock? Fill in the form",
+    ctaSubtitle: "We will answer all your questions and give you a demo of the software's capabilities.",
+  },
+  ru: {
+    description: "Новый инструмент для продвинутого численного моделирования в геомеханике. Моделирование разрушений и динамических процессов методом конечно-дискретных элементов",
+    heroSubtitle: "Новый инструмент для продвинутого численного моделирования в геомеханике",
+    updates: "История обновлений",
+    featuresTitle: "Ключевые возможности",
+    features: [
+      "Интерактивное задание литологии, тектонических нарушений, анкерного крепления, природных напряжений, граничных условий и внешних нагрузок",
+      "Отображение точечных данных, векторов главных напряжений, изгиба слоев",
+      "Импорт растров и DXF",
+      "Генерация системной трещиноватости (DFN)",
+      "Автопоиск ошибок и автоматическое исправление геометрии",
+      "Оптимизированная для FDEM генерация сетки",
+      "Моделирование выемки, замены свойств, выпуска",
+      "10 видов визуализации результатов",
+      "Массовая генерация скриншотов",
+      "Экспорт результатов в текстовом виде",
+    ],
+    mathText:
+      "Мощный математический аппарат программы позволяет моделировать деформационные процессы с любыми величинами деформаций, как упругие, так и происходящие с разрывами сплошности, фрагментацией и последующим смещением фрагментированных масс.",
+    applications: "Применение",
+    applicationItems: [
+      "Оценка остаточной прочности",
+      "Расчет устойчивости бортов при подработке",
+      "Обрушения из-за структур и напряжений",
+      "Прогноз зон сдвижения, нарушенности в массиве",
+      "Образование водопроводящих трещин и пустот",
+    ],
+    advantages: "Преимущества",
+    advantageItems: [
+      "Один из самых быстрых FDEM-солверов в мире благодаря CUDA и оптимизации. Расчеты выполняются за минуты",
+      "Высокая реалистичность моделирования геомеханических процессов",
+      "Интерфейс программы и техническая поддержка на русском языке",
+      "Интерфейс программы будет интуитивно понятен для специалистов, работавших в аналогичных ПО",
+    ],
+    keyFeaturesCard: "Ключевые особенности",
+    keyFeaturesCardText:
+      "Высокая реалистичность моделирования: явное моделирование разрушения и учёт трещиноватости массива",
+    videoTitle: "Видео",
+    videoItems: [
+      "Общее описание Prorock 2.0: возможности, преимущества, модули",
+      "Видеоурок по Prorock 2.0: построение модели и просмотр результатов расчётов",
+    ],
+    galleryAlt: "Prorock 2.0 — пример модели",
+    sysreq: "Системные требования:",
+    sysreqText:
+      "ОС: Windows 7 или более поздняя · Видеокарта: NVIDIA с поддержкой технологии CUDA (видеопамять более 1 Гб) · Оперативная память: 4+ Гб · Место на диске: 1+ Гб / проект",
+    ctaTitle: "Если хотите узнать про Prorock больше, пожалуйста, заполните форму",
+    ctaSubtitle: "Мы ответим на все вопросы и проведём демонстрацию возможностей программы.",
+  },
+}[locale];
+
+const gallery = ["/images/21.jpg", "/images/1.jpg", "/images/3.jpg", "/images/4.png"];
+---
+
+<Base title="Prorock 2.0" description={copy.description} locale={locale}>
+  <PageHero title="PROROCK 2.0" subtitle={copy.heroSubtitle} image="/images/21.jpg">
+    <a href={lp("/prorock_updates")} class="mt-6 inline-block rounded-lg bg-accent-300 px-5 py-2.5 font-semibold text-night-950 transition-colors hover:bg-accent-400">
+      {copy.updates}
+    </a>
+  </PageHero>
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
+      <h2 class="text-3xl font-bold tracking-tight text-night-950">{copy.featuresTitle}</h2>
+      <ul class="mt-8 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
+        {copy.features.map((f) => (
+          <li class="flex gap-3 rounded-xl border border-slate-200 p-4 text-sm leading-relaxed text-slate-700">
+            <svg class="mt-0.5 h-5 w-5 shrink-0 text-accent-500" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+              <path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z" clip-rule="evenodd" />
+            </svg>
+            {f}
+          </li>
+        ))}
+      </ul>
+      <p class="mt-10 max-w-4xl text-lg leading-relaxed text-slate-700">
+        {copy.mathText}
+      </p>
+    </div>
+  </section>
+
+  <section class="bg-slate-50">
+    <div class="mx-auto grid max-w-7xl gap-8 px-4 py-16 sm:px-6 lg:grid-cols-2">
+      <div class="rounded-2xl border border-slate-200 bg-white p-8">
+        <h2 class="text-2xl font-bold text-night-950">{copy.applications}</h2>
+        <ul class="mt-5 space-y-3">
+          {copy.applicationItems.map((item) => (
+            <li class="flex gap-3 text-sm leading-relaxed text-slate-700">
+              <span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
+              {item}
+            </li>
+          ))}
+        </ul>
+      </div>
+      <div class="rounded-2xl border border-slate-200 bg-white p-8">
+        <h2 class="text-2xl font-bold text-night-950">{copy.advantages}</h2>
+        <ul class="mt-5 space-y-3">
+          {copy.advantageItems.map((item) => (
+            <li class="flex gap-3 text-sm leading-relaxed text-slate-700">
+              <span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
+              {item}
+            </li>
+          ))}
+        </ul>
+      </div>
+    </div>
+  </section>
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
+      <div class="grid gap-4 sm:grid-cols-2">
+        <a href={lp("/prorockfeatures")} class="rounded-2xl bg-night-900 p-8 text-white transition-colors hover:bg-night-800">
+          <h3 class="text-xl font-semibold">{copy.keyFeaturesCard}</h3>
+          <p class="mt-2 text-sm text-slate-300">{copy.keyFeaturesCardText}</p>
+        </a>
+        <div class="rounded-2xl border border-slate-200 p-8">
+          <h3 class="text-xl font-semibold text-night-950">{copy.videoTitle}</h3>
+          <ul class="mt-3 space-y-2 text-sm text-slate-600">
+            {copy.videoItems.map((item) => <li>{item}</li>)}
+          </ul>
+        </div>
+      </div>
+
+      <div class="mt-12 grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
+        {gallery.map((src) => (
+          <img src={src} alt={copy.galleryAlt} class="aspect-[4/3] w-full rounded-xl border border-slate-200 object-cover" loading="lazy" />
+        ))}
+      </div>
+
+      <div class="mt-12 rounded-2xl bg-slate-50 p-6 text-sm leading-relaxed text-slate-700">
+        <strong class="font-semibold text-night-950">{copy.sysreq}</strong>
+        {copy.sysreqText}
+      </div>
+    </div>
+  </section>
+
+  <CTAForm title={copy.ctaTitle} subtitle={copy.ctaSubtitle} locale={locale} />
+</Base>

+ 57 - 0
src/components/pages/ProrockUpdatesPage.astro

@@ -0,0 +1,57 @@
+---
+import Base from "../../layouts/Base.astro";
+import PageHero from "../PageHero.astro";
+import { prorockReleases } from "../../data/prorock-updates";
+import { type Locale } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+const releases = prorockReleases[locale];
+
+const copy = {
+  en: {
+    title: "Prorock updates",
+    description: "Release history of the Prorock software",
+    heroTitle: "Prorock updates",
+    heroSubtitle: "Changelog of the Prorock software suite",
+  },
+  ru: {
+    title: "Обновления Prorock",
+    description: "История обновлений ПО Prorock",
+    heroTitle: "Обновления Prorock",
+    heroSubtitle: "История изменений программного комплекса Prorock",
+  },
+}[locale];
+---
+
+<Base title={copy.title} description={copy.description} locale={locale}>
+  <PageHero title={copy.heroTitle} subtitle={copy.heroSubtitle} />
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
+      {releases.map((r) => (
+        <article class="rounded-2xl border border-slate-200 p-8">
+          <header class="flex flex-wrap items-baseline justify-between gap-2 border-b border-slate-200 pb-5">
+            <h2 class="text-2xl font-bold text-night-950">Release {r.version}</h2>
+            <time class="text-sm font-medium text-slate-500">{r.date}</time>
+          </header>
+          {r.sections.map((s) => (
+            <div class="mt-7">
+              <h3 class="text-lg font-semibold text-accent-600">{s.title}</h3>
+              <ul class="mt-3 space-y-2.5">
+                {s.items.map((item) => (
+                  <li class="flex gap-3 text-sm leading-relaxed text-slate-700">
+                    <span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
+                    {item}
+                  </li>
+                ))}
+              </ul>
+            </div>
+          ))}
+        </article>
+      ))}
+    </div>
+  </section>
+</Base>

+ 100 - 0
src/components/pages/ScientiaJointsPage.astro

@@ -0,0 +1,100 @@
+---
+import Base from "../../layouts/Base.astro";
+import PageHero from "../PageHero.astro";
+import { type Locale } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+
+const copy = {
+  en: {
+    description: "A plugin for the free and open-source Blender software, designed for digital joint mapping on 3D models",
+    heroSubtitle: "A plugin for the free and open-source Blender software, designed for digital joint mapping on 3D models",
+    featuresTitle: "Features",
+    features: [
+      "The plugin makes joint mapping much more visual — the jointing diagram for all measurements is visible in real time, giving you more representative data during the survey.",
+      "Photorealistic models can be used to collect information about joint spacing. For this, a histogram of the distribution of all measurements and statistical parameters of the resulting sample has been added.",
+      "Measurements can also be exported in CSV format.",
+      "Ring shaders have been added to the plugin to improve model visualization.",
+    ],
+    downloadTitle: "Free download",
+    downloadText:
+      "You can download the ScientiaJoints plugin completely free of charge. Plugin updates are posted in our Telegram channel, and we provide help with installation and use.",
+    downloadButton: "Download the plugin",
+    tgButton: "Telegram channel ↗",
+    guideTitle: "Plugin installation and usage guide",
+    guideText: "The guide is available in the company's Telegram channel and in our",
+  },
+  ru: {
+    description: "Плагин для свободно распространяемого ПО Blender, предназначенный для цифрового картирования трещин на трёхмерных моделях",
+    heroSubtitle: "Плагин для свободно распространяемого ПО Blender, предназначенный для цифрового картирования трещин на трёхмерных моделях",
+    featuresTitle: "Возможности",
+    features: [
+      "С помощью плагина процесс картирования трещины стал гораздо нагляднее. Теперь в реальном времени можно увидеть диаграмму трещиноватости для всех измерений. Это позволит вам получать более репрезентативные данные во время съемки.",
+      "На основе фотореалистичных моделей можно собирать информацию о расстоянии между трещинами. Для этого была добавлена гистограмма распределения всех выполненных измерений, а также статистические параметры созданной выборки.",
+      "Также появилась возможность экспортировать измерения в формате CSV.",
+      "В плагине добавлены кольцевые шейдеры для улучшения визуализации модели.",
+    ],
+    downloadTitle: "Скачать бесплатно",
+    downloadText:
+      "Скачать ScientiaJoints плагин вы можете абсолютно бесплатно. В нашем телеграм-канале будут появляться обновления плагина, мы оказываем помощь по его установке и использованию.",
+    downloadButton: "Скачать плагин",
+    tgButton: "Телеграм-канал ↗",
+    guideTitle: "Гайд по установке и использованию плагина",
+    guideText: "Инструкция доступна в телеграм-канале компании и в нашем",
+  },
+}[locale];
+---
+
+<Base title="ScientiaJoints" description={copy.description} locale={locale}>
+  <PageHero title="ScientiaJoints" subtitle={copy.heroSubtitle} image="/images/1.jpg" />
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
+      <h2 class="text-3xl font-bold tracking-tight text-night-950">{copy.featuresTitle}</h2>
+      <ul class="mt-8 space-y-5">
+        {copy.features.map((f) => (
+          <li class="flex gap-4 leading-relaxed text-slate-700">
+            <svg class="mt-1 h-6 w-6 shrink-0 text-accent-500" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+              <path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z" clip-rule="evenodd" />
+            </svg>
+            {f}
+          </li>
+        ))}
+      </ul>
+
+      <div class="mt-12 rounded-2xl bg-night-900 p-8 text-white">
+        <h2 class="text-2xl font-bold">{copy.downloadTitle}</h2>
+        <p class="mt-3 max-w-2xl text-slate-300">{copy.downloadText}</p>
+        <div class="mt-6 flex flex-wrap gap-3">
+          <a
+            href="https://files.scientia.ru/public/588e8945a470"
+            target="_blank"
+            rel="noopener"
+            class="rounded-lg bg-accent-300 px-6 py-3 font-semibold text-night-950 transition-colors hover:bg-accent-400"
+          >
+            {copy.downloadButton}
+          </a>
+          <a
+            href="https://t.me/scientia_ru"
+            target="_blank"
+            rel="noopener"
+            class="rounded-lg border border-white/25 px-6 py-3 font-semibold transition-colors hover:bg-white/10"
+          >
+            {copy.tgButton}
+          </a>
+        </div>
+      </div>
+
+      <div class="mt-10 rounded-2xl border border-slate-200 p-6">
+        <h3 class="font-semibold text-night-950">{copy.guideTitle}</h3>
+        <p class="mt-2 text-sm text-slate-600">
+          {copy.guideText}
+          <a href="https://wiki.scientia.ru/" target="_blank" rel="noopener" class="text-accent-600 hover:text-accent-700">Wiki</a>.
+        </p>
+      </div>
+    </div>
+  </section>
+</Base>

+ 98 - 0
src/components/pages/SubscribePage.astro

@@ -0,0 +1,98 @@
+---
+import Base from "../../layouts/Base.astro";
+import PageHero from "../PageHero.astro";
+import { site } from "../../data/site";
+import { type Locale, localePath, translator } from "../../i18n";
+
+interface Props {
+  locale: Locale;
+}
+const { locale } = Astro.props;
+const t = translator(locale);
+const lp = (path: string) => localePath(locale, path);
+
+const copy = {
+  en: {
+    title: "Newsletter",
+    description: "Receive up-to-date knowledge from practitioner experts and news about our software",
+    heroSubtitle: "Receive up-to-date knowledge from practitioner experts and news about our software — updates and practical case studies",
+    submit: "Subscribe",
+    consent: "By clicking the button, you consent to the processing of personal data and agree to the",
+    consentLink: "privacy policy",
+    tgText: "Also subscribe to our Telegram channels:",
+  },
+  ru: {
+    title: "Рассылка",
+    description: "Получайте актуальные знания от экспертов-практиков и информацию о нашем программном обеспечении",
+    heroSubtitle: "Получайте актуальные знания от экспертов-практиков и информацию о нашем программном обеспечении — обновления и практические кейсы",
+    submit: "Подписаться",
+    consent: "Нажимая на кнопку, вы даёте согласие на обработку персональных данных и соглашаетесь c",
+    consentLink: "политикой конфиденциальности",
+    tgText: "Также подписывайтесь на наши Телеграм-каналы:",
+  },
+}[locale];
+---
+
+<Base title={copy.title} description={copy.description} locale={locale}>
+  <PageHero title={copy.title} subtitle={copy.heroSubtitle} />
+
+  <section class="bg-white">
+    <div class="mx-auto max-w-xl px-4 py-16 sm:px-6">
+      <!-- Static hosting: subscribe composes an email instead of posting to a backend. -->
+      <form id="subscribe-form" data-locale={locale} class="rounded-2xl border border-slate-200 p-8 shadow-sm">
+        <label class="block">
+          <span class="mb-1.5 block text-sm font-medium text-night-950">E-mail</span>
+          <input
+            required
+            type="email"
+            name="email"
+            autocomplete="email"
+            placeholder="you@company.com"
+            class="w-full rounded-lg border border-slate-300 px-3.5 py-2.5 text-sm outline-none transition-colors focus:border-accent-400 focus:ring-2 focus:ring-accent-200"
+          />
+        </label>
+        <button
+          type="submit"
+          class="mt-5 w-full rounded-lg bg-accent-300 px-5 py-3 text-sm font-semibold text-night-950 transition-colors hover:bg-accent-400"
+        >
+          {copy.submit}
+        </button>
+        <p class="mt-4 text-xs leading-relaxed text-slate-500">
+          {copy.consent}
+          <a href={lp("/personal_data")} class="underline hover:text-night-900">{copy.consentLink}</a>.
+        </p>
+      </form>
+
+      <div class="mt-10 rounded-2xl bg-slate-50 p-6 text-sm text-slate-700">
+        {copy.tgText}
+        <ul class="mt-3 space-y-1.5">
+          {site.telegram.map((tg) => (
+            <li>
+              <a href={tg.href} target="_blank" rel="noopener" class="font-medium text-accent-600 hover:text-accent-700">
+                {locale === "en" && tg.nameEn ? tg.nameEn : tg.name} ↗
+              </a>
+            </li>
+          ))}
+        </ul>
+      </div>
+    </div>
+  </section>
+</Base>
+
+<script>
+  const form = document.getElementById("subscribe-form") as HTMLFormElement | null;
+  form?.addEventListener("submit", (e) => {
+    e.preventDefault();
+    const locale = form.dataset.locale === "ru" ? "ru" : "en";
+    const email = new FormData(form).get("email");
+    const labels =
+      locale === "ru"
+        ? { subject: "Подписка на рассылку scientia.ru", body: "Прошу добавить в рассылку: " + email }
+        : { subject: "scientia.ru newsletter subscription", body: "Please add me to the newsletter: " + email };
+    window.location.href =
+      "mailto:info@scientia.ru?subject=" +
+      encodeURIComponent(labels.subject) +
+      "&body=" +
+      encodeURIComponent(labels.body);
+  });
+</script>

+ 37 - 17
src/data/digger-updates.ts

@@ -1,4 +1,5 @@
 // Generated from the live scientia.ru/diggerslope_updates page.
+import type { Localized } from "../i18n";
 
 export type Release = {
   version: string;
@@ -6,20 +7,39 @@ export type Release = {
   sections: { title: string; items: string[] }[];
 };
 
-export const diggerReleases: Release[] = [
-  {
-    "version": "1.3.345",
-    "date": "30.04.2026",
-    "sections": [
-      {
-        "title": "Новые возможности",
-        "items": [
-          "Оптимизированы расчёты",
-          "Добавлен формат экспорта в Excel",
-          "Добавлена опция корректировки бермы в секторах",
-          "Добавлена настройка стартовой папки"
-        ]
-      }
-    ]
-  }
-];
+export const diggerReleases: Localized<Release[]> = {
+  en: [
+    {
+      version: "1.3.345",
+      date: "30.04.2026",
+      sections: [
+        {
+          title: "New features",
+          items: [
+            "Optimized calculations",
+            "Added Excel export format",
+            "Added an option to adjust the berm in sectors",
+            "Added a startup folder setting",
+          ],
+        },
+      ],
+    },
+  ],
+  ru: [
+    {
+      version: "1.3.345",
+      date: "30.04.2026",
+      sections: [
+        {
+          title: "Новые возможности",
+          items: [
+            "Оптимизированы расчёты",
+            "Добавлен формат экспорта в Excel",
+            "Добавлена опция корректировки бермы в секторах",
+            "Добавлена настройка стартовой папки",
+          ],
+        },
+      ],
+    },
+  ],
+};

+ 303 - 150
src/data/personal-data.ts

@@ -1,4 +1,5 @@
 // Политика в отношении обработки персональных данных — migrated from scientia.ru/personal_data
+import type { Localized } from "../i18n";
 
 export type PolicySection = {
   title: string;
@@ -7,153 +8,305 @@ export type PolicySection = {
   table?: [string, string][];
 };
 
-export const policySections: PolicySection[] = [
-  {
-    title: "1. Общие положения",
-    intro:
-      "Настоящая политика обработки персональных данных составлена в соответствии с требованиями Федерального закона от 27.07.2006. № 152-ФЗ «О персональных данных» (далее — Закон о персональных данных) и определяет порядок обработки персональных данных и меры по обеспечению безопасности персональных данных, предпринимаемые ООО \"Скиентия\" (далее — Оператор).",
-    items: [
-      "1.1. Оператор ставит своей важнейшей целью и условием осуществления своей деятельности соблюдение прав и свобод человека и гражданина при обработке его персональных данных, в том числе защиты прав на неприкосновенность частной жизни, личную и семейную тайну.",
-      "1.2. Настоящая политика Оператора в отношении обработки персональных данных (далее — Политика) применяется ко всей информации, которую Оператор может получить о посетителях веб-сайта https://scientia.ru.",
-    ],
-  },
-  {
-    title: "2. Основные понятия, используемые в Политике",
-    items: [
-      "2.1. Автоматизированная обработка персональных данных — обработка персональных данных с помощью средств вычислительной техники.",
-      "2.2. Блокирование персональных данных — временное прекращение обработки персональных данных (за исключением случаев, если обработка необходима для уточнения персональных данных).",
-      "2.3. Веб-сайт — совокупность графических и информационных материалов, а также программ для ЭВМ и баз данных, обеспечивающих их доступность в сети интернет по сетевому адресу https://scientia.ru.",
-      "2.4. Информационная система персональных данных — совокупность содержащихся в базах данных персональных данных и обеспечивающих их обработку информационных технологий и технических средств.",
-      "2.5. Обезличивание персональных данных — действия, в результате которых невозможно определить без использования дополнительной информации принадлежность персональных данных конкретному Пользователю или иному субъекту персональных данных.",
-      "2.6. Обработка персональных данных — любое действие (операция) или совокупность действий (операций), совершаемых с использованием средств автоматизации или без использования таких средств с персональными данными, включая сбор, запись, систематизацию, накопление, хранение, уточнение (обновление, изменение), извлечение, использование, передачу (распространение, предоставление, доступ), обезличивание, блокирование, удаление, уничтожение персональных данных.",
-      "2.7. Оператор — государственный орган, муниципальный орган, юридическое или физическое лицо, самостоятельно или совместно с другими лицами организующие и/или осуществляющие обработку персональных данных, а также определяющие цели обработки персональных данных, состав персональных данных, подлежащих обработке, действия (операции), совершаемые с персональными данными.",
-      "2.8. Персональные данные — любая информация, относящаяся прямо или косвенно к определенному или определяемому Пользователю веб-сайта https://scientia.ru.",
-      "2.9. Персональные данные, разрешенные субъектом персональных данных для распространения, — персональные данные, доступ неограниченного круга лиц к которым предоставлен субъектом персональных данных путем дачи согласия на обработку персональных данных, разрешенных субъектом персональных данных для распространения в порядке, предусмотренном Законом о персональных данных (далее — персональные данные, разрешенные для распространения).",
-      "2.10. Пользователь — любой посетитель веб-сайта https://scientia.ru.",
-      "2.11. Предоставление персональных данных — действия, направленные на раскрытие персональных данных определенному лицу или определенному кругу лиц.",
-      "2.12. Распространение персональных данных — любые действия, направленные на раскрытие персональных данных неопределенному кругу лиц (передача персональных данных) или на ознакомление с персональными данными неограниченного круга лиц, в том числе обнародование персональных данных в средствах массовой информации, размещение в информационно-телекоммуникационных сетях или предоставление доступа к персональным данным каким-либо иным способом.",
-      "2.13. Трансграничная передача персональных данных — передача персональных данных на территорию иностранного государства органу власти иностранного государства, иностранному физическому или иностранному юридическому лицу.",
-      "2.14. Уничтожение персональных данных — любые действия, в результате которых персональные данные уничтожаются безвозвратно с невозможностью дальнейшего восстановления содержания персональных данных в информационной системе персональных данных и/или уничтожаются материальные носители персональных данных.",
-    ],
-  },
-  {
-    title: "3. Основные права и обязанности Оператора",
-    intro: "3.1. Оператор имеет право:",
-    items: [
-      "— получать от субъекта персональных данных достоверные информацию и/или документы, содержащие персональные данные;",
-      "— в случае отзыва субъектом персональных данных согласия на обработку персональных данных, а также, направления обращения с требованием о прекращении обработки персональных данных, Оператор вправе продолжить обработку персональных данных без согласия субъекта персональных данных при наличии оснований, указанных в Законе о персональных данных;",
-      "— самостоятельно определять состав и перечень мер, необходимых и достаточных для обеспечения выполнения обязанностей, предусмотренных Законом о персональных данных и принятыми в соответствии с ним нормативными правовыми актами, если иное не предусмотрено Законом о персональных данных или другими федеральными законами.",
-      "3.2. Оператор обязан:",
-      "— предоставлять субъекту персональных данных по его просьбе информацию, касающуюся обработки его персональных данных;",
-      "— организовывать обработку персональных данных в порядке, установленном действующим законодательством РФ;",
-      "— отвечать на обращения и запросы субъектов персональных данных и их законных представителей в соответствии с требованиями Закона о персональных данных;",
-      "— сообщать в уполномоченный орган по защите прав субъектов персональных данных по запросу этого органа необходимую информацию в течение 10 дней с даты получения такого запроса;",
-      "— публиковать или иным образом обеспечивать неограниченный доступ к настоящей Политике в отношении обработки персональных данных;",
-      "— принимать правовые, организационные и технические меры для защиты персональных данных от неправомерного или случайного доступа к ним, уничтожения, изменения, блокирования, копирования, предоставления, распространения персональных данных, а также от иных неправомерных действий в отношении персональных данных;",
-      "— прекратить передачу (распространение, предоставление, доступ) персональных данных, прекратить обработку и уничтожить персональные данные в порядке и случаях, предусмотренных Законом о персональных данных;",
-      "— исполнять иные обязанности, предусмотренные Законом о персональных данных.",
-    ],
-  },
-  {
-    title: "4. Основные права и обязанности субъектов персональных данных",
-    intro: "4.1. Субъекты персональных данных имеют право:",
-    items: [
-      "— получать информацию, касающуюся обработки его персональных данных, за исключением случаев, предусмотренных федеральными законами. Сведения предоставляются субъекту персональных данных Оператором в доступной форме, и в них не должны содержаться персональные данные, относящиеся к другим субъектам персональных данных, за исключением случаев, когда имеются законные основания для раскрытия таких персональных данных. Перечень информации и порядок ее получения установлен Законом о персональных данных;",
-      "— требовать от оператора уточнения его персональных данных, их блокирования или уничтожения в случае, если персональные данные являются неполными, устаревшими, неточными, незаконно полученными или не являются необходимыми для заявленной цели обработки, а также принимать предусмотренные законом меры по защите своих прав;",
-      "— выдвигать условие предварительного согласия при обработке персональных данных в целях продвижения на рынке товаров, работ и услуг;",
-      "— на отзыв согласия на обработку персональных данных, а также, на направление требования о прекращении обработки персональных данных;",
-      "— обжаловать в уполномоченный орган по защите прав субъектов персональных данных или в судебном порядке неправомерные действия или бездействие Оператора при обработке его персональных данных;",
-      "— на осуществление иных прав, предусмотренных законодательством РФ.",
-      "4.2. Субъекты персональных данных обязаны:",
-      "— предоставлять Оператору достоверные данные о себе;",
-      "— сообщать Оператору об уточнении (обновлении, изменении) своих персональных данных.",
-      "4.3. Лица, передавшие Оператору недостоверные сведения о себе, либо сведения о другом субъекте персональных данных без согласия последнего, несут ответственность в соответствии с законодательством РФ.",
-    ],
-  },
-  {
-    title: "5. Принципы обработки персональных данных",
-    items: [
-      "5.1. Обработка персональных данных осуществляется на законной и справедливой основе.",
-      "5.2. Обработка персональных данных ограничивается достижением конкретных, заранее определенных и законных целей. Не допускается обработка персональных данных, несовместимая с целями сбора персональных данных.",
-      "5.3. Не допускается объединение баз данных, содержащих персональные данные, обработка которых осуществляется в целях, несовместимых между собой.",
-      "5.4. Обработке подлежат только персональные данные, которые отвечают целям их обработки.",
-      "5.5. Содержание и объем обрабатываемых персональных данных соответствуют заявленным целям обработки. Не допускается избыточность обрабатываемых персональных данных по отношению к заявленным целям их обработки.",
-      "5.6. При обработке персональных данных обеспечивается точность персональных данных, их достаточность, а в необходимых случаях и актуальность по отношению к целям обработки персональных данных. Оператор принимает необходимые меры и/или обеспечивает их принятие по удалению или уточнению неполных или неточных данных.",
-      "5.7. Хранение персональных данных осуществляется в форме, позволяющей определить субъекта персональных данных, не дольше, чем этого требуют цели обработки персональных данных, если срок хранения персональных данных не установлен федеральным законом, договором, стороной которого, выгодоприобретателем или поручителем по которому является субъект персональных данных. Обрабатываемые персональные данные уничтожаются либо обезличиваются по достижении целей обработки или в случае утраты необходимости в достижении этих целей, если иное не предусмотрено федеральным законом.",
-    ],
-  },
-  {
-    title: "6. Цели обработки персональных данных",
-    table: [
-      [
-        "Цель обработки",
-        "Предоставление доступа Пользователю к сервисам, информации и/или материалам, содержащимся на веб-сайте",
-      ],
-      [
-        "Персональные данные",
-        "Фамилия, имя, отчество; электронный адрес; номера телефонов; почтовый адрес; сведения об образовании, профессии, специальности и квалификации, реквизиты документов об образовании",
-      ],
-      ["Правовые основания", "Уставные (учредительные) документы Оператора"],
-      [
-        "Виды обработки персональных данных",
-        "Сбор, запись, систематизация, накопление, хранение, уничтожение и обезличивание персональных данных; отправка информационных писем на адрес электронной почты",
-      ],
-    ],
-  },
-  {
-    title: "7. Условия обработки персональных данных",
-    items: [
-      "7.1. Обработка персональных данных осуществляется с согласия субъекта персональных данных на обработку его персональных данных.",
-      "7.2. Обработка персональных данных необходима для достижения целей, предусмотренных международным договором Российской Федерации или законом, для осуществления возложенных законодательством Российской Федерации на оператора функций, полномочий и обязанностей.",
-      "7.3. Обработка персональных данных необходима для осуществления правосудия, исполнения судебного акта, акта другого органа или должностного лица, подлежащих исполнению в соответствии с законодательством Российской Федерации об исполнительном производстве.",
-      "7.4. Обработка персональных данных необходима для исполнения договора, стороной которого либо выгодоприобретателем или поручителем по которому является субъект персональных данных, а также для заключения договора по инициативе субъекта персональных данных или договора, по которому субъект персональных данных будет являться выгодоприобретателем или поручителем.",
-      "7.5. Обработка персональных данных необходима для осуществления прав и законных интересов оператора или третьих лиц либо для достижения общественно значимых целей при условии, что при этом не нарушаются права и свободы субъекта персональных данных.",
-      "7.6. Осуществляется обработка персональных данных, доступ неограниченного круга лиц к которым предоставлен субъектом персональных данных либо по его просьбе (далее — общедоступные персональные данные).",
-      "7.7. Осуществляется обработка персональных данных, подлежащих опубликованию или обязательному раскрытию в соответствии с федеральным законом.",
-    ],
-  },
-  {
-    title: "8. Порядок сбора, хранения, передачи и других видов обработки персональных данных",
-    intro:
-      "Безопасность персональных данных, которые обрабатываются Оператором, обеспечивается путем реализации правовых, организационных и технических мер, необходимых для выполнения в полном объеме требований действующего законодательства в области защиты персональных данных.",
-    items: [
-      "8.1. Оператор обеспечивает сохранность персональных данных и принимает все возможные меры, исключающие доступ к персональным данным неуполномоченных лиц.",
-      "8.2. Персональные данные Пользователя никогда, ни при каких условиях не будут переданы третьим лицам, за исключением случаев, связанных с исполнением действующего законодательства либо в случае, если субъектом персональных данных дано согласие Оператору на передачу данных третьему лицу для исполнения обязательств по гражданско-правовому договору.",
-      "8.3. В случае выявления неточностей в персональных данных, Пользователь может актуализировать их самостоятельно, путем направления Оператору уведомление на адрес электронной почты Оператора info@scientia.ru с пометкой «Актуализация персональных данных».",
-      "8.4. Срок обработки персональных данных определяется достижением целей, для которых были собраны персональные данные, если иной срок не предусмотрен договором или действующим законодательством.",
-      "Пользователь может в любой момент отозвать свое согласие на обработку персональных данных, направив Оператору уведомление посредством электронной почты на электронный адрес Оператора info@scientia.ru с пометкой «Отзыв согласия на обработку персональных данных».",
-      "8.5. Вся информация, которая собирается сторонними сервисами, в том числе платежными системами, средствами связи и другими поставщиками услуг, хранится и обрабатывается указанными лицами (Операторами) в соответствии с их Пользовательским соглашением и Политикой конфиденциальности. Субъект персональных данных и/или с указанными документами. Оператор не несет ответственность за действия третьих лиц, в том числе указанных в настоящем пункте поставщиков услуг.",
-      "8.6. Установленные субъектом персональных данных запреты на передачу (кроме предоставления доступа), а также на обработку или условия обработки (кроме получения доступа) персональных данных, разрешенных для распространения, не действуют в случаях обработки персональных данных в государственных, общественных и иных публичных интересах, определенных законодательством РФ.",
-      "8.7. Оператор при обработке персональных данных обеспечивает конфиденциальность персональных данных.",
-      "8.8. Оператор осуществляет хранение персональных данных в форме, позволяющей определить субъекта персональных данных, не дольше, чем этого требуют цели обработки персональных данных, если срок хранения персональных данных не установлен федеральным законом, договором, стороной которого, выгодоприобретателем или поручителем по которому является субъект персональных данных.",
-      "8.9. Условием прекращения обработки персональных данных может являться достижение целей обработки персональных данных, истечение срока действия согласия субъекта персональных данных, отзыв согласия субъектом персональных данных или требование о прекращении обработки персональных данных, а также выявление неправомерной обработки персональных данных.",
-    ],
-  },
-  {
-    title: "9. Перечень действий, производимых Оператором с полученными персональными данными",
-    items: [
-      "9.1. Оператор осуществляет сбор, запись, систематизацию, накопление, хранение, уточнение (обновление, изменение), извлечение, использование, передачу (распространение, предоставление, доступ), обезличивание, блокирование, удаление и уничтожение персональных данных.",
-      "9.2. Оператор осуществляет автоматизированную обработку персональных данных с получением и/или передачей полученной информации по информационно-телекоммуникационным сетям или без таковой.",
-    ],
-  },
-  {
-    title: "10. Трансграничная передача персональных данных",
-    items: [
-      "10.1. Оператор до начала осуществления деятельности по трансграничной передаче персональных данных обязан уведомить уполномоченный орган по защите прав субъектов персональных данных о своем намерении осуществлять трансграничную передачу персональных данных (такое уведомление направляется отдельно от уведомления о намерении осуществлять обработку персональных данных).",
-      "10.2. Оператор до подачи вышеуказанного уведомления, обязан получить от органов власти иностранного государства, иностранных физических лиц, иностранных юридических лиц, которым планируется трансграничная передача персональных данных, соответствующие сведения.",
-    ],
-  },
-  {
-    title: "11. Конфиденциальность персональных данных",
-    intro:
-      "Оператор и иные лица, получившие доступ к персональным данным, обязаны не раскрывать третьим лицам и не распространять персональные данные без согласия субъекта персональных данных, если иное не предусмотрено федеральным законом.",
-  },
-  {
-    title: "12. Заключительные положения",
-    items: [
-      "12.1. Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты info@scientia.ru.",
-      "12.2. В данном документе будут отражены любые изменения политики обработки персональных данных Оператором. Политика действует бессрочно до замены ее новой версией.",
-      "12.3. Актуальная версия Политики в свободном доступе расположена в сети Интернет по адресу https://scientia.ru/personal_data.",
-    ],
-  },
-];
+export const policySections: Localized<PolicySection[]> = {
+  en: [
+    {
+      title: "1. General provisions",
+      intro:
+        "This personal data processing policy is drawn up in accordance with the requirements of Federal Law No. 152-FZ of 27.07.2006 \"On Personal Data\" (hereinafter — the Personal Data Law) and defines the procedure for processing personal data and the security measures taken by Scientia LLC (hereinafter — the Operator).",
+      items: [
+        "1.1. The Operator sets as its most important goal and condition of its activities the observance of human and civil rights and freedoms when processing personal data, including the protection of the rights to privacy, personal and family secrets.",
+        "1.2. This Operator policy on personal data processing (hereinafter — the Policy) applies to all information that the Operator may obtain about visitors to the website https://scientia.ru.",
+      ],
+    },
+    {
+      title: "2. Basic concepts used in the Policy",
+      items: [
+        "2.1. Automated processing of personal data — processing of personal data using computer hardware.",
+        "2.2. Blocking of personal data — temporary suspension of personal data processing (except in cases where processing is necessary to clarify personal data).",
+        "2.3. Website — a collection of graphic and informational materials, as well as computer programs and databases, ensuring their availability on the internet at the network address https://scientia.ru.",
+        "2.4. Personal data information system — a set of personal data contained in databases and the information technologies and technical means that ensure their processing.",
+        "2.5. Depersonalization of personal data — actions as a result of which it is impossible to determine, without the use of additional information, the attribution of personal data to a specific User or other personal data subject.",
+        "2.6. Processing of personal data — any action (operation) or set of actions (operations) performed with the use of automation tools or without such tools on personal data, including collection, recording, systematization, accumulation, storage, clarification (updating, modification), retrieval, use, transfer (distribution, provision, access), depersonalization, blocking, deletion, destruction of personal data.",
+        "2.7. Operator — a state body, municipal body, legal entity or individual, independently or jointly with other persons, organizing and/or carrying out the processing of personal data, as well as determining the purposes of processing personal data, the composition of personal data to be processed, and the actions (operations) performed with personal data.",
+        "2.8. Personal data — any information relating directly or indirectly to a specific or identifiable User of the website https://scientia.ru.",
+        "2.9. Personal data permitted for distribution by the personal data subject — personal data whose access by an unlimited circle of persons is granted by the personal data subject by giving consent to the processing of personal data permitted for distribution in the manner provided for by the Personal Data Law (hereinafter — personal data permitted for distribution).",
+        "2.10. User — any visitor to the website https://scientia.ru.",
+        "2.11. Provision of personal data — actions aimed at disclosing personal data to a specific person or a specific circle of persons.",
+        "2.12. Distribution of personal data — any actions aimed at disclosing personal data to an indefinite circle of persons (transfer of personal data) or at familiarizing an unlimited circle of persons with personal data, including publication of personal data in the media, placement in information and telecommunication networks, or providing access to personal data in any other way.",
+        "2.13. Cross-border transfer of personal data — transfer of personal data to the territory of a foreign state to an authority of a foreign state, a foreign individual or a foreign legal entity.",
+        "2.14. Destruction of personal data — any actions as a result of which personal data are irretrievably destroyed with the impossibility of further restoration of the content of personal data in the personal data information system and/or the material carriers of personal data are destroyed.",
+      ],
+    },
+    {
+      title: "3. Basic rights and obligations of the Operator",
+      intro: "3.1. The Operator has the right to:",
+      items: [
+        "— receive reliable information and/or documents containing personal data from the personal data subject;",
+        "— in case of withdrawal of consent to personal data processing by the personal data subject, as well as in case of a request to cease personal data processing, the Operator has the right to continue processing personal data without the consent of the personal data subject if there are grounds specified in the Personal Data Law;",
+        "— independently determine the composition and list of measures necessary and sufficient to ensure the fulfillment of obligations provided for by the Personal Data Law and the regulatory legal acts adopted in accordance with it, unless otherwise provided for by the Personal Data Law or other federal laws.",
+        "3.2. The Operator is obliged to:",
+        "— provide the personal data subject, at his request, with information relating to the processing of his personal data;",
+        "— organize the processing of personal data in the manner established by the current legislation of the Russian Federation;",
+        "— respond to appeals and requests from personal data subjects and their legal representatives in accordance with the requirements of the Personal Data Law;",
+        "— provide the authorized body for the protection of personal data subjects' rights, at the request of that body, with the necessary information within 10 days from the date of receipt of such request;",
+        "— publish or otherwise ensure unrestricted access to this Policy on personal data processing;",
+        "— take legal, organizational and technical measures to protect personal data from unlawful or accidental access, destruction, modification, blocking, copying, provision, distribution of personal data, as well as from other unlawful actions against personal data;",
+        "— cease the transfer (distribution, provision, access) of personal data, cease processing and destroy personal data in the manner and cases provided for by the Personal Data Law;",
+        "— fulfill other obligations provided for by the Personal Data Law.",
+      ],
+    },
+    {
+      title: "4. Basic rights and obligations of personal data subjects",
+      intro: "4.1. Personal data subjects have the right to:",
+      items: [
+        "— receive information relating to the processing of their personal data, except in cases provided for by federal laws. Information is provided by the Operator to the personal data subject in an accessible form, and it must not contain personal data relating to other personal data subjects, except in cases where there are legal grounds for disclosing such personal data. The list of information and the procedure for obtaining it is established by the Personal Data Law;",
+        "— demand that the Operator clarify their personal data, block or destroy it if the personal data is incomplete, outdated, inaccurate, unlawfully obtained, or is not necessary for the stated processing purpose, and also take measures provided for by law to protect their rights;",
+        "— put forward a condition of prior consent when processing personal data for the purpose of promoting goods, works and services on the market;",
+        "— withdraw consent to personal data processing, and also send a demand to cease personal data processing;",
+        "— appeal to the authorized body for the protection of personal data subjects' rights or to court the unlawful actions or inaction of the Operator in processing their personal data;",
+        "— exercise other rights provided for by the legislation of the Russian Federation.",
+        "4.2. Personal data subjects are obliged to:",
+        "— provide the Operator with reliable information about themselves;",
+        "— inform the Operator about updates (renewal, changes) of their personal data.",
+        "4.3. Persons who have provided the Operator with unreliable information about themselves, or information about another personal data subject without the latter's consent, are liable in accordance with the legislation of the Russian Federation.",
+      ],
+    },
+    {
+      title: "5. Principles of personal data processing",
+      items: [
+        "5.1. Personal data processing is carried out on a legal and fair basis.",
+        "5.2. Personal data processing is limited to the achievement of specific, pre-defined and lawful purposes. Processing of personal data incompatible with the purposes of collection of personal data is not allowed.",
+        "5.3. Merging of databases containing personal data processed for purposes incompatible with each other is not allowed.",
+        "5.4. Only personal data that meets the purposes of its processing is subject to processing.",
+        "5.5. The content and scope of processed personal data correspond to the stated processing purposes. Excessiveness of processed personal data in relation to the stated purposes of its processing is not allowed.",
+        "5.6. When processing personal data, the accuracy of personal data, its sufficiency, and, where necessary, its relevance to the purposes of processing are ensured. The Operator takes the necessary measures and/or ensures their adoption to delete or clarify incomplete or inaccurate data.",
+        "5.7. Personal data is stored in a form that allows identifying the personal data subject, no longer than required by the purposes of personal data processing, if the storage period of personal data is not established by federal law, a contract to which the personal data subject is a party, beneficiary, or guarantor. Processed personal data is destroyed or depersonalized upon achievement of the processing purposes or in case of loss of necessity to achieve these purposes, unless otherwise provided by federal law.",
+      ],
+    },
+    {
+      title: "6. Purposes of personal data processing",
+      table: [
+        [
+          "Purpose of processing",
+          "Providing the User with access to services, information and/or materials contained on the website",
+        ],
+        [
+          "Personal data",
+          "Last name, first name, patronymic; email address; phone numbers; postal address; information about education, profession, specialty and qualifications, details of education documents",
+        ],
+        ["Legal grounds", "Constituent (incorporation) documents of the Operator"],
+        [
+          "Types of personal data processing",
+          "Collection, recording, systematization, accumulation, storage, destruction and depersonalization of personal data; sending informational letters to the email address",
+        ],
+      ],
+    },
+    {
+      title: "7. Conditions of personal data processing",
+      items: [
+        "7.1. Personal data processing is carried out with the consent of the personal data subject to the processing of his personal data.",
+        "7.2. Personal data processing is necessary to achieve the purposes provided for by an international treaty of the Russian Federation or a law, for the exercise of functions, powers and obligations imposed on the operator by the legislation of the Russian Federation.",
+        "7.3. Personal data processing is necessary for the administration of justice, the execution of a judicial act, an act of another body or official, subject to execution in accordance with the legislation of the Russian Federation on enforcement proceedings.",
+        "7.4. Personal data processing is necessary for the execution of a contract to which the personal data subject is a party, beneficiary, or guarantor, as well as for concluding a contract at the initiative of the personal data subject or a contract under which the personal data subject will be a beneficiary or guarantor.",
+        "7.5. Personal data processing is necessary to exercise the rights and legitimate interests of the operator or third parties, or to achieve socially significant goals, provided that the rights and freedoms of the personal data subject are not violated.",
+        "7.6. Processing of personal data whose access by an unlimited circle of persons is granted by the personal data subject or at his request (hereinafter — publicly available personal data) is carried out.",
+        "7.7. Processing of personal data subject to publication or mandatory disclosure in accordance with federal law is carried out.",
+      ],
+    },
+    {
+      title: "8. Procedure for collecting, storing, transferring and other types of personal data processing",
+      intro:
+        "The security of personal data processed by the Operator is ensured by implementing legal, organizational and technical measures necessary to fully comply with the requirements of current legislation in the field of personal data protection.",
+      items: [
+        "8.1. The Operator ensures the safety of personal data and takes all possible measures to exclude access to personal data by unauthorized persons.",
+        "8.2. The User's personal data will never, under any circumstances, be transferred to third parties, except in cases related to the execution of current legislation, or in the case where the personal data subject has given consent to the Operator to transfer data to a third party to fulfill obligations under a civil law contract.",
+        "8.3. If inaccuracies are identified in personal data, the User can update them independently by sending a notification to the Operator's email address info@scientia.ru with the note \"Personal data update\".",
+        "8.4. The period of personal data processing is determined by the achievement of the purposes for which the personal data was collected, unless a different period is provided for by the contract or current legislation.",
+        "The User can withdraw his consent to personal data processing at any time by sending a notification to the Operator via email to the Operator's email address info@scientia.ru with the note \"Withdrawal of consent to personal data processing\".",
+        "8.5. All information collected by third-party services, including payment systems, communication means and other service providers, is stored and processed by those persons (Operators) in accordance with their User Agreement and Privacy Policy. The Operator is not responsible for the actions of third parties, including the service providers specified in this paragraph.",
+        "8.6. Prohibitions established by the personal data subject on transfer (except for providing access), as well as on processing or processing conditions (except for receiving access) of personal data permitted for distribution, do not apply in cases of processing personal data in state, public and other public interests defined by the legislation of the Russian Federation.",
+        "8.7. The Operator ensures the confidentiality of personal data when processing it.",
+        "8.8. The Operator stores personal data in a form that allows identifying the personal data subject, no longer than required by the purposes of personal data processing, if the storage period of personal data is not established by federal law or a contract to which the personal data subject is a party, beneficiary, or guarantor.",
+        "8.9. Conditions for termination of personal data processing may be the achievement of personal data processing purposes, expiration of the consent of the personal data subject, withdrawal of consent by the personal data subject or a demand to cease personal data processing, as well as identification of unlawful personal data processing.",
+      ],
+    },
+    {
+      title: "9. List of actions performed by the Operator with the received personal data",
+      items: [
+        "9.1. The Operator collects, records, systematizes, accumulates, stores, clarifies (updates, modifies), retrieves, uses, transfers (distributes, provides, accesses), depersonalizes, blocks, deletes and destroys personal data.",
+        "9.2. The Operator carries out automated processing of personal data with receipt and/or transfer of the received information via information and telecommunication networks or without them.",
+      ],
+    },
+    {
+      title: "10. Cross-border transfer of personal data",
+      items: [
+        "10.1. Before starting cross-border transfer of personal data, the Operator is obliged to notify the authorized body for the protection of personal data subjects' rights of its intention to carry out cross-border transfer of personal data (such notification is sent separately from the notification of the intention to process personal data).",
+        "10.2. Before submitting the above notification, the Operator is obliged to obtain relevant information from the authorities of the foreign state, foreign individuals, and foreign legal entities to whom the cross-border transfer of personal data is planned.",
+      ],
+    },
+    {
+      title: "11. Confidentiality of personal data",
+      intro:
+        "The Operator and other persons who have gained access to personal data are obliged not to disclose to third parties and not to distribute personal data without the consent of the personal data subject, unless otherwise provided by federal law.",
+    },
+    {
+      title: "12. Final provisions",
+      items: [
+        "12.1. The User can receive any clarification on issues of interest regarding the processing of his personal data by contacting the Operator via email info@scientia.ru.",
+        "12.2. Any changes to the Operator's personal data processing policy will be reflected in this document. The Policy is valid indefinitely until replaced by a new version.",
+        "12.3. The current version of the Policy is freely available on the Internet at https://scientia.ru/personal_data. In case of any discrepancies, the Russian version of the Policy prevails.",
+      ],
+    },
+  ],
+  ru: [
+    {
+      title: "1. Общие положения",
+      intro:
+        "Настоящая политика обработки персональных данных составлена в соответствии с требованиями Федерального закона от 27.07.2006. № 152-ФЗ «О персональных данных» (далее — Закон о персональных данных) и определяет порядок обработки персональных данных и меры по обеспечению безопасности персональных данных, предпринимаемые ООО \"Скиентия\" (далее — Оператор).",
+      items: [
+        "1.1. Оператор ставит своей важнейшей целью и условием осуществления своей деятельности соблюдение прав и свобод человека и гражданина при обработке его персональных данных, в том числе защиты прав на неприкосновенность частной жизни, личную и семейную тайну.",
+        "1.2. Настоящая политика Оператора в отношении обработки персональных данных (далее — Политика) применяется ко всей информации, которую Оператор может получить о посетителях веб-сайта https://scientia.ru.",
+      ],
+    },
+    {
+      title: "2. Основные понятия, используемые в Политике",
+      items: [
+        "2.1. Автоматизированная обработка персональных данных — обработка персональных данных с помощью средств вычислительной техники.",
+        "2.2. Блокирование персональных данных — временное прекращение обработки персональных данных (за исключением случаев, если обработка необходима для уточнения персональных данных).",
+        "2.3. Веб-сайт — совокупность графических и информационных материалов, а также программ для ЭВМ и баз данных, обеспечивающих их доступность в сети интернет по сетевому адресу https://scientia.ru.",
+        "2.4. Информационная система персональных данных — совокупность содержащихся в базах данных персональных данных и обеспечивающих их обработку информационных технологий и технических средств.",
+        "2.5. Обезличивание персональных данных — действия, в результате которых невозможно определить без использования дополнительной информации принадлежность персональных данных конкретному Пользователю или иному субъекту персональных данных.",
+        "2.6. Обработка персональных данных — любое действие (операция) или совокупность действий (операций), совершаемых с использованием средств автоматизации или без использования таких средств с персональными данными, включая сбор, запись, систематизацию, накопление, хранение, уточнение (обновление, изменение), извлечение, использование, передачу (распространение, предоставление, доступ), обезличивание, блокирование, удаление, уничтожение персональных данных.",
+        "2.7. Оператор — государственный орган, муниципальный орган, юридическое или физическое лицо, самостоятельно или совместно с другими лицами организующие и/или осуществляющие обработку персональных данных, а также определяющие цели обработки персональных данных, состав персональных данных, подлежащих обработке, действия (операции), совершаемые с персональными данными.",
+        "2.8. Персональные данные — любая информация, относящаяся прямо или косвенно к определенному или определяемому Пользователю веб-сайта https://scientia.ru.",
+        "2.9. Персональные данные, разрешенные субъектом персональных данных для распространения, — персональные данные, доступ неограниченного круга лиц к которым предоставлен субъектом персональных данных путем дачи согласия на обработку персональных данных, разрешенных субъектом персональных данных для распространения в порядке, предусмотренном Законом о персональных данных (далее — персональные данные, разрешенные для распространения).",
+        "2.10. Пользователь — любой посетитель веб-сайта https://scientia.ru.",
+        "2.11. Предоставление персональных данных — действия, направленные на раскрытие персональных данных определенному лицу или определенному кругу лиц.",
+        "2.12. Распространение персональных данных — любые действия, направленные на раскрытие персональных данных неопределенному кругу лиц (передача персональных данных) или на ознакомление с персональными данными неограниченного круга лиц, в том числе обнародование персональных данных в средствах массовой информации, размещение в информационно-телекоммуникационных сетях или предоставление доступа к персональным данным каким-либо иным способом.",
+        "2.13. Трансграничная передача персональных данных — передача персональных данных на территорию иностранного государства органу власти иностранного государства, иностранному физическому или иностранному юридическому лицу.",
+        "2.14. Уничтожение персональных данных — любые действия, в результате которых персональные данные уничтожаются безвозвратно с невозможностью дальнейшего восстановления содержания персональных данных в информационной системе персональных данных и/или уничтожаются материальные носители персональных данных.",
+      ],
+    },
+    {
+      title: "3. Основные права и обязанности Оператора",
+      intro: "3.1. Оператор имеет право:",
+      items: [
+        "— получать от субъекта персональных данных достоверные информацию и/или документы, содержащие персональные данные;",
+        "— в случае отзыва субъектом персональных данных согласия на обработку персональных данных, а также, направления обращения с требованием о прекращении обработки персональных данных, Оператор вправе продолжить обработку персональных данных без согласия субъекта персональных данных при наличии оснований, указанных в Законе о персональных данных;",
+        "— самостоятельно определять состав и перечень мер, необходимых и достаточных для обеспечения выполнения обязанностей, предусмотренных Законом о персональных данных и принятыми в соответствии с ним нормативными правовыми актами, если иное не предусмотрено Законом о персональных данных или другими федеральными законами.",
+        "3.2. Оператор обязан:",
+        "— предоставлять субъекту персональных данных по его просьбе информацию, касающуюся обработки его персональных данных;",
+        "— организовывать обработку персональных данных в порядке, установленном действующим законодательством РФ;",
+        "— отвечать на обращения и запросы субъектов персональных данных и их законных представителей в соответствии с требованиями Закона о персональных данных;",
+        "— сообщать в уполномоченный орган по защите прав субъектов персональных данных по запросу этого органа необходимую информацию в течение 10 дней с даты получения такого запроса;",
+        "— публиковать или иным образом обеспечивать неограниченный доступ к настоящей Политике в отношении обработки персональных данных;",
+        "— принимать правовые, организационные и технические меры для защиты персональных данных от неправомерного или случайного доступа к ним, уничтожения, изменения, блокирования, копирования, предоставления, распространения персональных данных, а также от иных неправомерных действий в отношении персональных данных;",
+        "— прекратить передачу (распространение, предоставление, доступ) персональных данных, прекратить обработку и уничтожить персональные данные в порядке и случаях, предусмотренных Законом о персональных данных;",
+        "— исполнять иные обязанности, предусмотренные Законом о персональных данных.",
+      ],
+    },
+    {
+      title: "4. Основные права и обязанности субъектов персональных данных",
+      intro: "4.1. Субъекты персональных данных имеют право:",
+      items: [
+        "— получать информацию, касающуюся обработки его персональных данных, за исключением случаев, предусмотренных федеральными законами. Сведения предоставляются субъекту персональных данных Оператором в доступной форме, и в них не должны содержаться персональные данные, относящиеся к другим субъектам персональных данных, за исключением случаев, когда имеются законные основания для раскрытия таких персональных данных. Перечень информации и порядок ее получения установлен Законом о персональных данных;",
+        "— требовать от оператора уточнения его персональных данных, их блокирования или уничтожения в случае, если персональные данные являются неполными, устаревшими, неточными, незаконно полученными или не являются необходимыми для заявленной цели обработки, а также принимать предусмотренные законом меры по защите своих прав;",
+        "— выдвигать условие предварительного согласия при обработке персональных данных в целях продвижения на рынке товаров, работ и услуг;",
+        "— на отзыв согласия на обработку персональных данных, а также, на направление требования о прекращении обработки персональных данных;",
+        "— обжаловать в уполномоченный орган по защите прав субъектов персональных данных или в судебном порядке неправомерные действия или бездействие Оператора при обработке его персональных данных;",
+        "— на осуществление иных прав, предусмотренных законодательством РФ.",
+        "4.2. Субъекты персональных данных обязаны:",
+        "— предоставлять Оператору достоверные данные о себе;",
+        "— сообщать Оператору об уточнении (обновлении, изменении) своих персональных данных.",
+        "4.3. Лица, передавшие Оператору недостоверные сведения о себе, либо сведения о другом субъекте персональных данных без согласия последнего, несут ответственность в соответствии с законодательством РФ.",
+      ],
+    },
+    {
+      title: "5. Принципы обработки персональных данных",
+      items: [
+        "5.1. Обработка персональных данных осуществляется на законной и справедливой основе.",
+        "5.2. Обработка персональных данных ограничивается достижением конкретных, заранее определенных и законных целей. Не допускается обработка персональных данных, несовместимая с целями сбора персональных данных.",
+        "5.3. Не допускается объединение баз данных, содержащих персональные данные, обработка которых осуществляется в целях, несовместимых между собой.",
+        "5.4. Обработке подлежат только персональные данные, которые отвечают целям их обработки.",
+        "5.5. Содержание и объем обрабатываемых персональных данных соответствуют заявленным целям обработки. Не допускается избыточность обрабатываемых персональных данных по отношению к заявленным целям их обработки.",
+        "5.6. При обработке персональных данных обеспечивается точность персональных данных, их достаточность, а в необходимых случаях и актуальность по отношению к целям обработки персональных данных. Оператор принимает необходимые меры и/или обеспечивает их принятие по удалению или уточнению неполных или неточных данных.",
+        "5.7. Хранение персональных данных осуществляется в форме, позволяющей определить субъекта персональных данных, не дольше, чем этого требуют цели обработки персональных данных, если срок хранения персональных данных не установлен федеральным законом, договором, стороной которого, выгодоприобретателем или поручителем по которому является субъект персональных данных. Обрабатываемые персональные данные уничтожаются либо обезличиваются по достижении целей обработки или в случае утраты необходимости в достижении этих целей, если иное не предусмотрено федеральным законом.",
+      ],
+    },
+    {
+      title: "6. Цели обработки персональных данных",
+      table: [
+        [
+          "Цель обработки",
+          "Предоставление доступа Пользователю к сервисам, информации и/или материалам, содержащимся на веб-сайте",
+        ],
+        [
+          "Персональные данные",
+          "Фамилия, имя, отчество; электронный адрес; номера телефонов; почтовый адрес; сведения об образовании, профессии, специальности и квалификации, реквизиты документов об образовании",
+        ],
+        ["Правовые основания", "Уставные (учредительные) документы Оператора"],
+        [
+          "Виды обработки персональных данных",
+          "Сбор, запись, систематизация, накопление, хранение, уничтожение и обезличивание персональных данных; отправка информационных писем на адрес электронной почты",
+        ],
+      ],
+    },
+    {
+      title: "7. Условия обработки персональных данных",
+      items: [
+        "7.1. Обработка персональных данных осуществляется с согласия субъекта персональных данных на обработку его персональных данных.",
+        "7.2. Обработка персональных данных необходима для достижения целей, предусмотренных международным договором Российской Федерации или законом, для осуществления возложенных законодательством Российской Федерации на оператора функций, полномочий и обязанностей.",
+        "7.3. Обработка персональных данных необходима для осуществления правосудия, исполнения судебного акта, акта другого органа или должностного лица, подлежащих исполнению в соответствии с законодательством Российской Федерации об исполнительном производстве.",
+        "7.4. Обработка персональных данных необходима для исполнения договора, стороной которого либо выгодоприобретателем или поручителем по которому является субъект персональных данных, а также для заключения договора по инициативе субъекта персональных данных или договора, по которому субъект персональных данных будет являться выгодоприобретателем или поручителем.",
+        "7.5. Обработка персональных данных необходима для осуществления прав и законных интересов оператора или третьих лиц либо для достижения общественно значимых целей при условии, что при этом не нарушаются права и свободы субъекта персональных данных.",
+        "7.6. Осуществляется обработка персональных данных, доступ неограниченного круга лиц к которым предоставлен субъектом персональных данных либо по его просьбе (далее — общедоступные персональные данные).",
+        "7.7. Осуществляется обработка персональных данных, подлежащих опубликованию или обязательному раскрытию в соответствии с федеральным законом.",
+      ],
+    },
+    {
+      title: "8. Порядок сбора, хранения, передачи и других видов обработки персональных данных",
+      intro:
+        "Безопасность персональных данных, которые обрабатываются Оператором, обеспечивается путем реализации правовых, организационных и технических мер, необходимых для выполнения в полном объеме требований действующего законодательства в области защиты персональных данных.",
+      items: [
+        "8.1. Оператор обеспечивает сохранность персональных данных и принимает все возможные меры, исключающие доступ к персональным данным неуполномоченных лиц.",
+        "8.2. Персональные данные Пользователя никогда, ни при каких условиях не будут переданы третьим лицам, за исключением случаев, связанных с исполнением действующего законодательства либо в случае, если субъектом персональных данных дано согласие Оператору на передачу данных третьему лицу для исполнения обязательств по гражданско-правовому договору.",
+        "8.3. В случае выявления неточностей в персональных данных, Пользователь может актуализировать их самостоятельно, путем направления Оператору уведомление на адрес электронной почты Оператора info@scientia.ru с пометкой «Актуализация персональных данных».",
+        "8.4. Срок обработки персональных данных определяется достижением целей, для которых были собраны персональные данные, если иной срок не предусмотрен договором или действующим законодательством.",
+        "Пользователь может в любой момент отозвать свое согласие на обработку персональных данных, направив Оператору уведомление посредством электронной почты на электронный адрес Оператора info@scientia.ru с пометкой «Отзыв согласия на обработку персональных данных».",
+        "8.5. Вся информация, которая собирается сторонними сервисами, в том числе платежными системами, средствами связи и другими поставщиками услуг, хранится и обрабатывается указанными лицами (Операторами) в соответствии с их Пользовательским соглашением и Политикой конфиденциальности. Субъект персональных данных и/или с указанными документами. Оператор не несет ответственность за действия третьих лиц, в том числе указанных в настоящем пункте поставщиков услуг.",
+        "8.6. Установленные субъектом персональных данных запреты на передачу (кроме предоставления доступа), а также на обработку или условия обработки (кроме получения доступа) персональных данных, разрешенных для распространения, не действуют в случаях обработки персональных данных в государственных, общественных и иных публичных интересах, определенных законодательством РФ.",
+        "8.7. Оператор при обработке персональных данных обеспечивает конфиденциальность персональных данных.",
+        "8.8. Оператор осуществляет хранение персональных данных в форме, позволяющей определить субъекта персональных данных, не дольше, чем этого требуют цели обработки персональных данных, если срок хранения персональных данных не установлен федеральным законом, договором, стороной которого, выгодоприобретателем или поручителем по которому является субъект персональных данных.",
+        "8.9. Условием прекращения обработки персональных данных может являться достижение целей обработки персональных данных, истечение срока действия согласия субъекта персональных данных, отзыв согласия субъектом персональных данных или требование о прекращении обработки персональных данных, а также выявление неправомерной обработки персональных данных.",
+      ],
+    },
+    {
+      title: "9. Перечень действий, производимых Оператором с полученными персональными данными",
+      items: [
+        "9.1. Оператор осуществляет сбор, запись, систематизацию, накопление, хранение, уточнение (обновление, изменение), извлечение, использование, передачу (распространение, предоставление, доступ), обезличивание, блокирование, удаление и уничтожение персональных данных.",
+        "9.2. Оператор осуществляет автоматизированную обработку персональных данных с получением и/или передачей полученной информации по информационно-телекоммуникационным сетям или без таковой.",
+      ],
+    },
+    {
+      title: "10. Трансграничная передача персональных данных",
+      items: [
+        "10.1. Оператор до начала осуществления деятельности по трансграничной передаче персональных данных обязан уведомить уполномоченный орган по защите прав субъектов персональных данных о своем намерении осуществлять трансграничную передачу персональных данных (такое уведомление направляется отдельно от уведомления о намерении осуществлять обработку персональных данных).",
+        "10.2. Оператор до подачи вышеуказанного уведомления, обязан получить от органов власти иностранного государства, иностранных физических лиц, иностранных юридических лиц, которым планируется трансграничная передача персональных данных, соответствующие сведения.",
+      ],
+    },
+    {
+      title: "11. Конфиденциальность персональных данных",
+      intro:
+        "Оператор и иные лица, получившие доступ к персональным данным, обязаны не раскрывать третьим лицам и не распространять персональные данные без согласия субъекта персональных данных, если иное не предусмотрено федеральным законом.",
+    },
+    {
+      title: "12. Заключительные положения",
+      items: [
+        "12.1. Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты info@scientia.ru.",
+        "12.2. В данном документе будут отражены любые изменения политики обработки персональных данных Оператором. Политика действует бессрочно до замены ее новой версией.",
+        "12.3. Актуальная версия Политики в свободном доступе расположена в сети Интернет по адресу https://scientia.ru/personal_data.",
+      ],
+    },
+  ],
+};

+ 117 - 57
src/data/products.ts

@@ -1,3 +1,5 @@
+import type { Localized } from "../i18n";
+
 export type Product = {
   id: string;
   name: string;
@@ -8,60 +10,118 @@ export type Product = {
   external?: string;
 };
 
-export const products: Product[] = [
-  {
-    id: "prorock",
-    name: "Prorock 2.0",
-    tagline: "Численное моделирование в геомеханике",
-    description:
-      "Программа для решения задач геомеханики с возможностью моделирования разрушений и динамических процессов",
-    href: "/prorock",
-    image: "/images/21.jpg",
-  },
-  {
-    id: "magicore",
-    name: "Magicore",
-    tagline: "ИИ-документация керна",
-    description:
-      "Сервис для автоматической генерации геомеханической документации керна по фотографии",
-    href: "/magicore",
-    image: "/images/image.png",
-    external: "https://magicore.scientia.ru",
-  },
-  {
-    id: "digger",
-    name: "Digger Slope",
-    tagline: "Оптимизация бортов карьера",
-    description:
-      "Программа для оптимизации бортов карьера с применением 3К-моделирования",
-    href: "/digger",
-    image: "/images/20200629_203443.jpg",
-  },
-  {
-    id: "nur",
-    name: "Экстензометр NUR",
-    tagline: "Автоматизированный мониторинг смещений",
-    description:
-      "Прибор для автоматизированного мониторинга смещений на лазерном дальномере с онлайн-передачей данных",
-    href: "/nur",
-    image: "/images/PXL_20240408_0840372.jpg",
-  },
-  {
-    id: "joint_explorer",
-    name: "Joint Explorer",
-    tagline: "Электронный горный компас",
-    description:
-      "Электронный горный компас для определения азимутов и углов падения структурно-геологических элементов",
-    href: "/joint_explorer",
-    image: "/images/photo_2022-08-25_21-.jpg",
-  },
-  {
-    id: "scientiajoints",
-    name: "ScientiaJoints",
-    tagline: "Плагин для Blender",
-    description:
-      "Плагин для свободно распространяемого ПО Blender, предназначенный для цифрового картирования трещин на трёхмерных моделях",
-    href: "/scientiajoints",
-    image: "/images/1.jpg",
-  },
-];
+export const products: Localized<Product[]> = {
+  en: [
+    {
+      id: "prorock",
+      name: "Prorock 2.0",
+      tagline: "Numerical modeling in geomechanics",
+      description:
+        "Software for solving geomechanics problems, with simulation of failure and dynamic processes",
+      href: "/prorock",
+      image: "/images/21.jpg",
+    },
+    {
+      id: "magicore",
+      name: "Magicore",
+      tagline: "AI core documentation",
+      description:
+        "A service that automatically generates geomechanical core documentation from photographs",
+      href: "/magicore",
+      image: "/images/image.png",
+      external: "https://magicore.scientia.ru",
+    },
+    {
+      id: "digger",
+      name: "Digger Slope",
+      tagline: "Open-pit slope optimization",
+      description: "Software for open-pit slope optimization with 3D modeling",
+      href: "/digger",
+      image: "/images/20200629_203443.jpg",
+    },
+    {
+      id: "nur",
+      name: "NUR Extensometer",
+      tagline: "Automated displacement monitoring",
+      description:
+        "An instrument for automated displacement monitoring based on a laser rangefinder, with online data transfer",
+      href: "/nur",
+      image: "/images/PXL_20240408_0840372.jpg",
+    },
+    {
+      id: "joint_explorer",
+      name: "Joint Explorer",
+      tagline: "Electronic geological compass",
+      description:
+        "An electronic geological compass for measuring dip azimuths and dip angles of structural-geological features",
+      href: "/joint_explorer",
+      image: "/images/photo_2022-08-25_21-.jpg",
+    },
+    {
+      id: "scientiajoints",
+      name: "ScientiaJoints",
+      tagline: "Blender plugin",
+      description:
+        "A plugin for the free and open-source Blender software, designed for digital joint mapping on 3D models",
+      href: "/scientiajoints",
+      image: "/images/1.jpg",
+    },
+  ],
+  ru: [
+    {
+      id: "prorock",
+      name: "Prorock 2.0",
+      tagline: "Численное моделирование в геомеханике",
+      description:
+        "Программа для решения задач геомеханики с возможностью моделирования разрушений и динамических процессов",
+      href: "/prorock",
+      image: "/images/21.jpg",
+    },
+    {
+      id: "magicore",
+      name: "Magicore",
+      tagline: "ИИ-документация керна",
+      description:
+        "Сервис для автоматической генерации геомеханической документации керна по фотографии",
+      href: "/magicore",
+      image: "/images/image.png",
+      external: "https://magicore.scientia.ru",
+    },
+    {
+      id: "digger",
+      name: "Digger Slope",
+      tagline: "Оптимизация бортов карьера",
+      description:
+        "Программа для оптимизации бортов карьера с применением 3К-моделирования",
+      href: "/digger",
+      image: "/images/20200629_203443.jpg",
+    },
+    {
+      id: "nur",
+      name: "Экстензометр NUR",
+      tagline: "Автоматизированный мониторинг смещений",
+      description:
+        "Прибор для автоматизированного мониторинга смещений на лазерном дальномере с онлайн-передачей данных",
+      href: "/nur",
+      image: "/images/PXL_20240408_0840372.jpg",
+    },
+    {
+      id: "joint_explorer",
+      name: "Joint Explorer",
+      tagline: "Электронный горный компас",
+      description:
+        "Электронный горный компас для определения азимутов и углов падения структурно-геологических элементов",
+      href: "/joint_explorer",
+      image: "/images/photo_2022-08-25_21-.jpg",
+    },
+    {
+      id: "scientiajoints",
+      name: "ScientiaJoints",
+      tagline: "Плагин для Blender",
+      description:
+        "Плагин для свободно распространяемого ПО Blender, предназначенный для цифрового картирования трещин на трёхмерных моделях",
+      href: "/scientiajoints",
+      image: "/images/1.jpg",
+    },
+  ],
+};

+ 145 - 74
src/data/prorock-updates.ts

@@ -1,4 +1,5 @@
 // Generated from the live scientia.ru/prorock_updates page.
+import type { Localized } from "../i18n";
 
 export type Release = {
   version: string;
@@ -6,77 +7,147 @@ export type Release = {
   sections: { title: string; items: string[] }[];
 };
 
-export const prorockReleases: Release[] = [
-  {
-    "version": "2.3.0",
-    "date": "14.04.2026",
-    "sections": [
-      {
-        "title": "Новые возможности",
-        "items": []
-      },
-      {
-        "title": "Решение",
-        "items": [
-          "Добавлена возможность учета физико-механических свойств для отдельных конечных и трещинных дискретных элементов.",
-          "Добавлена возможность запускать несколько проектов поочередно при нажатии на MENU (МЕНЮ) -> Calculation series (Серия расчетов).",
-          "Для видов стадий Excavation (Экскавация) и Change Properties (Замена свойств) добавлена возможность выбора нескольких областей.",
-          "Добавлена возможность экскавации упругой области.",
-          "Добавлено окно для настроек автозаполнения продолжительностей этапов.",
-          "Добавлены проверки для настроек продолжительности этапов.Рисование"
-        ]
-      },
-      {
-        "title": "Рисование",
-        "items": [
-          "На нижней панели кнопка ORTHO (ОРТО) заменена на кнопку SNAP (ПРИВЯЗКА) и добавлено меню, открывающееся при нажатии на эту кнопку, с видами привязок: 1) к границе 2) к сетке 3) орто",
-          "При включении привязки к сетке включается отображение сетки и при выключении отображения сетки отключается привязка к сетке."
-        ]
-      },
-      {
-        "title": "Импорт",
-        "items": [
-          "Добавлена возможность импортировать свойства из блочной модели (БМ) при нажатии на кнопку Import BM data (Импорт данных БМ). Используются критерии Мора-Кулона и Хука-Брауна.",
-          "Более точная обработка геометрии при импорте .dxf файлов."
-        ]
-      },
-      {
-        "title": "Отображение",
-        "items": [
-          "Добавлена возможность просмотра импортированных из БМ физико-механических свойств.",
-          "Добавлено возможность просмотра ошибок, возникших при импорте свойств из БМ.",
-          "Доработан перевод некоторых элементов графического интерфейса и сообщений.",
-          "Отображение величины нагрузки по умолчанию включено.",
-          "Добавлен выбор параметров для визуализации в окне Check Mesh (Качество сетки).",
-          "Введен новый строковый формат для чисел. Если число < 0.001 или > 1000, то число отображается в виде 1.234*10^b.",
-          "Добавлена возможность заливки заднего фона цветовой шкалы белым цветом.Результаты"
-        ]
-      },
-      {
-        "title": "Результаты",
-        "items": [
-          "Добавлена информация о скорости: 1) выгрузка в ElementData 2) скриншоты 3) отображение 4) информация об узлах, элементах и Label value at point (Значение в точке).",
-          "Добавлена выгрузка Safety factor (Коэффициент запаса прочности).Руководство пользователя"
-        ]
-      },
-      {
-        "title": "Руководство пользователя",
-        "items": [
-          "Открытие руководства пользователя на сайте Scientia при нажатии на кнопку Help."
-        ]
-      },
-      {
-        "title": "Исправление ошибок",
-        "items": [
-          "Исправлено отображение анкерных элементов. Проблема: \"Отсутствовал пересчет координат\".",
-          "Масштабирование модели происходит только по двойному нажатию средней кнопки мыши. Проблема: \"Масштабирование происходило по двойному нажатию на правую или левую кнопки мыши\".",
-          "Оптимизация геометрических алгоритмов.",
-          "Исправлено удаление трещин при ручном редактировании в окне Check Geometry (Качество геометрии).",
-          "Исправлена ошибка с отсутствием изображения при сохранении проекта.",
-          "Исправлена ошибка отображения углов в окне Check Mesh (Качество сетки). Проблема: \"Не всегда отображался правильный угол\".",
-          "Проверка существования файлов расчета .prc происходит повторно при переходе на вкладку Results (Результаты). Проблема: \"В текстовом поле номера файла расчета мог отображаться номер файла, которого уже нет в папке результатов\"."
-        ]
-      }
-    ]
-  }
-];
+export const prorockReleases: Localized<Release[]> = {
+  en: [
+    {
+      version: "2.3.0",
+      date: "14.04.2026",
+      sections: [
+        { title: "New features", items: [] },
+        {
+          title: "Solver",
+          items: [
+            "Added support for physical and mechanical properties of individual finite and joint discrete elements.",
+            "Added the ability to run several projects sequentially via MENU -> Calculation series.",
+            "For the Excavation and Change Properties stage types, multiple regions can now be selected.",
+            "Added the ability to excavate an elastic region.",
+            "Added a window with auto-fill settings for stage durations.",
+            "Added validation for stage duration settings.Drawing",
+          ],
+        },
+        {
+          title: "Drawing",
+          items: [
+            "The ORTHO button on the bottom panel has been replaced with a SNAP button that opens a menu with snapping modes: 1) to edge 2) to grid 3) ortho.",
+            "Enabling snap-to-grid turns grid display on, and turning the grid display off disables snap-to-grid.",
+          ],
+        },
+        {
+          title: "Import",
+          items: [
+            "Added the ability to import properties from a block model (BM) via the Import BM data button. Mohr-Coulomb and Hoek-Brown criteria are supported.",
+            "More accurate geometry processing when importing .dxf files.",
+          ],
+        },
+        {
+          title: "Display",
+          items: [
+            "Added the ability to view physical and mechanical properties imported from a block model.",
+            "Added the ability to view errors that occurred during property import from a block model.",
+            "Improved translation of several UI elements and messages.",
+            "Load magnitude display is now enabled by default.",
+            "Added parameter selection for visualization in the Check Mesh window.",
+            "Introduced a new string format for numbers: values below 0.001 or above 1000 are shown as 1.234*10^b.",
+            "Added the ability to fill the color scale background with white.Results",
+          ],
+        },
+        {
+          title: "Results",
+          items: [
+            "Added velocity information: 1) export to ElementData 2) screenshots 3) display 4) node, element, and Label value at point info.",
+            "Added export of the Safety factor.User Guide",
+          ],
+        },
+        {
+          title: "User guide",
+          items: [
+            "The user guide on the Scientia website now opens when the Help button is pressed.",
+          ],
+        },
+        {
+          title: "Bug fixes",
+          items: [
+            "Fixed the display of bolt elements. Issue: \"Coordinates were not recalculated\".",
+            "Model scaling now works only on double click of the middle mouse button. Issue: \"Scaling was triggered by double-clicking the right or left button\".",
+            "Optimization of geometric algorithms.",
+            "Fixed deletion of joints during manual editing in the Check Geometry window.",
+            "Fixed a missing image when saving a project.",
+            "Fixed the display of angles in the Check Mesh window. Issue: \"The correct angle was not always shown\".",
+            "Calculation files (.prc) are now re-checked when switching to the Results tab. Issue: \"The calculation file number field could show a file that no longer exists in the results folder\".",
+          ],
+        },
+      ],
+    },
+  ],
+  ru: [
+    {
+      version: "2.3.0",
+      date: "14.04.2026",
+      sections: [
+        { title: "Новые возможности", items: [] },
+        {
+          title: "Решение",
+          items: [
+            "Добавлена возможность учета физико-механических свойств для отдельных конечных и трещинных дискретных элементов.",
+            "Добавлена возможность запускать несколько проектов поочередно при нажатии на MENU (МЕНЮ) -> Calculation series (Серия расчетов).",
+            "Для видов стадий Excavation (Экскавация) и Change Properties (Замена свойств) добавлена возможность выбора нескольких областей.",
+            "Добавлена возможность экскавации упругой области.",
+            "Добавлено окно для настроек автозаполнения продолжительностей этапов.",
+            "Добавлены проверки для настроек продолжительности этапов.Рисование",
+          ],
+        },
+        {
+          title: "Рисование",
+          items: [
+            "На нижней панели кнопка ORTHO (ОРТО) заменена на кнопку SNAP (ПРИВЯЗКА) и добавлено меню, открывающееся при нажатии на эту кнопку, с видами привязок: 1) к границе 2) к сетке 3) орто",
+            "При включении привязки к сетке включается отображение сетки и при выключении отображения сетки отключается привязка к сетке.",
+          ],
+        },
+        {
+          title: "Импорт",
+          items: [
+            "Добавлена возможность импортировать свойства из блочной модели (БМ) при нажатии на кнопку Import BM data (Импорт данных БМ). Используются критерии Мора-Кулона и Хука-Брауна.",
+            "Более точная обработка геометрии при импорте .dxf файлов.",
+          ],
+        },
+        {
+          title: "Отображение",
+          items: [
+            "Добавлена возможность просмотра импортированных из БМ физико-механических свойств.",
+            "Добавлено возможность просмотра ошибок, возникших при импорте свойств из БМ.",
+            "Доработан перевод некоторых элементов графического интерфейса и сообщений.",
+            "Отображение величины нагрузки по умолчанию включено.",
+            "Добавлен выбор параметров для визуализации в окне Check Mesh (Качество сетки).",
+            "Введен новый строковый формат для чисел. Если число < 0.001 или > 1000, то число отображается в виде 1.234*10^b.",
+            "Добавлена возможность заливки заднего фона цветовой шкалы белым цветом.Результаты",
+          ],
+        },
+        {
+          title: "Результаты",
+          items: [
+            "Добавлена информация о скорости: 1) выгрузка в ElementData 2) скриншоты 3) отображение 4) информация об узлах, элементах и Label value at point (Значение в точке).",
+            "Добавлена выгрузка Safety factor (Коэффициент запаса прочности).Руководство пользователя",
+          ],
+        },
+        {
+          title: "Руководство пользователя",
+          items: [
+            "Открытие руководства пользователя на сайте Scientia при нажатии на кнопку Help.",
+          ],
+        },
+        {
+          title: "Исправление ошибок",
+          items: [
+            "Исправлено отображение анкерных элементов. Проблема: \"Отсутствовал пересчет координат\".",
+            "Масштабирование модели происходит только по двойному нажатию средней кнопки мыши. Проблема: \"Масштабирование происходило по двойному нажатию на правую или левую кнопки мыши\".",
+            "Оптимизация геометрических алгоритмов.",
+            "Исправлено удаление трещин при ручном редактировании в окне Check Geometry (Качество геометрии).",
+            "Исправлена ошибка с отсутствием изображения при сохранении проекта.",
+            "Исправлена ошибка отображения углов в окне Check Mesh (Качество сетки). Проблема: \"Не всегда отображался правильный угол\".",
+            "Проверка существования файлов расчета .prc происходит повторно при переходе на вкладку Results (Результаты). Проблема: \"В текстовом поле номера файла расчета мог отображаться номер файла, которого уже нет в папке результатов\".",
+          ],
+        },
+      ],
+    },
+  ],
+};

+ 59 - 27
src/data/publications.ts

@@ -1,34 +1,66 @@
 // Publications migrated from scientia.ru/about
+import type { Localized } from "../i18n";
 
 export type Publication = { text: string; href?: string };
 
-export const publications: Publication[] = [
-  {"text":"Гузеев И.А., Ильясов Б.Т., Мусихин А.С. Искусственный интеллект для документирования керна скальных грунтов // \"Мосты и время\" Специальный выпуск журнала \"ДОРОГИ. Инновации в строительстве\" № 130. 2025. с. 30.","href":"https://files.scientia.ru/public/dce6ad9b6d01"},
-  {"text":"Ильясов Б.Т., Ожиганов И.А., Трофимов А.В. О влиянии пространственной изменчивости прочности пород на удароопасность породных массивов // Научно-технический и производственный журнал «Горная промышленность» № 6. 2024. с. 74-82.","href":"https://download.scientia.ru/Mining_industry_6_Geomechanics.pdf"},
-  {"text":"Ильясов Б.Т., Кульсаитов Р.В., Неугомонов С.С., Солуянов Н.О. Оценка устойчивости закрепленный выработки на основе численного моделирования методом конечно-дискретных элементов // Горный журнал «Геотехническое моделирование в горном деле: задачи, методы и современная практика» № 1 (2306). 2023. с. 118-123.","href":"http://77.246.99.121:8111/19.%20%D0%98%D0%BB%D1%8C%D1%8F%D1%81%D0%BE%D0%B2%20%D0%91.%D0%A2.%20%282%29.pdf"},
-  {"text":"Солуянов Н.О., Кузьмин С.В., Цымбалов А.А., Давыдов А.А. Анализ исходных данных при построении геомеханической модели шахты «Глубокая» рудника «Скалистый» в контуре залежи богатых руд С-6 Октябрьского месторождения. ЗФ ПАО «ГМК «Норильский Никель». 2023. №6. С. 12-17.","href":"http://77.246.99.121:8111/%D0%93%D0%BE%D1%80%D0%BD%D1%8B%D0%B9%20%D0%B6%D1%83%D1%80%D0%BD%D0%B0%D0%BB%20%E2%84%96%206%20%D0%BE%D1%82%202023%20%D0%B3-2.pdf"},
-  {"text":"Ильясов Б.Т. О необходимости эксплицитного моделирования разрушения горных пород в геомеханике на практических примерах // Сборник материалов конференции и школы молодых ученых и студентов «Разрушение горных пород и минералов». Екатеринбург. УГГУ, 2023. с. 68-70.","href":"http://77.246.99.121:8111/elibrary_50515201_28793160%20%D0%98%D0%BB%D1%8C%D1%8F%D1%81%D0%BE%D0%B2.pdf"},
-  {"text":"Ильясов Б.Т., Солуянов Н.О., Садинов Ш.М., Содиков И.Ю. Оптимизация бортов карьера Бесапантау на основе 3К-моделирования в программном комплексе DIGGER SLOPE // Научно-технический и производственный журнал «Горный вестник Узбекистана» № 1 (92). 2023. с. 4-12.","href":"http://77.246.99.121:8111/2023-yanvar-mart1.pdf"},
-  {"text":"Гузеев И.А. Прогнозирование структурных обрушений уступов карьера по данным комбинированной съемки трещиноватости // Сборник материалов конференции и школы молодых ученых и студентов «Разрушение горных пород и минералов». Екатеринбург. УГГУ, 2023. с. 66-68.","href":"http://77.246.99.121:8111/elibrary_50515201_28793160%20%D0%93%D1%83%D0%B7%D0%B5%D0%B5%D0%B2.pdf"},
-  {"text":"Ильясов Б.Т. Разработка и применение геомеханической модели месторождения, отрабатываемого открытым способом // VI международный форум Seymartec Mining. Челябинск: 2022. c.16.","href":"http://77.246.99.121:8111/SEYMARTEC_MINING_%D0%A0%D0%90%D0%97%D0%A0%D0%90%D0%91%D0%9E%D0%A2%D0%9A%D0%90_%D0%98_%D0%9F%D0%A0%D0%98%D0%9C%D0%95%D0%9D%D0%95%D0%9D%D0%98%D0%95.pdf"},
-  {"text":"Мусихин А.С. Современные методы структурно­ геологической съемки в геомеханике // VI международный форум Seymartec Mining. Челябинск: 2022. c.17.","href":"http://77.246.99.121:8111/SEYMARTEC_MINING_%D0%A1%D0%9E%D0%92%D0%A0%D0%95%D0%9C%D0%95%D0%9D%D0%9D%D0%AB%D0%95.pdf"},
-  {"text":"Ильясов Б. Т., Гузеев И. А. Изучение трещиноватости горных пород железорудных месторождений на основе аэрофотосъёмки для обоснования параметров устойчивых уступов // Сборник научных статей «Маркшейдерское искусство, геометрия недр и горная геомеханика − 100 лет на «cедом» Урале». Екатеринбург: УГГУ, 2021. с.165-172.","href":"http://77.246.99.121:8111/IlyasovBT_GuzeevIA_Izuchenie_treshchinovatosti.pdf"},
-  {"text":"Рузиев Н.Б., Садинов Ш.М., Мусаев Г.М, Ильясов Б.Т. Изучение месторождения Амантайтау и разработка его геомеханической модели // Научно-технический и производственный журнал «Горный вестник Узбекистана» № 3 (82). 2020. с. 32-34.","href":"http://download.scientia.ru:8111/2020-iyul-sentyabr.pdf"},
-  {"text":"Ilyasov, B., Makarov, A., Biryuchiov, I. Prediction of rock movements using a finite-discrete element method // EUROCK – 2018. Geomechanics and Geodynamics of Rock Masses. pp. 805-810.","href":"https://download.scientia.ru/10.%20PREDICTIONOFROCKMOVEMENTS.pdf"},
-  {"text":"S. Antonyuk, B. Sogrin, V. Kolpakov & N. Soluyanov. Modeling geomechanical system of the Polymetal Company. Eurock “Geomechanics and geodynamics of rock masses”. Saint-Petersburg, 22-26 may 2018.","href":"https://download.scientia.ru/11%20-%20Article%20-%20Modeling%20geomechanical%20system%20%28RUS%29.pdf"},
-  {"text":"Ильясов Б.Т. Прогнозирование деформаций массивов горных пород с применением ПК «Prorock» // Проблемы недоропользования. №1. 2018. с. 39-51. DOI: 10.25635/2313-1586.2018.01.039.","href":"http://77.246.99.121:8111/%D0%98%D0%BB%D1%8C%D1%8F%D1%81%D0%BE%D0%B2-%D0%9F%D1%80%D0%BE%D0%B3%D0%BD%D0%BE%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5.pdf"},
-  {"text":"Солуянов Н.О., Антонюк С.А., Согрин Б.Б., Колпаков В.Б. Геомеханическая модель как средство обеспечения безопасной разработки рудных месторождений. VII Международная научно-техническая конференция «Инновационные направления в проектировании горнодобывающих предприятий», НМСУ «Горный», Санкт-Петербург, 12-13 мая 2016 г.","href":"https://download.scientia.ru/13%20%D0%A1%D1%82%D0%B0%D1%82%D1%8C%D1%8F%20-%20%D0%B3%D0%B5%D0%BE%D0%BC%D0%B5%D1%85.%20%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C%20%D0%BA%D0%B0%D0%BA%20%D0%B8%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BC%D0%B5%D0%BD%D1%82.pdf"},
-  {"text":"Солуянов Н.О. Методика построения геомеханической модели для планирования открытых горных работ. // Маркшейдерия и недропользование №6, ноябрь-декабрь 2015 г."},
-  {"text":"Макаров А.Б., Hormazabal Esteban, Ливинский И.С., Спирин В.И., Солуянов Н.О. Методика обратных расчётов сцепления и трения по трещинам по фактам вывалов с бортов карьеров. VI Международная научно-техническая конференция «Инновационные направления в проектировании горнодобывающих предприятий», НМСУ «Горный», Санкт-Петербург, 14-15 мая 2015 г.","href":"http://77.246.99.121:8111/%D0%9E%D0%B1%D1%80%D0%B0%D1%82%D0%BD%D1%8B%D0%B5_%D1%80%D0%B0%D1%81%D1%87%D0%B5%D1%82%D1%8B_%D1%81%D1%86%D0%B5%D0%BF%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F.pdf"},
-];
+export const publications: Localized<Publication[]> = {
+  en: [
+    { text: "Guzeev I.A., Ilyasov B.T., Musikhin A.S. Artificial intelligence for core documentation of rock masses // \"Mosty i Vremya\", special issue of \"ROADS. Innovations in Construction\" No. 130. 2025. p. 30.", href: "https://files.scientia.ru/public/dce6ad9b6d01" },
+    { text: "Ilyasov B.T., Ozhiganov I.A., Trofimov A.V. On the effect of spatial strength variability on rockburst hazard of rock masses // Mining Industry Journal No. 6. 2024. pp. 74-82.", href: "https://download.scientia.ru/Mining_industry_6_Geomechanics.pdf" },
+    { text: "Ilyasov B.T., Kulsaitov R.V., Neugomonov S.S., Soluyanov N.O. Stability assessment of a supported opening based on combined finite-discrete element modeling // Mining Journal \"Geotechnical modeling in mining: tasks, methods and current practice\" No. 1 (2306). 2023. pp. 118-123.", href: "http://77.246.99.121:8111/19.%D0%98%D0%BB%D1%8C%D1%8F%D1%81%D0%BE%D0%B2%20%D0%91.%D0%A2.%20%282%29.pdf" },
+    { text: "Soluyanov N.O., Kuzmin S.V., Tsymbalov A.A., Davydov A.A. Analysis of input data for building the geomechanical model of the Glubokaya mine, Skalisty deposit, S-6 rich ore zone of the Oktyabrskoye deposit. Kola MMC (Nornickel). 2023. No. 6. pp. 12-17.", href: "http://77.246.99.121:8111/%D0%93%D0%BE%D1%80%D0%BD%D1%8B%D0%B9%20%D0%B6%D1%83%D1%80%D0%BD%D0%B0%D0%BB%20%E2%84%96%206%20%D0%BE%D1%82%202023%20%D0%B3-2.pdf" },
+    { text: "Ilyasov B.T. On the need for explicit modeling of rock failure in geomechanics, with practical examples // Proceedings of the conference and young scientists' school \"Rock and Mineral Failure\". Yekaterinburg, USMU, 2023. pp. 68-70.", href: "http://77.246.99.121:8111/elibrary_50515201_28793160%20%D0%98%D0%BB%D1%8C%D1%8F%D1%81%D0%BE%D0%B2.pdf" },
+    { text: "Ilyasov B.T., Soluyanov N.O., Sadinov Sh.M., Sodikov I.Yu. Optimization of the Besapantau open-pit slopes based on 3D modeling in the DIGGER SLOPE software // Mining Bulletin of Uzbekistan No. 1 (92). 2023. pp. 4-12.", href: "http://77.246.99.121:8111/2023-yanvar-mart1.pdf" },
+    { text: "Guzeev I.A. Predicting structural failures of pit benches from combined joint survey data // Proceedings of the conference and young scientists' school \"Rock and Mineral Failure\". Yekaterinburg, USMU, 2023. pp. 66-68.", href: "http://77.246.99.121:8111/elibrary_50515201_28793160%20%D0%93%D1%83%D0%B7%D0%B5%D0%B5%D0%B2.pdf" },
+    { text: "Ilyasov B.T. Development and application of a geomechanical model of an open-pit mine // VI international forum Seymartec Mining. Chelyabinsk, 2022. p. 16.", href: "http://77.246.99.121:8111/SEYMARTEC_MINING_%D0%A0%D0%90%D0%97%D0%A0%D0%90%D0%91%D0%9E%D0%A2%D0%9A%D0%90_%D0%98_%D0%9F%D0%A0%D0%98%D0%9C%D0%95%D0%9D%D0%95%D0%9D%D0%98%D0%95.pdf" },
+    { text: "Musikhin A.S. Modern methods of structural-geological surveying in geomechanics // VI international forum Seymartec Mining. Chelyabinsk, 2022. p. 17.", href: "http://77.246.99.121:8111/SEYMARTEC_MINING_%D0%A1%D0%9E%D0%92%D0%A0%D0%95%D0%9C%D0%95%D0%9D%D0%9D%D0%AB%D0%95.pdf" },
+    { text: "Ilyasov B.T., Guzeev I.A. Study of jointing in iron-ore deposits based on aerial photography to justify stable bench parameters // \"Mine surveying, subsurface geometry and mining geomechanics — 100 years on the \"grey\" Urals\". Yekaterinburg, USMU, 2021. pp. 165-172.", href: "http://77.246.99.121:8111/IlyasovBT_GuzeevIA_Izuchenie_treshchinovatosti.pdf" },
+    { text: "Ruziev N.B., Sadinov Sh.M., Musaev G.M., Ilyasov B.T. Study of the Amantaytau deposit and development of its geomechanical model // Mining Bulletin of Uzbekistan No. 3 (82). 2020. pp. 32-34.", href: "http://download.scientia.ru:8111/2020-iyul-sentyabr.pdf" },
+    { text: "Ilyasov, B., Makarov, A., Biryuchiov, I. Prediction of rock movements using a finite-discrete element method // EUROCK – 2018. Geomechanics and Geodynamics of Rock Masses. pp. 805-810.", href: "https://download.scientia.ru/10.%20PREDICTIONOFROCKMOVEMENTS.pdf" },
+    { text: "S. Antonyuk, B. Sogrin, V. Kolpakov & N. Soluyanov. Modeling geomechanical system of the Polymetal Company. Eurock \"Geomechanics and geodynamics of rock masses\". Saint-Petersburg, 22-26 May 2018.", href: "https://download.scientia.ru/11%20-%20Article%20-%20Modeling%20geomechanical%20system%20%28RUS%29.pdf" },
+    { text: "Ilyasov B.T. Prediction of rock mass deformations using the Prorock software // Problems of Subsurface Use. No. 1. 2018. pp. 39-51. DOI: 10.25635/2313-1586.2018.01.039.", href: "http://77.246.99.121:8111/%D0%98%D0%BB%D1%8C%D1%8F%D1%81%D0%BE%D0%B2-%D0%9F%D1%80%D0%BE%D0%B3%D0%BD%D0%BE%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5.pdf" },
+    { text: "Soluyanov N.O., Antonyuk S.A., Sogrin B.B., Kolpakov V.B. A geomechanical model as a tool for safe mining of ore deposits. VII International scientific and technical conference \"Innovative directions in the design of mining enterprises\", Mining University, Saint Petersburg, 12-13 May 2016.", href: "https://download.scientia.ru/13%20%D0%A1%D1%82%D0%B0%D1%82%D1%8C%D1%8F%20-%20%D0%B3%D0%B5%D0%BE%D0%BC%D0%B5%D1%85.%20%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C%20%D0%BA%D0%B0%D0%BA%20%D0%B8%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BC%D0%B5%D0%BD%D1%82.pdf" },
+    { text: "Soluyanov N.O. A methodology for building a geomechanical model for open-pit mine planning // Mine Surveying and Subsurface Use No. 6, November-December 2015." },
+    { text: "Makarov A.B., Hormazabal Esteban, Livinsky I.S., Spirin V.I., Soluyanov N.O. A back-analysis method for joint cohesion and friction from bench failures in open pits. VI International scientific and technical conference \"Innovative directions in the design of mining enterprises\", Mining University, Saint Petersburg, 14-15 May 2015.", href: "http://77.246.99.121:8111/%D0%9E%D0%B1%D1%80%D0%B0%D1%82%D0%BD%D1%8B%D0%B5_%D1%80%D0%B0%D1%81%D1%87%D0%B5%D1%82%D1%8B_%D1%81%D1%86%D0%B5%D0%BF%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F.pdf" },
+  ],
+  ru: [
+    { text: "Гузеев И.А., Ильясов Б.Т., Мусихин А.С. Искусственный интеллект для документирования керна скальных грунтов // \"Мосты и время\" Специальный выпуск журнала \"ДОРОГИ. Инновации в строительстве\" № 130. 2025. с. 30.", href: "https://files.scientia.ru/public/dce6ad9b6d01" },
+    { text: "Ильясов Б.Т., Ожиганов И.А., Трофимов А.В. О влиянии пространственной изменчивости прочности пород на удароопасность породных массивов // Научно-технический и производственный журнал «Горная промышленность» № 6. 2024. с. 74-82.", href: "https://download.scientia.ru/Mining_industry_6_Geomechanics.pdf" },
+    { text: "Ильясов Б.Т., Кульсаитов Р.В., Неугомонов С.С., Солуянов Н.О. Оценка устойчивости закрепленный выработки на основе численного моделирования методом конечно-дискретных элементов // Горный журнал «Геотехническое моделирование в горном деле: задачи, методы и современная практика» № 1 (2306). 2023. с. 118-123.", href: "http://77.246.99.121:8111/19.%D0%98%D0%BB%D1%8C%D1%8F%D1%81%D0%BE%D0%B2%20%D0%91.%D0%A2.%20%282%29.pdf" },
+    { text: "Солуянов Н.О., Кузьмин С.В., Цымбалов А.А., Давыдов А.А. Анализ исходных данных при построении геомеханической модели шахты «Глубокая» рудника «Скалистый» в контуре залежи богатых руд С-6 Октябрьского месторождения. ЗФ ПАО «ГМК «Норильский Никель». 2023. №6. С. 12-17.", href: "http://77.246.99.121:8111/%D0%93%D0%BE%D1%80%D0%BD%D1%8B%D0%B9%20%D0%B6%D1%83%D1%80%D0%BD%D0%B0%D0%BB%20%E2%84%96%206%20%D0%BE%D1%82%202023%20%D0%B3-2.pdf" },
+    { text: "Ильясов Б.Т. О необходимости эксплицитного моделирования разрушения горных пород в геомеханике на практических примерах // Сборник материалов конференции и школы молодых ученых и студентов «Разрушение горных пород и минералов». Екатеринбург. УГГУ, 2023. с. 68-70.", href: "http://77.246.99.121:8111/elibrary_50515201_28793160%20%D0%98%D0%BB%D1%8C%D1%8F%D1%81%D0%BE%D0%B2.pdf" },
+    { text: "Ильясов Б.Т., Солуянов Н.О., Садинов Ш.М., Содиков И.Ю. Оптимизация бортов карьера Бесапантау на основе 3К-моделирования в программном комплексе DIGGER SLOPE // Научно-технический и производственный журнал «Горный вестник Узбекистана» № 1 (92). 2023. с. 4-12.", href: "http://77.246.99.121:8111/2023-yanvar-mart1.pdf" },
+    { text: "Гузеев И.А. Прогнозирование структурных обрушений уступов карьера по данным комбинированной съемки трещиноватости // Сборник материалов конференции и школы молодых ученых и студентов «Разрушение горных пород и минералов». Екатеринбург. УГГУ, 2023. с. 66-68.", href: "http://77.246.99.121:8111/elibrary_50515201_28793160%20%D0%93%D1%83%D0%B7%D0%B5%D0%B5%D0%B2.pdf" },
+    { text: "Ильясов Б.Т. Разработка и применение геомеханической модели месторождения, отрабатываемого открытым способом // VI международный форум Seymartec Mining. Челябинск: 2022. c.16.", href: "http://77.246.99.121:8111/SEYMARTEC_MINING_%D0%A0%D0%90%D0%97%D0%A0%D0%90%D0%91%D0%9E%D0%A2%D0%9A%D0%90_%D0%98_%D0%9F%D0%A0%D0%98%D0%9C%D0%95%D0%9D%D0%95%D0%9D%D0%98%D0%95.pdf" },
+    { text: "Мусихин А.С. Современные методы структурно­ геологической съемки в геомеханике // VI международный форум Seymartec Mining. Челябинск: 2022. c.17.", href: "http://77.246.99.121:8111/SEYMARTEC_MINING_%D0%A1%D0%9E%D0%92%D0%A0%D0%95%D0%9C%D0%95%D0%9D%D0%9D%D0%AB%D0%95.pdf" },
+    { text: "Ильясов Б. Т., Гузеев И. А. Изучение трещиноватости горных пород железорудных месторождений на основе аэрофотосъёмки для обоснования параметров устойчивых уступов // Сборник научных статей «Маркшейдерское искусство, геометрия недр и горная геомеханика − 100 лет на «cедом» Урале». Екатеринбург: УГГУ, 2021. с.165-172.", href: "http://77.246.99.121:8111/IlyasovBT_GuzeevIA_Izuchenie_treshchinovatosti.pdf" },
+    { text: "Рузиев Н.Б., Садинов Ш.М., Мусаев Г.М, Ильясов Б.Т. Изучение месторождения Амантайтау и разработка его геомеханической модели // Научно-технический и производственный журнал «Горный вестник Узбекистана» № 3 (82). 2020. с. 32-34.", href: "http://download.scientia.ru:8111/2020-iyul-sentyabr.pdf" },
+    { text: "Ilyasov, B., Makarov, A., Biryuchiov, I. Prediction of rock movements using a finite-discrete element method // EUROCK – 2018. Geomechanics and Geodynamics of Rock Masses. pp. 805-810.", href: "https://download.scientia.ru/10.%20PREDICTIONOFROCKMOVEMENTS.pdf" },
+    { text: "S. Antonyuk, B. Sogrin, V. Kolpakov & N. Soluyanov. Modeling geomechanical system of the Polymetal Company. Eurock “Geomechanics and geodynamics of rock masses”. Saint-Petersburg, 22-26 may 2018.", href: "https://download.scientia.ru/11%20-%20Article%20-%20Modeling%20geomechanical%20system%20%28RUS%29.pdf" },
+    { text: "Ильясов Б.Т. Прогнозирование деформаций массивов горных пород с применением ПК «Prorock» // Проблемы недоропользования. №1. 2018. с. 39-51. DOI: 10.25635/2313-1586.2018.01.039.", href: "http://77.246.99.121:8111/%D0%98%D0%BB%D1%8C%D1%8F%D1%81%D0%BE%D0%B2-%D0%9F%D1%80%D0%BE%D0%B3%D0%BD%D0%BE%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5.pdf" },
+    { text: "Солуянов Н.О., Антонюк С.А., Согрин Б.Б., Колпаков В.Б. Геомеханическая модель как средство обеспечения безопасной разработки рудных месторождений. VII Международная научно-техническая конференция «Инновационные направления в проектировании горнодобывающих предприятий», НМСУ «Горный», Санкт-Петербург, 12-13 мая 2016 г.", href: "https://download.scientia.ru/13%20%D0%A1%D1%82%D0%B0%D1%82%D1%8C%D1%8F%20-%20%D0%B3%D0%B5%D0%BE%D0%BC%D0%B5%D1%85.%20%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C%20%D0%BA%D0%B0%D0%BA%20%D0%B8%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BC%D0%B5%D0%BD%D1%82.pdf" },
+    { text: "Солуянов Н.О. Методика построения геомеханической модели для планирования открытых горных работ. // Маркшейдерия и недропользование №6, ноябрь-декабрь 2015 г." },
+    { text: "Макаров А.Б., Hormazabal Esteban, Ливинский И.С., Спирин В.И., Солуянов Н.О. Методика обратных расчётов сцепления и трения по трещинам по фактам вывалов с бортов карьеров. VI Международная научно-техническая конференция «Инновационные направления в проектировании горнодобывающих предприятий», НМСУ «Горный», Санкт-Петербург, 14-15 мая 2015 г.", href: "http://77.246.99.121:8111/%D0%9E%D0%B1%D1%80%D0%B0%D1%82%D0%BD%D1%8B%D0%B5_%D1%80%D0%B0%D1%81%D1%87%D0%B5%D1%82%D1%8B_%D1%81%D1%86%D0%B5%D0%BF%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F.pdf" },
+  ],
+};
 
 export type LicenseDoc = { title: string; href: string };
 
-export const licenseDocs: LicenseDoc[] = [
-  { title: "Лицензия на производство маркшейдерских работ", href: "https://files.scientia.ru/public/41b52ea6bac6" },
-  { title: "Выписка СРО о допуске к выполнению инженерных изысканий (НОПРИЗ)", href: "https://files.scientia.ru/public/b84b918cc0ba" },
-  { title: "Выписка СРО о допуске к выполнению проектных работ (НОПРИЗ)", href: "https://files.scientia.ru/public/f7006fda666e" },
-  { title: "Выписка СРО о допуске к выполнению проектных работ (ЦЕНТРСТРОЙПРОЕКТ)", href: "https://files.scientia.ru/public/153694da3da1" },
-  { title: "Выписка СРО о допуске к выполнению инженерных изысканий (ИНЖГЕОТЕХ)", href: "https://files.scientia.ru/public/5f38e8e630f1" },
-  { title: "Лицензия на осуществление образовательной деятельности", href: "https://files.scientia.ru/public/a1418e4804d9" },
-];
+export const licenseDocs: Localized<LicenseDoc[]> = {
+  en: [
+    { title: "Mine surveying operations license", href: "https://files.scientia.ru/public/41b52ea6bac6" },
+    { title: "SRO certificate for engineering surveys (NOPRIZ)", href: "https://files.scientia.ru/public/b84b918cc0ba" },
+    { title: "SRO certificate for design works (NOPRIZ)", href: "https://files.scientia.ru/public/f7006fda666e" },
+    { title: "SRO certificate for design works (TSENTRSTROYPROEKT)", href: "https://files.scientia.ru/public/153694da3da1" },
+    { title: "SRO certificate for engineering surveys (INZHGEOATEKH)", href: "https://files.scientia.ru/public/5f38e8e630f1" },
+    { title: "Educational activities license", href: "https://files.scientia.ru/public/a1418e4804d9" },
+  ],
+  ru: [
+    { title: "Лицензия на производство маркшейдерских работ", href: "https://files.scientia.ru/public/41b52ea6bac6" },
+    { title: "Выписка СРО о допуске к выполнению инженерных изысканий (НОПРИЗ)", href: "https://files.scientia.ru/public/b84b918cc0ba" },
+    { title: "Выписка СРО о допуске к выполнению проектных работ (НОПРИЗ)", href: "https://files.scientia.ru/public/f7006fda666e" },
+    { title: "Выписка СРО о допуске к выполнению проектных работ (ЦЕНТРСТРОЙПРОЕКТ)", href: "https://files.scientia.ru/public/153694da3da1" },
+    { title: "Выписка СРО о допуске к выполнению инженерных изысканий (ИНЖГЕОТЕХ)", href: "https://files.scientia.ru/public/5f38e8e630f1" },
+    { title: "Лицензия на осуществление образовательной деятельности", href: "https://files.scientia.ru/public/a1418e4804d9" },
+  ],
+};

+ 192 - 94
src/data/services.ts

@@ -1,3 +1,5 @@
+import type { Localized } from "../i18n";
+
 export type Service = {
   title: string;
   items?: string[];
@@ -9,97 +11,193 @@ export type Service = {
   tag?: string;
 };
 
-export const services: Service[] = [
-  {
-    title: "Комплексные решения",
-    items: [
-      "Оптимизация параметров бортов и уступов карьеров",
-      "Решение проблем с устойчивостью бортов карьеров и отвалов",
-      "Оптимизация параметров крепления горных выработок",
-      "Разработка рекомендаций для комбинированной разработки",
-    ],
-    image: "/images/20200629_141121.jpg",
-  },
-  {
-    title: "Исследование месторождений",
-    items: [
-      "Анализ фондовой документации",
-      "Структурно-геологическое картирование уступов карьеров и подземных выработок",
-      "Оценка породного массива с использованием рейтингов: GSI, Q, S, RMR, MRMR, Qslope, CSMR",
-    ],
-    image: "/images/32aaff8b-29d0-4e9a-8.jpeg",
-  },
-  {
-    title: "Геомеханическое моделирование",
-    items: [
-      "Определение геомеханических доменов в трехмерной среде",
-      "Разработка и актуализация геомеханических моделей",
-      "Оценка механических свойств массива и геологических структур, статистический анализ, проведение обратных расчетов",
-      "Составление программ и сопровождение геомеханического бурения скважин",
-      "Составление заданий на физико-механические испытания и их аудит",
-      "Генерация геомеханической документации керна на основе фотодокументации с применением нейросетей",
-    ],
-    image: "/images/photo_2022-09-19_06-.jpg",
-    tag: "NEW",
-  },
-  {
-    title: "Аналитические исследования",
-    items: [
-      "Детерминированный и вероятностный кинематический анализ уступов",
-      "Оценка и обоснование устойчивости бортов и отвалов с применением методов предельного равновесия",
-      "Моделирование методом конечных элементов в 2D и 3D",
-      "Моделирование методом конечно-дискретных элементов",
-      "Back-analysis деформационных процессов численным моделированием",
-      "Расчет устойчивых параметров конструктивных элементов систем разработки",
-      "Геомеханическое обоснование параметров систем разработок",
-    ],
-    image: "/images/image_2023-09-25_23-.png",
-  },
-  {
-    title: "Мониторинг деформаций",
-    items: [
-      "Визуальный (выявление рисков)",
-      "Радарный",
-      "Автоматизированный геотехнический",
-      "Спутниковый интерферометрический",
-      "Геометрическое нивелирование",
-      "Фотограмметрия с применением БПЛА",
-      "Интерпретация результатов наблюдений",
-      "Разработка программ автоматизированного мониторинга",
-    ],
-    objects: ["борта карьеров", "земная поверхность над подземными выработками", "отвалы"],
-    image: "/images/2_.jpg",
-  },
-  {
-    title: "Обучение",
-    items: [
-      "Структурно-геологическое картирование горных пород",
-      "Устойчивость бортов карьеров",
-      "Кинематический анализ и вероятностные расчёты устойчивости (с применением Digger Slope)",
-      "Численное моделирование в геомеханике (с применением Prorock)",
-      "Другие темы по направлениям нашей деятельности",
-    ],
-    image: "/images/photo_2024-12-13_10-.jpg",
-    href: "https://education.scientia.ru",
-    external: true,
-  },
-  {
-    title: "Геодезические работы",
-    items: [
-      "Топографические и геодезические изыскания",
-      "Геодезический мониторинг",
-      "Маркшейдерские работы",
-      "Воздушное лазерное сканирование",
-      "Аэрофотосъёмка и фотограмметрия",
-    ],
-    image: "/images/PXL_20240515_0620422.jpg",
-    href: "/geodesy",
-  },
-  {
-    title: "Скорая геотехническая помощь",
-    description:
-      "Быстрый запуск непрерывного мониторинга потенциальных обрушений на карьерах и отвалах с выработкой рекомендаций по мерам реагирования.",
-    image: "/images/1__2_.png",
-    href: "/emergency_care",
-  },
-];
+export const services: Localized<Service[]> = {
+  en: [
+    {
+      title: "Integrated solutions",
+      items: [
+        "Optimization of open-pit slope and bench parameters",
+        "Resolving pit slope and waste dump stability issues",
+        "Optimization of mine opening support parameters",
+        "Recommendations for combined open-pit and underground mining",
+      ],
+      image: "/images/20200629_141121.jpg",
+    },
+    {
+      title: "Deposit studies",
+      items: [
+        "Review of archived exploration and mining documentation",
+        "Structural-geological mapping of pit benches and underground openings",
+        "Rock mass assessment using GSI, Q, S, RMR, MRMR, Qslope, and CSMR ratings",
+      ],
+      image: "/images/32aaff8b-29d0-4e9a-8.jpeg",
+    },
+    {
+      title: "Geomechanical modeling",
+      items: [
+        "Delineation of geomechanical domains in a 3D environment",
+        "Development and updating of geomechanical models",
+        "Estimation of rock mass and geological structure properties, statistical analysis, back-analysis",
+        "Design and supervision of geomechanical drilling programs",
+        "Preparation of laboratory testing assignments and audit of the results",
+        "Generation of geomechanical core logs from photographic documentation using neural networks",
+      ],
+      image: "/images/photo_2022-09-19_06-.jpg",
+      tag: "NEW",
+    },
+    {
+      title: "Analytical studies",
+      items: [
+        "Deterministic and probabilistic kinematic analysis of benches",
+        "Pit slope and dump stability assessment using limit equilibrium methods",
+        "2D and 3D finite element modeling",
+        "Combined finite-discrete element modeling",
+        "Back-analysis of deformation processes by numerical modeling",
+        "Design of stable parameters for mining system elements",
+        "Geomechanical justification of mining system parameters",
+      ],
+      image: "/images/image_2023-09-25_23-.png",
+    },
+    {
+      title: "Deformation monitoring",
+      items: [
+        "Visual inspection (hazard identification)",
+        "Radar monitoring",
+        "Automated geotechnical monitoring",
+        "Satellite interferometry (InSAR)",
+        "Geometric leveling",
+        "UAV photogrammetry",
+        "Interpretation of monitoring results",
+        "Design of automated monitoring programs",
+      ],
+      objects: ["open-pit slopes", "ground surface above underground openings", "waste dumps"],
+      image: "/images/2_.jpg",
+    },
+    {
+      title: "Training",
+      items: [
+        "Structural-geological mapping of rocks",
+        "Open-pit slope stability",
+        "Kinematic analysis and probabilistic stability calculations (with Digger Slope)",
+        "Numerical modeling in geomechanics (with Prorock)",
+        "Other topics within our fields of expertise",
+      ],
+      image: "/images/photo_2024-12-13_10-.jpg",
+      href: "https://education.scientia.ru",
+      external: true,
+    },
+    {
+      title: "Geodetic surveying",
+      items: [
+        "Topographic and geodetic surveys",
+        "Geodetic monitoring",
+        "Mine surveying operations",
+        "Aerial laser scanning",
+        "Aerial photography and photogrammetry",
+      ],
+      image: "/images/PXL_20240515_0620422.jpg",
+      href: "/geodesy",
+    },
+    {
+      title: "Geotechnical emergency response",
+      description:
+        "Rapid deployment of continuous monitoring over potential collapse zones in open pits and waste dumps, with response measure recommendations.",
+      image: "/images/1__2_.png",
+      href: "/emergency_care",
+    },
+  ],
+  ru: [
+    {
+      title: "Комплексные решения",
+      items: [
+        "Оптимизация параметров бортов и уступов карьеров",
+        "Решение проблем с устойчивостью бортов карьеров и отвалов",
+        "Оптимизация параметров крепления горных выработок",
+        "Разработка рекомендаций для комбинированной разработки",
+      ],
+      image: "/images/20200629_141121.jpg",
+    },
+    {
+      title: "Исследование месторождений",
+      items: [
+        "Анализ фондовой документации",
+        "Структурно-геологическое картирование уступов карьеров и подземных выработок",
+        "Оценка породного массива с использованием рейтингов: GSI, Q, S, RMR, MRMR, Qslope, CSMR",
+      ],
+      image: "/images/32aaff8b-29d0-4e9a-8.jpeg",
+    },
+    {
+      title: "Геомеханическое моделирование",
+      items: [
+        "Определение геомеханических доменов в трехмерной среде",
+        "Разработка и актуализация геомеханических моделей",
+        "Оценка механических свойств массива и геологических структур, статистический анализ, проведение обратных расчетов",
+        "Составление программ и сопровождение геомеханического бурения скважин",
+        "Составление заданий на физико-механические испытания и их аудит",
+        "Генерация геомеханической документации керна на основе фотодокументации с применением нейросетей",
+      ],
+      image: "/images/photo_2022-09-19_06-.jpg",
+      tag: "NEW",
+    },
+    {
+      title: "Аналитические исследования",
+      items: [
+        "Детерминированный и вероятностный кинематический анализ уступов",
+        "Оценка и обоснование устойчивости бортов и отвалов с применением методов предельного равновесия",
+        "Моделирование методом конечных элементов в 2D и 3D",
+        "Моделирование методом конечно-дискретных элементов",
+        "Back-analysis деформационных процессов численным моделированием",
+        "Расчет устойчивых параметров конструктивных элементов систем разработки",
+        "Геомеханическое обоснование параметров систем разработок",
+      ],
+      image: "/images/image_2023-09-25_23-.png",
+    },
+    {
+      title: "Мониторинг деформаций",
+      items: [
+        "Визуальный (выявление рисков)",
+        "Радарный",
+        "Автоматизированный геотехнический",
+        "Спутниковый интерферометрический",
+        "Геометрическое нивелирование",
+        "Фотограмметрия с применением БПЛА",
+        "Интерпретация результатов наблюдений",
+        "Разработка программ автоматизированного мониторинга",
+      ],
+      objects: ["борта карьеров", "земная поверхность над подземными выработками", "отвалы"],
+      image: "/images/2_.jpg",
+    },
+    {
+      title: "Обучение",
+      items: [
+        "Структурно-геологическое картирование горных пород",
+        "Устойчивость бортов карьеров",
+        "Кинематический анализ и вероятностные расчёты устойчивости (с применением Digger Slope)",
+        "Численное моделирование в геомеханике (с применением Prorock)",
+        "Другие темы по направлениям нашей деятельности",
+      ],
+      image: "/images/photo_2024-12-13_10-.jpg",
+      href: "https://education.scientia.ru",
+      external: true,
+    },
+    {
+      title: "Геодезические работы",
+      items: [
+        "Топографические и геодезические изыскания",
+        "Геодезический мониторинг",
+        "Маркшейдерские работы",
+        "Воздушное лазерное сканирование",
+        "Аэрофотосъёмка и фотограмметрия",
+      ],
+      image: "/images/PXL_20240515_0620422.jpg",
+      href: "/geodesy",
+    },
+    {
+      title: "Скорая геотехническая помощь",
+      description:
+        "Быстрый запуск непрерывного мониторинга потенциальных обрушений на карьерах и отвалах с выработкой рекомендаций по мерам реагирования.",
+      image: "/images/1__2_.png",
+      href: "/emergency_care",
+    },
+  ],
+};

+ 50 - 23
src/data/site.ts

@@ -1,21 +1,25 @@
+export type TelegramChannel = { name: string; nameEn?: string; href: string };
+
 export const site = {
   name: "Scientia",
   legalName: "ООО «Скиентия»",
-  tagline: "Геомеханика и горное дело",
+  tagline: { en: "Geomechanics and mining", ru: "Геомеханика и горное дело" },
   url: "https://scientia.ru",
   phone: "+7 (922) 203-24-60",
   phoneHref: "tel:+79222032460",
   email: "info@scientia.ru",
   address:
+    "620014, Sverdlovsk Oblast, Yekaterinburg, Sheinkmana St., bldg. 9, office 65",
+  addressRu:
     "620014, Свердловская область, г. Екатеринбург, ул. Шейнкмана, стр. 9, офис 65",
   inn: "6686148633",
   kpp: "668601001",
   ogrn: "1236600002572",
   telegram: [
-    { name: "Канал компании", href: "https://t.me/scientia_ru" },
+    { name: "Канал компании", nameEn: "Company channel", href: "https://t.me/scientia_ru" },
     { name: "Magicore", href: "https://t.me/scientia_magicore" },
     { name: "Joint Explorer", href: "https://t.me/jointexplorer" },
-  ],
+  ] as TelegramChannel[],
   external: {
     education: "https://education.scientia.ru",
     blog: "https://teletype.media/@scientia",
@@ -27,23 +31,46 @@ export const site = {
 
 export type NavItem = { text: string; href: string; external?: boolean; children?: NavItem[] };
 
-export const nav: NavItem[] = [
-  { text: "Услуги", href: "/#uslugi" },
-  {
-    text: "Разработки",
-    href: "/#razrabotki",
-    children: [
-      { text: "Prorock 2.0", href: "/prorock" },
-      { text: "Magicore", href: "/magicore" },
-      { text: "Digger Slope", href: "/digger" },
-      { text: "Экстензометр NUR", href: "/nur" },
-      { text: "Joint Explorer", href: "/joint_explorer" },
-      { text: "ScientiaJoints", href: "/scientiajoints" },
-    ],
-  },
-  { text: "Обучение", href: site.external.education, external: true },
-  { text: "Блог", href: site.external.blog, external: true },
-  { text: "Wiki", href: site.external.wiki, external: true },
-  { text: "О нас", href: "/about" },
-  { text: "Контакты", href: "/about#contacts" },
-];
+// hrefs are locale-neutral; the Header localizes internal ones at render time.
+export const nav = {
+  en: [
+    { text: "Services", href: "/#uslugi" },
+    {
+      text: "Products",
+      href: "/#razrabotki",
+      children: [
+        { text: "Prorock 2.0", href: "/prorock" },
+        { text: "Magicore", href: "/magicore" },
+        { text: "Digger Slope", href: "/digger" },
+        { text: "NUR Extensometer", href: "/nur" },
+        { text: "Joint Explorer", href: "/joint_explorer" },
+        { text: "ScientiaJoints", href: "/scientiajoints" },
+      ],
+    },
+    { text: "Training", href: site.external.education, external: true },
+    { text: "Blog", href: site.external.blog, external: true },
+    { text: "Wiki", href: site.external.wiki, external: true },
+    { text: "About us", href: "/about" },
+    { text: "Contacts", href: "/about#contacts" },
+  ] as NavItem[],
+  ru: [
+    { text: "Услуги", href: "/#uslugi" },
+    {
+      text: "Разработки",
+      href: "/#razrabotki",
+      children: [
+        { text: "Prorock 2.0", href: "/prorock" },
+        { text: "Magicore", href: "/magicore" },
+        { text: "Digger Slope", href: "/digger" },
+        { text: "Экстензометр NUR", href: "/nur" },
+        { text: "Joint Explorer", href: "/joint_explorer" },
+        { text: "ScientiaJoints", href: "/scientiajoints" },
+      ],
+    },
+    { text: "Обучение", href: site.external.education, external: true },
+    { text: "Блог", href: site.external.blog, external: true },
+    { text: "Wiki", href: site.external.wiki, external: true },
+    { text: "О нас", href: "/about" },
+    { text: "Контакты", href: "/about#contacts" },
+  ] as NavItem[],
+};

文件差异内容过多而无法显示
+ 0 - 0
src/data/telegram-news.json


+ 106 - 0
src/i18n.ts

@@ -0,0 +1,106 @@
+// Locale plumbing for the bilingual site: English at /, Russian under /ru/.
+export const locales = ["en", "ru"] as const;
+export type Locale = (typeof locales)[number];
+export type Localized<T> = Record<Locale, T>;
+
+export const defaultLocale: Locale = "en";
+
+/** Locale of the current page, derived from the URL (/ru/... → "ru"). */
+export function getLocale(url: URL): Locale {
+  const [, first] = url.pathname.split("/");
+  return first === "ru" ? "ru" : "en";
+}
+
+/** Prefix an internal path with the locale segment when needed. */
+export function localePath(locale: Locale, path: string): string {
+  if (!path.startsWith("/") || path.startsWith("//")) return path; // external or anchor-only
+  if (locale === defaultLocale) return path;
+  return path === "/" ? "/ru/" : `/ru${path}`;
+}
+
+/** Same page in the other locale — used by the language switcher and hreflang. */
+export function otherLocalePath(locale: Locale, path: string): string {
+  return localePath(locale === "en" ? "ru" : "en", stripLocale(path));
+}
+
+/** Remove the /ru prefix from a path (for computing the counterpart URL). */
+export function stripLocale(path: string): string {
+  if (path === "/ru" || path === "/ru/") return "/";
+  return path.replace(/^\/ru(?=\/)/, "");
+}
+
+/** Shared UI strings. Page-specific copy lives in the page components. */
+export const ui: Localized<Record<string, string>> = {
+  en: {
+    "nav.primary": "Main navigation",
+    "nav.menu": "Menu",
+    "nav.contact": "Contact",
+    "header.products": "Products",
+    "header.information": "Information",
+    "header.contacts": "Contacts",
+    "footer.about": "About us",
+    "footer.publications": "Publications",
+    "footer.licenses": "Licenses",
+    "footer.education": "Training",
+    "footer.subscribe": "Newsletter",
+    "footer.blog": "Blog",
+    "footer.license": "Mine surveying operations license<br />Member of an SRO for engineering surveys",
+    "footer.privacy": "Personal data processing policy",
+    "cta.title": "Let's discuss your task",
+    "cta.subtitle":
+      "We will get back to you within one business day to answer questions and discuss the next steps.",
+    "cta.name": "Name",
+    "cta.phone": "Phone",
+    "cta.message": "Message",
+    "cta.submit": "Send",
+    "cta.consent":
+      "By clicking the button, you consent to the processing of personal data and agree to the privacy policy.",
+    "cta.consentLink": "privacy policy",
+    "cta.mailtoSubject": "Website inquiry — scientia.ru",
+    "tg.channel": "channel",
+    "tg.open": "Open in Telegram",
+    "tg.more": "Show more",
+    "tg.openPost": "Open post",
+    "tg.video": "Video",
+    "tg.photo": "Photo",
+    "tg.logoAlt": "Client logo",
+  },
+  ru: {
+    "nav.primary": "Основная навигация",
+    "nav.menu": "Меню",
+    "nav.contact": "Связаться",
+    "header.products": "Разработки",
+    "header.information": "Информация",
+    "header.contacts": "Контакты",
+    "footer.about": "Об организации",
+    "footer.publications": "Публикации",
+    "footer.licenses": "Лицензии",
+    "footer.education": "Образование",
+    "footer.subscribe": "Рассылка",
+    "footer.blog": "Блог",
+    "footer.license": "Лицензия на производство маркшейдерских работ<br />Член СРО в области инженерных изысканий",
+    "footer.privacy": "Политика обработки персональных данных",
+    "cta.title": "Обсудим вашу задачу",
+    "cta.subtitle":
+      "Мы свяжемся с вами в течение рабочего дня, чтобы ответить на вопросы и обсудить дальнейший план действий.",
+    "cta.name": "Имя",
+    "cta.phone": "Телефон",
+    "cta.message": "Сообщение",
+    "cta.submit": "Отправить",
+    "cta.consent":
+      "Нажимая на кнопку, вы даёте согласие на обработку персональных данных и соглашаетесь с",
+    "cta.consentLink": "политикой конфиденциальности",
+    "cta.mailtoSubject": "Запрос с сайта scientia.ru",
+    "tg.channel": "канал",
+    "tg.open": "Перейти в телеграм",
+    "tg.more": "Показать ещё",
+    "tg.openPost": "Открыть пост",
+    "tg.video": "Видео",
+    "tg.photo": "Фото",
+    "tg.logoAlt": "Логотип заказчика",
+  },
+};
+
+export function translator(locale: Locale) {
+  return (key: keyof (typeof ui)["en"] & string) => ui[locale][key] ?? key;
+}

+ 12 - 4
src/layouts/Base.astro

@@ -3,20 +3,25 @@ import "../styles/global.css";
 import Header from "../components/Header.astro";
 import Footer from "../components/Footer.astro";
 import { site } from "../data/site";
+import { type Locale, getLocale, otherLocalePath } from "../i18n";
 
 interface Props {
   title: string;
   description?: string;
   ogImage?: string;
+  locale?: Locale;
 }
 
 const { title, description = "", ogImage = "/images/1655676643_10-kartin.jpg" } = Astro.props;
+const locale = Astro.props.locale ?? getLocale(Astro.url);
 const fullTitle = title.includes(site.name) ? title : `${title} — ${site.name}`;
-const floating = Astro.url.pathname === "/";
+const floating = Astro.url.pathname === "/" || Astro.url.pathname === "/ru" || Astro.url.pathname === "/ru/";
+const enPath = locale === "en" ? Astro.url.pathname : otherLocalePath(locale, Astro.url.pathname);
+const ruPath = locale === "ru" ? Astro.url.pathname : otherLocalePath(locale, Astro.url.pathname);
 ---
 
 <!doctype html>
-<html lang="ru">
+<html lang={locale}>
   <head>
     <meta charset="UTF-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
@@ -27,14 +32,17 @@ const floating = Astro.url.pathname === "/";
     <meta property="og:type" content="website" />
     <meta property="og:url" content={new URL(Astro.url.pathname, site.url)} />
     <meta property="og:image" content={new URL(ogImage, site.url)} />
+    <link rel="alternate" hreflang="en" href={new URL(enPath, site.url)} />
+    <link rel="alternate" hreflang="ru" href={new URL(ruPath, site.url)} />
+    <link rel="alternate" hreflang="x-default" href={new URL(enPath, site.url)} />
     <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
     <meta name="generator" content={Astro.generator} />
   </head>
   <body>
-    <Header floating={floating} />
+    <Header floating={floating} locale={locale} />
     <main>
       <slot />
     </main>
-    <Footer />
+    <Footer locale={locale} />
   </body>
 </html>

+ 26 - 5
src/pages/404.astro

@@ -1,15 +1,36 @@
 ---
 import Base from "../layouts/Base.astro";
+import { getLocale } from "../i18n";
+
+const locale = getLocale(Astro.url);
+const home = locale === "ru" ? "/ru/" : "/";
+const copy = {
+  en: {
+    title: "Page not found",
+    h1: "Page not found",
+    text: "It may have been moved or deleted.",
+    button: "Go to homepage",
+    secondary: "Страница не найдена",
+  },
+  ru: {
+    title: "Страница не найдена",
+    h1: "Страница не найдена",
+    text: "Возможно, она была перемещена или удалена.",
+    button: "На главную",
+    secondary: "Page not found",
+  },
+}[locale];
 ---
 
-<Base title="Страница не найдена" description="Страница не найдена">
+<Base title={copy.title} description={copy.title} locale={locale}>
   <section class="bg-white">
     <div class="mx-auto max-w-xl px-4 py-32 text-center sm:px-6">
       <p class="text-7xl font-bold text-accent-300">404</p>
-      <h1 class="mt-4 text-2xl font-bold text-night-950">Страница не найдена</h1>
-      <p class="mt-3 text-slate-600">Возможно, она была перемещена или удалена.</p>
-      <a href="/" class="mt-8 inline-block rounded-lg bg-accent-300 px-6 py-3 font-semibold text-night-950 transition-colors hover:bg-accent-400">
-        На главную
+      <h1 class="mt-4 text-2xl font-bold text-night-950">{copy.h1}</h1>
+      <p class="mt-3 text-slate-600">{copy.text}</p>
+      <p class="text-sm text-slate-400">{copy.secondary}</p>
+      <a href={home} class="mt-8 inline-block rounded-lg bg-accent-300 px-6 py-3 font-semibold text-night-950 transition-colors hover:bg-accent-400">
+        {copy.button}
       </a>
     </div>
   </section>

+ 2 - 141
src/pages/about.astro

@@ -1,144 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import PageHero from "../components/PageHero.astro";
-import { site } from "../data/site";
-import { publications } from "../data/publications";
-import { licenseDocs } from "../data/publications";
+import AboutPage from "../components/pages/AboutPage.astro";
 ---
 
-<Base
-  title="Об организации"
-  description="Компания Scientia специализируется на научных исследованиях и консалтинге в сфере горной геомеханики"
->
-  <PageHero
-    title="Об организации"
-    subtitle="ООО «Скиентия» — научные исследования и консалтинг в сфере горной геомеханики"
-  />
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
-      <p class="text-lg leading-relaxed text-slate-700">
-        Компания Scientia специализируется на научных исследованиях и консалтинге в сфере горной
-        геомеханики, предлагая решения с передового края науки. Scientia выполняет комплексные
-        геомеханические исследования месторождений, изыскивая возможности для повышения безопасности
-        и экономической эффективности горных работ.
-      </p>
-      <p class="mt-5 text-lg leading-relaxed text-slate-700">
-        Компания является разработчиком специализированных приборов и программного обеспечения,
-        такого как:
-      </p>
-      <ul class="mt-4 space-y-2 text-lg text-slate-700">
-        <li class="flex gap-3"><span class="mt-3 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />сервис для автоматического документирования керна по фото Magicore,</li>
-        <li class="flex gap-3"><span class="mt-3 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />программа для оптимизации бортов карьера Digger Slope,</li>
-        <li class="flex gap-3"><span class="mt-3 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />программа для численного моделирования Prorock,</li>
-        <li class="flex gap-3"><span class="mt-3 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />автоматизированный экстензометр NUR,</li>
-        <li class="flex gap-3"><span class="mt-3 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />электронный горный компас Joint Explorer.</li>
-      </ul>
-
-      <div class="mt-10 rounded-2xl bg-slate-50 p-6 text-slate-700">
-        <h2 class="text-xl font-semibold text-night-950">{site.legalName}</h2>
-        <p class="mt-2 text-sm leading-relaxed">Адрес: {site.address}<br />ИНН: {site.inn} · КПП: {site.kpp} · ОГРН: {site.ogrn}</p>
-      </div>
-
-      <div class="mt-10 rounded-2xl border border-slate-200 p-6">
-        <h2 class="text-xl font-semibold text-night-950">Наука и образование</h2>
-        <p class="mt-3 leading-relaxed text-slate-600">
-          Наша команда занимается наукой и развитием профессионального сообщества. Делимся своими
-          наработками и открытиями в научных статьях, на конференциях, в своих соцсетях и в нашей
-          <a href={site.external.wiki} target="_blank" rel="noopener" class="font-medium text-accent-600 hover:text-accent-700">Wiki</a>.
-          Занимаемся
-          <a href={site.external.education} target="_blank" rel="noopener" class="font-medium text-accent-600 hover:text-accent-700">обучением</a>
-          по направлениям нашей деятельности.
-        </p>
-      </div>
-    </div>
-  </section>
-
-  <!-- Publications -->
-  <section id="publications" class="scroll-mt-20 bg-slate-50">
-    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
-      <h2 class="text-3xl font-bold tracking-tight text-night-950">Публикации</h2>
-      <ol class="mt-8 space-y-4">
-        {publications.map((p, i) => (
-          <li class="text-sm leading-relaxed text-slate-700">
-            <span class="font-semibold text-night-950">{i + 1})</span>{" "}
-            {p.href ? (
-              <a href={p.href} target="_blank" rel="noopener" class="hover:text-accent-700 hover:underline">
-                {p.text}
-              </a>
-            ) : (
-              p.text
-            )}
-          </li>
-        ))}
-      </ol>
-    </div>
-  </section>
-
-  <!-- Licenses -->
-  <section id="licenses" class="scroll-mt-20 bg-white">
-    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
-      <h2 class="text-3xl font-bold tracking-tight text-night-950">Лицензии</h2>
-      <p class="mt-3 text-slate-600">
-        Мы являемся членом СРО в области инженерных изысканий и подготовки проектной документации,
-        а также имеем лицензию на производство маркшейдерских работ и образовательную деятельность.
-      </p>
-      <ul class="mt-8 grid gap-4 sm:grid-cols-2">
-        {licenseDocs.map((l) => (
-          <li>
-            <a
-              href={l.href}
-              target="_blank"
-              rel="noopener"
-              class="flex items-center gap-3 rounded-xl border border-slate-200 p-4 text-sm font-medium text-night-900 transition-colors hover:border-accent-400 hover:bg-accent-50"
-            >
-              <svg class="h-6 w-6 shrink-0 text-accent-500" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true">
-                <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" />
-              </svg>
-              {l.title}
-            </a>
-          </li>
-        ))}
-      </ul>
-    </div>
-  </section>
-
-  <!-- Contacts -->
-  <section id="contacts" class="scroll-mt-20 bg-night-900 text-white">
-    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:py-20">
-      <h2 class="text-3xl font-bold tracking-tight sm:text-4xl">Контакты</h2>
-      <div class="mt-8 grid gap-10 md:grid-cols-2">
-        <div class="space-y-3 text-lg text-slate-300">
-          <p class="text-xl font-semibold text-white">{site.legalName}</p>
-          <p>Адрес: {site.address}</p>
-          <p>ИНН: {site.inn} · КПП: {site.kpp}</p>
-          <p>
-            Телефон:
-            <a href={site.phoneHref} class="font-semibold text-accent-300 hover:text-accent-200">{site.phone}</a>
-            (Россия)
-          </p>
-          <p>
-            E-mail:
-            <a href={`mailto:${site.email}`} class="font-semibold text-accent-300 hover:text-accent-200">{site.email}</a>
-          </p>
-        </div>
-        <div>
-          <h3 class="font-semibold uppercase tracking-wider text-slate-400">Наши Телеграм-каналы</h3>
-          <ul class="mt-4 space-y-3">
-            {site.telegram.map((t) => (
-              <li>
-                <a href={t.href} target="_blank" rel="noopener" class="text-lg font-medium text-accent-300 hover:text-accent-200">
-                  {t.name} ↗
-                </a>
-              </li>
-            ))}
-          </ul>
-          <div class="mt-6 space-y-2 text-sm text-slate-400">
-            <p><a href="/personal_data" class="underline hover:text-white">Политика обработки персональных данных</a></p>
-            <p><a href="/education" class="underline hover:text-white">Сведения об образовательной организации</a></p>
-          </div>
-        </div>
-      </div>
-    </div>
-  </section>
-</Base>
+<AboutPage locale="en" />

+ 2 - 172
src/pages/digger.astro

@@ -1,175 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import PageHero from "../components/PageHero.astro";
-import CTAForm from "../components/CTAForm.astro";
-
-const analysis = [
-  "Доменизация бортов карьера (структурное районирование и литологическое строение месторождения)",
-  "Гидрогеологические условия",
-  "Сейсмическая активность района",
-  "Действия внешних нагрузок",
-];
-
-const knnResults = [
-  "Рекомендованная конфигурация откоса: угол откоса, ширина бермы",
-  "Оценка устойчивости откоса: коэффициент запаса устойчивости, вероятность обрушения, уровень риска",
-  "Прогнозный объём обрушений",
-];
-
-const gallery = ["/images/_2-1zwkuo.jpg", "/images/1-axy1h6.jpg", "/images/2.jpg", "/images/3.jpg"];
-
-const docs = [
-  {
-    title: "Digger Slope — Буклет (Россия)",
-    href: "https://download.scientia.ru/Digger_Slope/Documents/Digger_Slope_Буклет_(Россия).pdf",
-  },
-  {
-    title: "Digger Slope — Презентация на конкурсе МайнДиджитал Майнекс 2022",
-    href: "https://download.scientia.ru/Digger_Slope/Documents/Digger_Slope_программный_комплекс_для_оптимизации_бортов_карьера_МАЙНЕКС_Россия_2022.pdf",
-  },
-  {
-    title: "Digger Slope — Презентация «Комплексный кинематический анализ в программе»",
-    href: "https://download.scientia.ru/Digger_Slope/Documents/Digger_Slope_Компл",
-  },
-];
+import DiggerPage from "../components/pages/DiggerPage.astro";
 ---
 
-<Base
-  title="Digger Slope"
-  description="Программа для расчётов коэффициента обеспечения устойчивости бортов карьера и отвалов, грунтового откоса уступов, оценки фактических рисков и снижения технологических затрат при отработке месторождения"
->
-  <PageHero
-    title="Digger Slope"
-    subtitle="Программный комплекс для анализа устойчивости и оптимизации бортов карьера, позволяющий оценить фактические риски и минимизировать технологические затраты при отработке месторождения"
-    image="/images/20200629_203443.jpg"
-  >
-    <a href="/diggerslope_updates" class="mt-6 inline-block rounded-lg bg-accent-300 px-5 py-2.5 font-semibold text-night-950 transition-colors hover:bg-accent-400">
-      История обновлений
-    </a>
-  </PageHero>
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
-      <div class="rounded-2xl border-l-4 border-accent-400 bg-accent-50 p-6 text-sm leading-relaxed text-slate-700">
-        Все расчёты в программе выполняются в строгом соответствии с Федеральными нормами и
-        правилами в области промышленной безопасности «Правила обеспечения устойчивости бортов и
-        уступов карьеров, разрезов и откосов отвалов» 2020 г. Программа сертифицирована в
-        РОССТАНДАРТе (реестровая запись №24973 от 27.11.2024).
-      </div>
-
-      <h2 class="mt-12 text-3xl font-bold tracking-tight text-night-950">Комплексный кинематический анализ</h2>
-      <p class="mt-4 leading-relaxed text-slate-700">
-        В программе реализован комплексный кинематический анализ устойчивости откосов на основании
-        детерминированного и вероятностного подходов с учётом:
-      </p>
-      <ul class="mt-4 space-y-2">
-        {analysis.map((a) => (
-          <li class="flex gap-3 text-slate-700">
-            <span class="mt-2.5 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
-            {a}
-          </li>
-        ))}
-      </ul>
-      <p class="mt-4 leading-relaxed text-slate-700">
-        Расчёт устойчивости производится автоматизировано по заданной сетке положения откоса (угол и
-        азимут падения с заданным шагом). Программный комплекс позволяет выполнить построение
-        Кинематической Карты Карьера (3К), включающей в себя результаты расчёта:
-      </p>
-      <ul class="mt-4 space-y-2">
-        {knnResults.map((a) => (
-          <li class="flex gap-3 text-slate-700">
-            <span class="mt-2.5 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
-            {a}
-          </li>
-        ))}
-      </ul>
-    </div>
-  </section>
-
-  <section class="bg-slate-50">
-    <div class="mx-auto grid max-w-7xl gap-8 px-4 py-16 sm:px-6 lg:grid-cols-2">
-      <div class="rounded-2xl border border-slate-200 bg-white p-8">
-        <h2 class="text-2xl font-bold text-night-950">Детальная настройка расчётов</h2>
-        <p class="mt-4 text-sm leading-relaxed text-slate-700">
-          В программе реализована детальная настройка расчётов предохранительной бермы на основе
-          детерминированного и вероятностного подходов с учётом задания свойств поверхности откоса,
-          срока службы бермы, эффективной ширины в зависимости от оборудования, корректировки
-          статистического распределения объёмов обрушений путём отсечения процента самых малых и
-          самых больших значений, снижения радиуса развала пород за счёт опытных данных и
-          эмпирических зависимостей.
-        </p>
-        <p class="mt-4 text-sm leading-relaxed text-slate-700">
-          Помимо основных видов обрушений (плоское, клиновидное, опрокидывание) программа позволяет
-          выполнить автоматизированный поиск трещины отрыва с детальной настройкой и расчётом
-          критичной дистанции трещины отрыва от бровки откоса.
-        </p>
-        <p class="mt-4 text-sm leading-relaxed text-slate-700">
-          Масштабируемость каждого вида обрушений задаётся в программе с обеих сторон — ограничения
-          минимальных и максимальных значений выбранных параметров (высота, ширина, объём и вес
-          обрушения, длина трещин и граней), а также фильтр результатов для определённого режима
-          обрушения и диапазона коэффициента запаса устойчивости.
-        </p>
-      </div>
-      <div class="space-y-8">
-        <div class="rounded-2xl border border-slate-200 bg-white p-8">
-          <h2 class="text-2xl font-bold text-night-950">Обратные расчёты</h2>
-          <p class="mt-4 text-sm leading-relaxed text-slate-700">
-            Для калибровки расчётов по фактическим данным отработки месторождения в программном
-            комплексе реализовано проведение обратных расчётов, которые позволяют извлечь практически
-            ценную геомеханическую информацию из фактов происшедших вывалов — данные о сцеплении и
-            угле внутреннего трения по поверхностям ослабления породного массива.
-          </p>
-        </div>
-        <div class="rounded-2xl border border-slate-200 bg-white p-8">
-          <h2 class="text-2xl font-bold text-night-950">Результаты для инженерных решений</h2>
-          <p class="mt-4 text-sm leading-relaxed text-slate-700">
-            Кинематическая Карта Карьера представима в виде 3D-каркаса карьера, стереограммы или
-            таблицы по секторам ориентации откосов. Предусмотрена автоматическая субдоменизация
-            карьера по устойчивости и определение мер реагирования на прогнозируемые обрушения по
-            заданной матрице рисков. Реализован эмпирический анализ на основе рейтинговых
-            классификаций Q-Slope, SMR, MRMR и оценка предельного устойчивого генерального угла
-            борта по методикам Фисенко и Хука. При расчётах учитывается криволинейность борта в
-            плане.
-          </p>
-        </div>
-      </div>
-    </div>
-  </section>
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
-      <div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
-        {gallery.map((src) => (
-          <img src={src} alt="Digger Slope — кинематическая карта карьера" class="aspect-[4/3] w-full rounded-xl border border-slate-200 object-cover" loading="lazy" />
-        ))}
-      </div>
-
-      <h2 class="mt-14 text-2xl font-bold text-night-950">Демонстрационные материалы</h2>
-      <ul class="mt-5 grid gap-3 sm:grid-cols-2">
-        {docs.map((d) => (
-          <li>
-            <a href={d.href} target="_blank" rel="noopener" class="flex items-center gap-3 rounded-xl border border-slate-200 p-4 text-sm font-medium text-night-900 transition-colors hover:border-accent-400 hover:bg-accent-50">
-              <svg class="h-5 w-5 shrink-0 text-accent-500" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-                <path d="M10.75 2.75a.75.75 0 00-1.5 0v8.614L6.295 8.235a.75.75 0 10-1.09 1.03l4.25 4.5a.75.75 0 001.09 0l4.25-4.5a.75.75 0 00-1.09-1.03l-2.955 3.129V2.75z" />
-                <path d="M3.5 12.75a.75.75 0 00-1.5 0v2.5A2.75 2.75 0 004.75 18h10.5A2.75 2.75 0 0018 15.25v-2.5a.75.75 0 00-1.5 0v2.5c0 .69-.56 1.25-1.25 1.25H4.75c-.69 0-1.25-.56-1.25-1.25v-2.5z" />
-              </svg>
-              {d.title}
-            </a>
-          </li>
-        ))}
-      </ul>
-
-      <div class="mt-12 rounded-2xl bg-slate-50 p-6 text-sm leading-relaxed text-slate-700">
-        <strong class="font-semibold text-night-950">Системные требования:</strong>
-        Операционная система — Windows 11, 10, 7 · Частота процессора — не ниже 2 GHz · Объём
-        оперативной памяти — не менее 4 Gb · Свободное место на диске — не менее 1 Gb · Разрешение
-        экрана — не менее 1024×768.
-      </div>
-    </div>
-  </section>
-
-  <CTAForm
-    title="Для заказа демо-версии, пожалуйста, заполните форму"
-    subtitle="Мы свяжемся с вами и организуем демонстрацию программного комплекса Digger Slope."
-  />
-</Base>
+<DiggerPage locale="en" />

+ 2 - 32
src/pages/diggerslope_updates.astro

@@ -1,35 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import PageHero from "../components/PageHero.astro";
-import { diggerReleases } from "../data/digger-updates";
+import DiggerslopeUpdatesPage from "../components/pages/DiggerslopeUpdatesPage.astro";
 ---
 
-<Base title="Обновления Digger Slope" description="История обновлений программного комплекса Digger Slope">
-  <PageHero title="Обновления Digger Slope" subtitle="История изменений программного комплекса Digger Slope" />
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
-      {diggerReleases.map((r) => (
-        <article class="rounded-2xl border border-slate-200 p-8">
-          <header class="flex flex-wrap items-baseline justify-between gap-2 border-b border-slate-200 pb-5">
-            <h2 class="text-2xl font-bold text-night-950">Release {r.version}</h2>
-            <time class="text-sm font-medium text-slate-500">{r.date}</time>
-          </header>
-          {r.sections.map((s) => (
-            <div class="mt-7">
-              <h3 class="text-lg font-semibold text-accent-600">{s.title}</h3>
-              <ul class="mt-3 space-y-2.5">
-                {s.items.map((item) => (
-                  <li class="flex gap-3 text-sm leading-relaxed text-slate-700">
-                    <span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
-                    {item}
-                  </li>
-                ))}
-              </ul>
-            </div>
-          ))}
-        </article>
-      ))}
-    </div>
-  </section>
-</Base>
+<DiggerslopeUpdatesPage locale="en" />

+ 2 - 104
src/pages/education.astro

@@ -1,107 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import PageHero from "../components/PageHero.astro";
-import { site } from "../data/site";
-
-const docs = [
-  ["Устав организации", "6a941e28dfb5"],
-  ["Об утверждении локальных нормативных актов по организации и осуществлению образовательной деятельности по дополнительным профессиональным программам", "ccb8f9a9ee7e"],
-  ["Положение об образовательной деятельности", "493c011f8e72"],
-  ["Правила приема обучающихся", "e4acecb8c65c"],
-  ["Положение о режиме занятий", "a2aa79f58d92"],
-  ["Положение о контроле", "fa6b65f46d20"],
-  ["Положение о переводе", "6776c55b9f29"],
-  ["Положение об образовательных отношениях", "b7f876c117a6"],
-  ["Дополнительная профессиональная программа повышения квалификации", "6139a79df404"],
-].map(([title, hash]) => ({ title, href: `https://files.scientia.ru/public/${hash}` }));
+import EducationPage from "../components/pages/EducationPage.astro";
 ---
 
-<Base title="Сведения об образовательной организации" description="Сведения об образовательной организации ООО «Скиентия»">
-  <PageHero title="Сведения об образовательной организации" />
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-4xl space-y-10 px-4 py-16 sm:px-6">
-      <div class="rounded-2xl border border-slate-200 p-8">
-        <h2 class="text-2xl font-bold text-night-950">Основные сведения</h2>
-        <dl class="mt-5 divide-y divide-slate-100">
-          {[
-            ["Полное наименование организации", `Общество с ограниченной ответственностью «Скиентия» (ИНН ${site.inn}, ОГРН ${site.ogrn})`],
-            ["Краткое наименование организации", 'ООО "Скиентия"'],
-            ["Дата создания организации", "18 января 2023 года"],
-            ["Место нахождения организации", site.address],
-            ["Контактные телефоны организации", site.phone],
-            ["Адрес электронной почты организации", site.email],
-          ].map(([k, v]) => (
-            <div class="grid gap-1 py-3.5 sm:grid-cols-3 sm:gap-6">
-              <dt class="text-sm font-medium text-slate-500">{k}</dt>
-              <dd class="text-sm font-medium text-night-950 sm:col-span-2">{v}</dd>
-            </div>
-          ))}
-        </dl>
-      </div>
-
-      <div class="rounded-2xl border border-slate-200 p-8">
-        <h2 class="text-2xl font-bold text-night-950">Документы</h2>
-        <ul class="mt-5 grid gap-3">
-          {docs.map((d) => (
-            <li>
-              <a href={d.href} target="_blank" rel="noopener" class="flex items-center gap-3 rounded-xl border border-slate-200 p-4 text-sm font-medium text-night-900 transition-colors hover:border-accent-400 hover:bg-accent-50">
-                <svg class="h-5 w-5 shrink-0 text-accent-500" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-                  <path d="M3 3.5A1.5 1.5 0 014.5 2h6.879a1.5 1.5 0 011.06.44l4.122 4.12A1.5 1.5 0 0117 7.622V16.5a1.5 1.5 0 01-1.5 1.5h-11A1.5 1.5 0 013 16.5v-13z" />
-                </svg>
-                {d.title}
-              </a>
-            </li>
-          ))}
-        </ul>
-      </div>
-
-      <div class="rounded-2xl border border-slate-200 p-8">
-        <h2 class="text-2xl font-bold text-night-950">Образование</h2>
-        <div class="mt-4 space-y-4 text-sm leading-relaxed text-slate-700">
-          <p>
-            ООО «Скиентия» реализует дополнительную профессиональную программу повышения
-            квалификации <strong>«ГЕОМЕХАНИКА И ОСНОВЫ ГИДРОГЕОЛОГИИ»</strong>. Учебный процесс
-            осуществляется в течение всего календарного года, обучение ведётся на русском языке.
-          </p>
-          <p>
-            Обучение проводится по заочной форме обучения. При реализации образовательной программы
-            используются электронное обучение и дистанционные образовательные технологии. Целью
-            программы является совершенствование компетенций в области геомеханики и гидрогеологии, в
-            том числе в области механики горных пород, сыпучих и структурно-неоднородных сред,
-            необходимых для профессиональной деятельности обучающихся, и повышение профессионального
-            уровня в рамках имеющейся квалификации.
-          </p>
-          <p>
-            Программа рассчитана на руководителей и специалистов горнодобывающих предприятий,
-            занимающихся обеспечением безопасности ведения горных работ — служба главного геотехника
-            предприятия, служба прогнозирования и предупреждения горных ударов,
-            специалисты-геомеханики.
-          </p>
-          <p><strong>Выдаваемый документ:</strong> удостоверение о повышении квалификации установленного образца.</p>
-        </div>
-      </div>
-
-      <div class="rounded-2xl border border-slate-200 p-8">
-        <h2 class="text-2xl font-bold text-night-950">Места осуществления образовательной деятельности</h2>
-        <ol class="mt-4 list-decimal space-y-2 pl-5 text-sm leading-relaxed text-slate-700">
-          <li>По адресу места нахождения образовательной организации: {site.address}</li>
-          <li>С применением электронного обучения и дистанционных образовательных технологий — посредством информационно-телекоммуникационной сети «Интернет»</li>
-        </ol>
-      </div>
-
-      <div class="rounded-2xl bg-night-900 p-8 text-white">
-        <h2 class="text-2xl font-bold">Портал дистанционного обучения</h2>
-        <p class="mt-3 text-slate-300">Обучение проводится на нашем образовательном портале.</p>
-        <a
-          href={site.external.education}
-          target="_blank"
-          rel="noopener"
-          class="mt-5 inline-block rounded-lg bg-accent-300 px-6 py-3 font-semibold text-night-950 transition-colors hover:bg-accent-400"
-        >
-          Перейти на портал ↗
-        </a>
-      </div>
-    </div>
-  </section>
-</Base>
+<EducationPage locale="en" />

+ 2 - 65
src/pages/emergency_care.astro

@@ -1,68 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import PageHero from "../components/PageHero.astro";
-import { site } from "../data/site";
-
-const steps = [
-  { n: 1, text: "Предоставляем коммерческое предложение", time: "день обращения" },
-  { n: 2, text: "Наши специалисты выезжают на объект по гарантийному письму (после проверки контрагента)", time: "2–3 д." },
-  { n: 3, text: "Запуск мониторинга автоматизированными мобильными экстензометрами NUR", time: "3–4 д.", href: "/nur" },
-  { n: 4, text: "Проводим геомеханическое обследование деформации, заполняем паспорт деформации", time: "3–4 д." },
-  { n: 5, text: "Определяем потенциальные причины деформации и находим пробелы в изученности деформирующегося участка", time: "3–4 д." },
-  { n: 6, text: "Проводим дополнительные полевые исследования", time: "3–5 д." },
-  { n: 7, text: "Совместно с заказчиком проводим ВКС с нашими опытными специалистами по выработке мер реагирования, разрабатываем меры по минимизации последствий потенциального обрушения", time: "4–5 д." },
-  { n: 8, text: "Составление прогноза развития деформационного процесса. Обоснование критических параметров деформации", time: "4–5 д." },
-  { n: 9, text: "Составление итоговой записки с описанием пп. 2–8", time: "2 нед." },
-  { n: 10, text: "Сопровождение мониторинга: настройка оповещений по превышению критических параметров, прогнозирование времени обрушения, отчётность о динамике деформационного процесса, предоставление онлайн-доступа к графикам смещений и скоростей", time: "полгода" },
-];
+import EmergencyCarePage from "../components/pages/EmergencyCarePage.astro";
 ---
 
-<Base
-  title="Скорая геотехническая помощь"
-  description="Быстрый запуск непрерывного мониторинга потенциальных обрушений на карьерах и отвалах с выработкой рекомендаций по мерам реагирования"
->
-  <PageHero
-    title="Скорая геотехническая помощь"
-    subtitle="Быстрый запуск непрерывного мониторинга потенциальных обрушений на карьерах и отвалах с выработкой рекомендаций по мерам реагирования. Возьмём под контроль обнаруженные вами заколы на бортах карьеров и на отвалах. В кратчайшие сроки"
-    image="/images/0c243b47-f913-4e05-8.jpeg"
-  />
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
-      <h2 class="text-3xl font-bold tracking-tight text-night-950">Как мы работаем</h2>
-      <ol class="mt-10 space-y-0">
-        {steps.map((s) => (
-          <li class="relative flex gap-5 pb-8 last:pb-0">
-            {s.n !== steps.length && <span class="absolute left-5 top-12 h-full w-px bg-slate-200" aria-hidden="true" />}
-            <span class="z-10 flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-accent-300 font-bold text-night-950">{s.n}</span>
-            <div class="flex-1 rounded-2xl border border-slate-200 p-5">
-              <p class="text-sm leading-relaxed text-slate-700">
-                {s.text}
-                {s.href && (
-                  <a href={s.href} class="font-medium text-accent-600 hover:text-accent-700"> (подробнее об экстензометре)</a>
-                )}
-              </p>
-              <span class="mt-2 inline-block rounded-full bg-slate-100 px-3 py-1 text-xs font-semibold text-slate-500">{s.time}</span>
-            </div>
-          </li>
-        ))}
-      </ol>
-
-      <div class="mt-12 rounded-2xl bg-slate-50 p-6 text-sm leading-relaxed text-slate-700">
-        <strong class="font-semibold text-night-950">Примечания:</strong>
-        Предоставление услуги возможно только в случае наличия у нас экстензометров, наличия
-        мобильной связи на объекте и возможности установки экстензометра для мониторинга деформации.
-        Услуга включает установку одного экстензометра и полгода мониторинга им.
-      </div>
-
-      <div class="mt-10 rounded-2xl bg-night-900 p-8 text-white">
-        <h2 class="text-2xl font-bold">Чтобы получить данную услугу как можно быстрее, звоните</h2>
-        <div class="mt-5 flex flex-wrap gap-x-10 gap-y-3">
-          <a href="tel:+79222032460" class="text-2xl font-bold text-accent-300 hover:text-accent-200">{site.phone}</a>
-          <a href="tel:+79826356310" class="text-2xl font-bold text-accent-300 hover:text-accent-200">+7 (982) 635-63-10</a>
-        </div>
-        <p class="mt-2 text-sm text-slate-400">(Россия, Казахстан, Узбекистан)</p>
-      </div>
-    </div>
-  </section>
-</Base>
+<EmergencyCarePage locale="en" />

+ 2 - 113
src/pages/geodesy.astro

@@ -1,116 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import PageHero from "../components/PageHero.astro";
-
-const directions = [
-  {
-    title: "Воздушное лазерное сканирование",
-    points: [
-      "Получение детализированного облака точек с последующим построением трехмерной модели местности и цифровой модели рельефа",
-      "Измерение скрытых или труднодоступных участков, включая зону растительности и отвалы",
-      "Использование лазерных сканнеров для контроля деформаций и раннего выявления потенциальных оползней",
-    ],
-  },
-  {
-    title: "Геодезический мониторинг",
-    points: [
-      "Постоянное или периодическое наблюдение за подвижками и деформациями зданий, сооружений, бортов карьеров",
-      "Использование высокоточных инструментальных методов",
-      "Мониторинг осадок и кренов в реальном времени для своевременного выявления и предотвращения аварийных ситуаций",
-      "Анализ полученных данных для корректировки проектных решений с учётом геомеханических факторов",
-    ],
-  },
-  {
-    title: "Маркшейдерские работы",
-    points: [
-      "Определение запасов и объёмов добытых горных пород",
-      "Подготовка маркшейдерской документации в соответствии с требованиями Ростехнадзора",
-      "Мониторинг динамики горных выработок и оценка рисков обрушений",
-    ],
-  },
-  {
-    title: "Топографические и геодезические изыскания",
-    points: [
-      "Съёмка и построение топопланов для планирования и проектирования",
-      "Создание планово-высотного обоснования (ПВО)",
-      "Контроль смещений сооружений и деформации бортов карьеров",
-    ],
-  },
-  {
-    title: "Аэрофотосъёмка",
-    points: [
-      "Съёмка крупной площади за короткие сроки",
-      "Построение ортофотопланов и 3D-моделей для точного анализа рельефа, построения карт и топопланов, а также подсчёта объёмов",
-      "Повышенная точность при планировании горно-технических мероприятий и рекультивационных работ",
-    ],
-  },
-  {
-    title: "Наземная фотограмметрия",
-    points: [
-      "Высокодетализированная съемка отдельных объектов, откосов карьера, строительных конструкций и прочее",
-      "Объединение данных наземной и воздушной съёмки для более полной картины",
-    ],
-  },
-];
-
-const gallery = ["/images/3.jpg", "/images/4.jpg", "/images/5.jpg", "/images/1-2ab29z.jpg", "/images/6.JPG", "/images/PXL_20240515_0620422-fsrmkv.jpg"];
+import GeodesyPage from "../components/pages/GeodesyPage.astro";
 ---
 
-<Base
-  title="Геодезические работы"
-  description="Наблюдения за деформацией и геодезический мониторинг борта карьеров, проектирование геодезических и строительных работ. Воздушное лазерное сканирование, инженерно геодезические изыскания, маркшейдерское обеспечение горных работ"
->
-  <PageHero
-    title="Геодезические работы"
-    subtitle="Комплекс работ по топографии, геодезии и маркшейдерскому сопровождению, включая воздушное лазерное сканирование (ВЛС), аэрофотосъёмку, наземную фотограмметрию"
-    image="/images/PXL_20240515_0620422.jpg"
-  />
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
-      <p class="max-w-4xl text-lg leading-relaxed text-slate-700">
-        Мы специализируемся на создании высокоточных цифровых моделей рельефа и анализе
-        геопространственных данных, что особенно актуально в горном деле, строительстве,
-        проектировании и мониторинге.
-      </p>
-      <h2 class="mt-12 text-3xl font-bold tracking-tight text-night-950">Ключевые направления</h2>
-      <div class="mt-8 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
-        {directions.map((d) => (
-          <div class="rounded-2xl border border-slate-200 p-6">
-            <h3 class="text-lg font-semibold text-night-950">{d.title}</h3>
-            <ul class="mt-4 space-y-2.5">
-              {d.points.map((p) => (
-                <li class="flex gap-2.5 text-sm leading-relaxed text-slate-600">
-                  <span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
-                  {p}
-                </li>
-              ))}
-            </ul>
-          </div>
-        ))}
-      </div>
-    </div>
-  </section>
-
-  <section class="bg-slate-50">
-    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
-      <h2 class="text-3xl font-bold tracking-tight text-night-950">Реальные примеры применения</h2>
-      <div class="mt-8 grid gap-6 lg:grid-cols-2">
-        <div class="rounded-2xl border border-slate-200 bg-white p-8 text-sm leading-relaxed text-slate-700">
-          Маркшейдерское сопровождение на одном из рудных месторождений Свердловской области
-          позволило урегулировать споры между пользователем недр и подрядчиком по вскрышным работам.
-        </div>
-        <div class="rounded-2xl border border-slate-200 bg-white p-8 text-sm leading-relaxed text-slate-700">
-          Регулярное воздушное лазерное сканирование рекультивируемого угольного карьера в
-          Челябинской области позволяет анализировать в камеральном режиме все протекающие деформации
-          на значительной площади (более 700 Га).
-        </div>
-      </div>
-      <div class="mt-10 grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-6">
-        {gallery.map((src) => (
-          <img src={src} alt="Геодезические работы — полевые съёмки" class="aspect-square w-full rounded-xl border border-slate-200 object-cover" loading="lazy" />
-        ))}
-      </div>
-    </div>
-  </section>
-</Base>
+<GeodesyPage locale="en" />

+ 2 - 240
src/pages/index.astro

@@ -1,243 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import CTAForm from "../components/CTAForm.astro";
-import TelegramWidget from "../components/TelegramWidget.astro";
-import { services } from "../data/services";
-import { products } from "../data/products";
-import { site } from "../data/site";
-
-const whyUs = [
-  {
-    title: "Разработки",
-    text: "Собственные программные и аппаратные решения позволяют решать задачи, которые другие считают невозможными. В команде работают не только инженеры, но и программисты.",
-  },
-  {
-    title: "Инновации",
-    text: "Регулярно тестируем и внедряем технические новшества, что поддерживает актуальность наших услуг.",
-  },
-  {
-    title: "Открытость",
-    text: "В отчётах подробно описываются все параметры, решения и допущения. Клиенты получают развёрнутые консультации.",
-  },
-  {
-    title: "Эффективность",
-    text: "Важна не только безопасность, но и экономика решений. Поиск потенциала для экономии — одна из задач геомеханика.",
-  },
-];
-
-// Client logos, arranged checkerboard: heavy dark logos alternate with light ones.
-// `big` — logos with lots of internal whitespace, render larger to match the others optically
-const clients = [
-  { file: "___1.png" },                         // УГМК — heavy
-  { file: "unnamed.jpg", big: true },           // Атлас Майнинг — light
-  { file: "c5aa9760-2920-4b4d-b.png" },         // ВНИМИ — heavy
-  { file: "29595058_20159791717.jpg", big: true }, // Норникель — light
-  { file: "9f97a370e8530d40a0ff.jpg" },         // РМК — heavy
-  { file: "_2.jpg" },                           // Полюс — light
-  { file: "evraz.jpg" },                        // Евраз — medium
-  { file: "17304586690.jpg", big: true },       // УГХ — light
-  { file: "photo-610z4l.jpg" },                 // Алроса — medium
-].map((c) => ({ ...c, src: "/images/" + c.file }));
+import HomePage from "../components/pages/HomePage.astro";
 ---
 
-<Base
-  title="Геомеханическое моделирование и ПО. Горная геомеханика — Scientia"
-  description="Институт геомеханики оценивает геомеханические риски, ведёт геотехнический мониторинг, кинематический анализ, расчет прочности и устойчивости горных работ, мониторинг бортов карьера, инженерно геологическая съемка, геомеханическая модель"
->
-  <!-- Cinematic full-viewport hero -->
-  <section class="relative flex h-[100svh] min-h-[640px] items-end overflow-hidden bg-night-950 text-white">
-    <img
-      src="/images/1655676643_10-kartin.jpg"
-      alt=""
-      class="absolute inset-0 h-full w-full object-cover"
-      loading="eager"
-    />
-    <div class="absolute inset-0 bg-gradient-to-t from-black/80 via-black/25 to-black/40"></div>
-
-    <div class="relative mx-auto w-full max-w-[1400px] px-5 pb-28 sm:px-8">
-      <p class="text-xs font-semibold uppercase tracking-[0.25em] text-accent-300">{site.tagline}</p>
-      <h1 class="display mt-5 max-w-4xl text-5xl sm:text-7xl lg:text-8xl">
-        Разработки, инновации и&nbsp;открытость<span class="dot">.</span>
-      </h1>
-      <p class="mt-6 max-w-xl text-lg leading-relaxed text-white/75">
-        Для эффективности горной промышленности: комплексные геомеханические исследования,
-        собственное ПО и аппаратура.
-      </p>
-      <div class="mt-9 flex flex-wrap items-center gap-4">
-        <a
-          href="#razrabotki"
-          class="group flex items-center gap-3 rounded-full bg-accent-300 py-3.5 pl-7 pr-4 font-semibold text-night-950 transition-colors hover:bg-accent-200"
-        >
-          Наши разработки
-          <span class="flex h-8 w-8 items-center justify-center rounded-full bg-night-950 text-accent-300" aria-hidden="true">→</span>
-        </a>
-        <a
-          href="#uslugi"
-          class="rounded-full border border-white/40 px-7 py-3.5 font-semibold text-white transition-colors hover:border-white hover:bg-white/10"
-        >
-          Услуги
-        </a>
-      </div>
-    </div>
-
-    <!-- Telegram news window (right side) -->
-    <div class="absolute bottom-24 right-20 z-10 hidden xl:block">
-      <TelegramWidget />
-    </div>
-
-    <!-- Scroll indicator -->
-    <a
-      href="#uslugi"
-      class="absolute bottom-6 left-1/2 -translate-x-1/2 text-white/70 transition-colors hover:text-white"
-      aria-label="Листайте вниз"
-    >
-      <svg class="h-7 w-7 animate-bounce" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true">
-        <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
-      </svg>
-    </a>
-  </section>
-
-  <!-- Services — Rocscience-style section header + card deck -->
-  <section id="uslugi" class="scroll-mt-20 bg-white">
-    <div class="mx-auto max-w-[1400px] px-5 py-24 sm:px-8 lg:py-32">
-      <div class="flex flex-wrap items-end justify-between gap-6">
-        <h2 class="display text-5xl sm:text-6xl">Услуги<span class="dot">.</span></h2>
-        <p class="max-w-md text-slate-500">
-          Полный цикл: от структурно-геологического картирования до мониторинга деформаций
-          и аналитических исследований.
-        </p>
-      </div>
-
-      <div class="mt-14 grid gap-x-8 gap-y-14 sm:grid-cols-2 lg:grid-cols-4">
-        {services.map((s) => (
-          <a
-            href={s.href ?? (s.external ? s.href : "#contacts")}
-            class="group block"
-            {...s.external ? { target: "_blank", rel: "noopener" } : {}}
-          >
-            <div class="relative aspect-[4/3] overflow-hidden">
-              <img
-                src={s.image}
-                alt={s.title}
-                class="h-full w-full object-cover transition-transform duration-700 group-hover:scale-105"
-                loading="lazy"
-              />
-              {"tag" in s && s.tag && (
-                <span class="absolute left-4 top-4 bg-accent-300 px-2.5 py-1 text-xs font-bold text-night-950">{s.tag}</span>
-              )}
-            </div>
-            <div class="mt-5">
-              <h3 class="display text-2xl">{s.title}</h3>
-              {s.items && (
-                <p class="mt-2 line-clamp-2 text-sm leading-relaxed text-slate-500">{s.items[0]}</p>
-              )}
-              {s.description && (
-                <p class="mt-2 line-clamp-2 text-sm leading-relaxed text-slate-500">{s.description}</p>
-              )}
-            </div>
-          </a>
-        ))}
-      </div>
-    </div>
-  </section>
-
-  <!-- Products — Porsche-style full-bleed stages -->
-  <section id="razrabotki" class="scroll-mt-20 bg-night-950 text-white">
-    {products.map((p) => (
-      <a href={p.href} class="group relative block h-[82svh] min-h-[560px] overflow-hidden border-t border-white/10">
-        <img
-          src={p.image}
-          alt={p.name}
-          class="absolute inset-0 h-full w-full object-cover opacity-80 transition-all duration-700 group-hover:scale-[1.03] group-hover:opacity-100"
-          loading="lazy"
-        />
-        <div class="absolute inset-0 bg-gradient-to-t from-black/85 via-black/20 to-black/30"></div>
-        <div class="relative mx-auto flex h-full max-w-[1400px] items-end px-5 pb-16 sm:px-8">
-          <div class="w-full">
-            <p class="text-xs font-semibold uppercase tracking-[0.25em] text-accent-300">{p.tagline}</p>
-            <div class="mt-3 flex flex-wrap items-end justify-between gap-6">
-              <div class="max-w-2xl">
-                <h3 class="display text-5xl sm:text-6xl lg:text-7xl">{p.name}<span class="dot">.</span></h3>
-                <p class="mt-4 max-w-xl text-white/75">{p.description}</p>
-              </div>
-              <span class="chip-arrow" aria-hidden="true">
-                <svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
-                  <path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5L21 12l-7.5 7.5M21 12H3" />
-                </svg>
-              </span>
-            </div>
-          </div>
-        </div>
-      </a>
-    ))}
-  </section>
-
-  <!-- Why us — editorial dark numbers -->
-  <section class="bg-white">
-    <div class="mx-auto max-w-[1400px] px-5 py-24 sm:px-8 lg:py-32">
-      <h2 class="display max-w-3xl text-5xl sm:text-6xl">
-        Почему выбирают нас<span class="dot">.</span>
-      </h2>
-
-      <!-- Client logos -->
-      <div class="mt-12">
-        <div class="grid grid-cols-2 items-center justify-items-center gap-x-10 gap-y-8 sm:grid-cols-3">
-          {clients.map((c) => (
-            <span class="flex h-36 w-full items-center justify-center">
-              <img
-                src={c.src}
-                alt="Логотип заказчика"
-                class:list={["w-auto object-contain", c.big ? "max-h-36 max-w-[300px]" : "max-h-24 max-w-[220px]"]}
-                loading="lazy"
-              />
-            </span>
-          ))}
-        </div>
-      </div>
-
-      <div class="mt-16 grid gap-x-8 gap-y-12 sm:grid-cols-2 lg:grid-cols-4">
-        {whyUs.map((w, i) => (
-          <div class="border-t-2 border-night-950 pt-6">
-            <span class="display text-6xl text-accent-300">{String(i + 1).padStart(2, "0")}</span>
-            <h3 class="display mt-4 text-2xl">{w.title}</h3>
-            <p class="mt-3 text-sm leading-relaxed text-slate-500">{w.text}</p>
-          </div>
-        ))}
-      </div>
-    </div>
-  </section>
-
-  <!-- Community — Porsche-style tiles -->
-  <section class="bg-night-950 text-white">
-    <div class="mx-auto grid max-w-[1400px] gap-px px-0 sm:grid-cols-2">
-      <a href="https://t.me/scientia_ru" target="_blank" rel="noopener" class="group relative block min-h-[420px] overflow-hidden">
-        <img src="/images/20200629_141121.jpg" alt="" class="absolute inset-0 h-full w-full object-cover opacity-40 transition-all duration-700 group-hover:scale-[1.03] group-hover:opacity-60" loading="lazy" />
-        <div class="absolute inset-0 bg-gradient-to-t from-black/85 to-transparent"></div>
-        <div class="relative flex h-full flex-col justify-end p-10">
-          <h3 class="display text-4xl">Телеграм-канал<span class="dot">.</span></h3>
-          <p class="mt-3 max-w-sm text-white/70">Новости, открытия и рекомендации — делимся в канале компании</p>
-          <span class="chip-arrow mt-8" aria-hidden="true">
-            <svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
-              <path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5L21 12l-7.5 7.5M21 12H3" />
-            </svg>
-          </span>
-        </div>
-      </a>
-      <a href={site.external.blog} target="_blank" rel="noopener" class="group relative block min-h-[420px] overflow-hidden border-l border-white/10">
-        <img src="/images/photo_2022-09-19_06-.jpg" alt="" class="absolute inset-0 h-full w-full object-cover opacity-40 transition-all duration-700 group-hover:scale-[1.03] group-hover:opacity-60" loading="lazy" />
-        <div class="absolute inset-0 bg-gradient-to-t from-black/85 to-transparent"></div>
-        <div class="relative flex h-full flex-col justify-end p-10">
-          <h3 class="display text-4xl">Блог<span class="dot">.</span></h3>
-          <p class="mt-3 max-w-sm text-white/70">Последние записи и статьи — на платформе Teletype</p>
-          <span class="chip-arrow mt-8" aria-hidden="true">
-            <svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
-              <path stroke-linecap="round" stroke-linejoin="round" d="M13.5 4.5L21 12l-7.5 7.5M21 12H3" />
-            </svg>
-          </span>
-        </div>
-      </a>
-    </div>
-  </section>
-
-  <CTAForm />
-</Base>
+<HomePage locale="en" />

+ 2 - 64
src/pages/joint_explorer.astro

@@ -1,67 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import PageHero from "../components/PageHero.astro";
-import CTAForm from "../components/CTAForm.astro";
-import { site } from "../data/site";
-
-const gallery = [
-  "/images/IMG_20230712_205454.jpg",
-  "/images/IMG_20230712_205500.jpg",
-  "/images/IMG_20230712_205505.jpg",
-  "/images/IMG_20230712_205512.jpg",
-  "/images/IMG_20230712_205533.jpg",
-  "/images/IMG_20230712_205542.jpg",
-  "/images/IMG_20230712_205551.jpg",
-  "/images/IMG_20230712_205557.jpg",
-  "/images/IMG_20230712_205602.jpg",
-  "/images/IMG_20230712_205615.jpg",
-];
+import JointExplorerPage from "../components/pages/JointExplorerPage.astro";
 ---
 
-<Base
-  title="Joint Explorer"
-  description="Электронный горный компас для определения азимутов и углов падения трещиноватости и тектонических нарушений"
->
-  <PageHero
-    title="Joint Explorer"
-    subtitle="Электронный горный компас, предназначенный для определения азимутов и углов падения трещиноватости, тектонических нарушений. В отличие от аналогового компаса позволяет выполнять большее количество замеров за меньшее количество времени"
-    image="/images/photo_2022-08-25_21-.jpg"
-  />
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
-      <div class="rounded-2xl border border-slate-200 bg-slate-50 p-8">
-        <h2 class="text-2xl font-bold text-night-950">Программное обеспечение</h2>
-        <p class="mt-4 leading-relaxed text-slate-700">
-          Разработано специальное ПО JointExplorer для мобильных устройств, позволяющее проводить
-          предварительный полевой анализ данных, полученных с устройства, а также формировать файлы
-          экспорта в виде таблиц по каждой точке съемки.
-        </p>
-        <a
-          href={`https://t.me/${site.telegram.find((t) => t.href.includes("jointexplorer"))?.href.split("/").pop() ?? "jointexplorer"}`}
-          target="_blank"
-          rel="noopener"
-          class="mt-5 inline-block rounded-lg bg-accent-300 px-5 py-2.5 text-sm font-semibold text-night-950 transition-colors hover:bg-accent-400"
-        >
-          Телеграм-канал Joint Explorer ↗
-        </a>
-      </div>
-    </div>
-  </section>
-
-  <section class="bg-slate-50">
-    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
-      <h2 class="text-3xl font-bold tracking-tight text-night-950">Прибор в работе</h2>
-      <div class="mt-8 columns-2 gap-4 sm:columns-3 lg:columns-5 [&>img]:mb-4">
-        {gallery.map((src) => (
-          <img src={src} alt="Joint Explorer — полевые замеры" class="w-full rounded-xl border border-slate-200" loading="lazy" />
-        ))}
-      </div>
-    </div>
-  </section>
-
-  <CTAForm
-    title="По всем вопросам или предложениям"
-    subtitle={`Просьба писать на почту ${site.email} или заполнить форму, представленную ниже.`}
-  />
-</Base>
+<JointExplorerPage locale="en" />

+ 2 - 100
src/pages/magicore.astro

@@ -1,103 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import PageHero from "../components/PageHero.astro";
-import CTAForm from "../components/CTAForm.astro";
-import { site } from "../data/site";
-
-const purpose = [
-  "Проверка структурного описания полевых работ",
-  "Обработка скважин без структурной документации",
-  "Обработка архивных материалов",
-];
-
-const features = [
-  "Привязывает фотографии керна по глубине",
-  "Выделяет геомеханические интервалы",
-  "Рассчитывает RQD и FF/m",
-];
-
-const steps = [
-  { n: 1, text: `Зайдите на сайт ${site.external.magicoreApp}` },
-  { n: 2, text: "Загрузите изображение" },
-  { n: 3, text: "Получите документацию по вашей фотографии" },
-];
+import MagicorePage from "../components/pages/MagicorePage.astro";
 ---
 
-<Base
-  title="Magicore"
-  description="Сервис для автоматической генерации геомеханической документации керна по фотографии с применением нейросетей"
->
-  <PageHero
-    title="Magicore"
-    subtitle="Сервис для автоматической генерации геомеханической документации керна по фотографии"
-    image="/images/image.png"
-  />
-
-  <section class="bg-white">
-    <div class="mx-auto grid max-w-7xl gap-10 px-4 py-16 sm:px-6 lg:grid-cols-2">
-      <div class="rounded-2xl border border-slate-200 p-8">
-        <h2 class="text-2xl font-bold text-night-950">Предназначение</h2>
-        <ul class="mt-5 space-y-3">
-          {purpose.map((p) => (
-            <li class="flex gap-3 text-slate-700">
-              <svg class="mt-0.5 h-5 w-5 shrink-0 text-accent-500" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-                <path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z" clip-rule="evenodd" />
-              </svg>
-              {p}
-            </li>
-          ))}
-        </ul>
-      </div>
-      <div class="rounded-2xl border border-slate-200 p-8">
-        <h2 class="text-2xl font-bold text-night-950">Возможности</h2>
-        <ul class="mt-5 space-y-3">
-          {features.map((p) => (
-            <li class="flex gap-3 text-slate-700">
-              <svg class="mt-0.5 h-5 w-5 shrink-0 text-accent-500" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-                <path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z" clip-rule="evenodd" />
-              </svg>
-              {p}
-            </li>
-          ))}
-        </ul>
-      </div>
-    </div>
-  </section>
-
-  <section class="bg-slate-50">
-    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
-      <h2 class="text-3xl font-bold tracking-tight text-night-950">Использование</h2>
-      <div class="mt-8 grid gap-6 sm:grid-cols-3">
-        {steps.map((s) => (
-          <div class="rounded-2xl bg-white p-6 shadow-sm">
-            <span class="flex h-10 w-10 items-center justify-center rounded-full bg-accent-300 font-bold text-night-950">{s.n}</span>
-            <p class="mt-4 text-sm leading-relaxed text-slate-700">{s.text}</p>
-          </div>
-        ))}
-      </div>
-      <a
-        href={site.external.magicoreApp}
-        target="_blank"
-        rel="noopener"
-        class="mt-8 inline-block rounded-lg bg-accent-300 px-6 py-3 font-semibold text-night-950 transition-colors hover:bg-accent-400"
-      >
-        Попробовать Magicore ↗
-      </a>
-    </div>
-  </section>
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
-      <h2 class="text-3xl font-bold tracking-tight text-night-950">Пример геомеханической документации</h2>
-      <img src="/images/image-y390se.png" alt="Пример геомеханической документации Magicore" class="mt-8 w-full rounded-2xl border border-slate-200" loading="lazy" />
-      <p class="mt-6 text-sm text-slate-500">
-        Сервис внесён в реестр российского ПО. Реестровая запись №28251 от 19.05.2025.
-      </p>
-    </div>
-  </section>
-
-  <CTAForm
-    title={`Звоните по номеру ${site.phone}`}
-    subtitle="Мы подробно расскажем Вам о данном сервисе, проведем для Вас презентацию в формате видео-звонка."
-  />
-</Base>
+<MagicorePage locale="en" />

+ 2 - 92
src/pages/nur.astro

@@ -1,95 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import PageHero from "../components/PageHero.astro";
-
-const specs = [
-  ["Диапазон измерений", "0–40 м"],
-  ["Точность измерений (СКО)", "1 мм"],
-  ["Разрешающая способность", "1 мм"],
-  ["Частота измерений", "настраиваемая, от 1 сек⁻¹"],
-  ["Мониторинг смещений онлайн", "с задержкой в ~1 сек"],
-  ["Передача данных", "посредством GSM (планируется реализация посредством радиосвязи и др.)"],
-  ["Оповещения", "через телеграм-бот, SMS, e-mail"],
-  ["Источник автономного питания", "5 В"],
-  ["Автономность", "при подключении к солнечной панели"],
-  ["Емкость аккумулятора", "38900 mAh (144 Wh)"],
-  ["Влаго- и пылезащита", "IP65"],
-  ["Класс опасности лазера", "2"],
-];
+import NurPage from "../components/pages/NurPage.astro";
 ---
 
-<Base
-  title="Экстензометр NUR"
-  description="Прибор для автоматизированного мониторинга заколов, раскрытия трещин, конвергенции подземных выработок, контроля вывалов в откосах карьеров"
->
-  <PageHero
-    title="Экстензометр NUR"
-    subtitle="Прибор для автоматизированного мониторинга смещений, использующий лазерный датчик расстояния. Принцип работы заключается в высокочастотном измерении расстояния до отражающей поверхности и передаче данных на сервер"
-    image="/images/PXL_20240408_0840372.jpg"
-  />
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
-      <h2 class="text-3xl font-bold tracking-tight text-night-950">Характеристики</h2>
-      <dl class="mt-8 grid gap-x-10 gap-y-0 sm:grid-cols-2">
-        {specs.map(([k, v]) => (
-          <div class="flex flex-col gap-1 border-b border-slate-200 py-3.5 sm:flex-row sm:items-baseline sm:justify-between sm:gap-6">
-            <dt class="text-sm font-medium text-slate-500">{k}</dt>
-            <dd class="text-sm font-semibold text-night-950 sm:text-right">{v}</dd>
-          </div>
-        ))}
-      </dl>
-    </div>
-  </section>
-
-  <section class="bg-slate-50">
-    <div class="mx-auto grid max-w-7xl gap-8 px-4 py-16 sm:px-6 lg:grid-cols-2">
-      <div class="rounded-2xl border border-slate-200 bg-white p-8">
-        <h2 class="text-2xl font-bold text-night-950">Применение</h2>
-        <p class="mt-4 text-sm leading-relaxed text-slate-700">
-          Экстензометр NUR предназначен для мониторинга заколов, раскрытия трещин, конвергенции
-          подземных выработок, контроля вывалов в откосах карьеров, в боку и кровле подземных
-          выработок.
-        </p>
-        <p class="mt-4 text-sm leading-relaxed text-slate-700">
-          Точность измерений прибора достаточна для фиксации смещений на ранних этапах обрушений.
-          Благодаря высокой частоте измерений возможно определение скоростей смещений, что делает
-          возможность прогноза времени обрушений, оповещений по достижению критических скоростей
-          (аналогично интерферометрическим радарам).
-        </p>
-        <p class="mt-4 text-sm leading-relaxed text-slate-700">
-          На данный момент прибор был испытан на карьерах, где показал свою эффективность. Испытания
-          в подземных выработках пока не проводились.
-        </p>
-      </div>
-      <div class="space-y-8">
-        <div class="rounded-2xl border border-slate-200 bg-white p-8">
-          <h2 class="text-2xl font-bold text-night-950">Установка</h2>
-          <ul class="mt-4 space-y-3 text-sm leading-relaxed text-slate-700">
-            <li class="flex gap-3">
-              <span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
-              Прибор устанавливается на специальное крепление, обеспечивающее фиксацию и поворот на 360°
-            </li>
-            <li class="flex gap-3">
-              <span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
-              Для непрерывной и полностью автоматизированной работы подключается солнечная панель
-            </li>
-          </ul>
-          <div class="mt-6 grid grid-cols-2 gap-4">
-            <img src="/images/1-2nktvc.png" alt="Установка экстензометра NUR" class="aspect-square w-full rounded-xl object-cover" loading="lazy" />
-            <img src="/images/2.png" alt="Крепление экстензометра NUR" class="aspect-square w-full rounded-xl object-cover" loading="lazy" />
-          </div>
-        </div>
-        <div class="rounded-2xl border border-slate-200 bg-white p-8">
-          <h2 class="text-2xl font-bold text-night-950">Мониторинг</h2>
-          <p class="mt-4 text-sm leading-relaxed text-slate-700">
-            Результаты замеров экстензометром отображаются на графиках в нашем веб-сервисе.
-            Веб-сервис позволяет в режиме реального времени отображать расстояния, скорости смещений
-            и т.д. Настраиваются оповещения по превышению критических скоростей.
-          </p>
-          <img src="/images/321.jpg" alt="Графики мониторинга смещений" class="mt-6 w-full rounded-xl border border-slate-200" loading="lazy" />
-        </div>
-      </div>
-    </div>
-  </section>
-</Base>
+<NurPage locale="en" />

+ 2 - 36
src/pages/personal_data.astro

@@ -1,39 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import { policySections } from "../data/personal-data";
+import PersonalDataPage from "../components/pages/PersonalDataPage.astro";
 ---
 
-<Base title="Персональные данные" description="Политика в отношении обработки персональных данных ООО «Скиентия»">
-  <section class="bg-white">
-    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
-      <h1 class="text-3xl font-bold tracking-tight text-night-950 sm:text-4xl">
-        Политика в отношении обработки персональных данных
-      </h1>
-      <div class="mt-10 space-y-10">
-        {policySections.map((s) => (
-          <section>
-            <h2 class="text-xl font-bold text-night-950">{s.title}</h2>
-            {s.intro && <p class="mt-3 text-sm leading-relaxed text-slate-700">{s.intro}</p>}
-            {s.items && (
-              <div class="mt-3 space-y-3">
-                {s.items.map((item) => (
-                  <p class="text-sm leading-relaxed text-slate-700">{item}</p>
-                ))}
-              </div>
-            )}
-            {s.table && (
-              <dl class="mt-4 divide-y divide-slate-200 rounded-xl border border-slate-200">
-                {s.table.map(([k, v]) => (
-                  <div class="grid gap-1 p-4 sm:grid-cols-4 sm:gap-6">
-                    <dt class="text-sm font-semibold text-night-950">{k}</dt>
-                    <dd class="text-sm leading-relaxed text-slate-700 sm:col-span-3">{v}</dd>
-                  </div>
-                ))}
-              </dl>
-            )}
-          </section>
-        ))}
-      </div>
-    </div>
-  </section>
-</Base>
+<PersonalDataPage locale="en" />

+ 2 - 128
src/pages/prorock.astro

@@ -1,131 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import PageHero from "../components/PageHero.astro";
-import CTAForm from "../components/CTAForm.astro";
-
-const features = [
-  "Интерактивное задание литологии, тектонических нарушений, анкерного крепления, природных напряжений, граничных условий и внешних нагрузок",
-  "Отображение точечных данных, векторов главных напряжений, изгиба слоев",
-  "Импорт растров и DXF",
-  "Генерация системной трещиноватости (DFN)",
-  "Автопоиск ошибок и автоматическое исправление геометрии",
-  "Оптимизированная для FDEM генерация сетки",
-  "Моделирование выемки, замены свойств, выпуска",
-  "10 видов визуализации результатов",
-  "Массовая генерация скриншотов",
-  "Экспорт результатов в текстовом виде",
-];
-
-const advantages = [
-  {
-    title: "Применение",
-    items: [
-      "Оценка остаточной прочности",
-      "Расчет устойчивости бортов при подработке",
-      "Обрушения из-за структур и напряжений",
-      "Прогноз зон сдвижения, нарушенности в массиве",
-      "Образование водопроводящих трещин и пустот",
-    ],
-  },
-  {
-    title: "Преимущества",
-    items: [
-      "Один из самых быстрых FDEM-солверов в мире благодаря CUDA и оптимизации. Расчеты выполняются за минуты",
-      "Высокая реалистичность моделирования геомеханических процессов",
-      "Интерфейс программы и техническая поддержка на русском языке",
-      "Интерфейс программы будет интуитивно понятен для специалистов, работавших в аналогичных ПО",
-    ],
-  },
-];
-
-const gallery = ["/images/21.jpg", "/images/1.jpg", "/images/3.jpg", "/images/4.png"];
+import ProrockPage from "../components/pages/ProrockPage.astro";
 ---
 
-<Base
-  title="Prorock 2.0"
-  description="Новый инструмент для продвинутого численного моделирования в геомеханике. Моделирование разрушений и динамических процессов методом конечно-дискретных элементов"
->
-  <PageHero
-    title="PROROCK 2.0"
-    subtitle="Новый инструмент для продвинутого численного моделирования в геомеханике"
-    image="/images/21.jpg"
-  >
-    <a href="/prorock_updates" class="mt-6 inline-block rounded-lg bg-accent-300 px-5 py-2.5 font-semibold text-night-950 transition-colors hover:bg-accent-400">
-      История обновлений
-    </a>
-  </PageHero>
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
-      <h2 class="text-3xl font-bold tracking-tight text-night-950">Ключевые возможности</h2>
-      <ul class="mt-8 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
-        {features.map((f) => (
-          <li class="flex gap-3 rounded-xl border border-slate-200 p-4 text-sm leading-relaxed text-slate-700">
-            <svg class="mt-0.5 h-5 w-5 shrink-0 text-accent-500" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-              <path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z" clip-rule="evenodd" />
-            </svg>
-            {f}
-          </li>
-        ))}
-      </ul>
-      <p class="mt-10 max-w-4xl text-lg leading-relaxed text-slate-700">
-        Мощный математический аппарат программы позволяет моделировать деформационные процессы с
-        любыми величинами деформаций, как упругие, так и происходящие с разрывами сплошности,
-        фрагментацией и последующим смещением фрагментированных масс.
-      </p>
-    </div>
-  </section>
-
-  <section class="bg-slate-50">
-    <div class="mx-auto grid max-w-7xl gap-8 px-4 py-16 sm:px-6 lg:grid-cols-2">
-      {advantages.map((a) => (
-        <div class="rounded-2xl border border-slate-200 bg-white p-8">
-          <h2 class="text-2xl font-bold text-night-950">{a.title}</h2>
-          <ul class="mt-5 space-y-3">
-            {a.items.map((item) => (
-              <li class="flex gap-3 text-sm leading-relaxed text-slate-700">
-                <span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
-                {item}
-              </li>
-            ))}
-          </ul>
-        </div>
-      ))}
-    </div>
-  </section>
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-7xl px-4 py-16 sm:px-6">
-      <div class="grid gap-4 sm:grid-cols-2">
-        <a href="/prorockfeatures" class="rounded-2xl bg-night-900 p-8 text-white transition-colors hover:bg-night-800">
-          <h3 class="text-xl font-semibold">Ключевые особенности</h3>
-          <p class="mt-2 text-sm text-slate-300">Высокая реалистичность моделирования: явное моделирование разрушения и учёт трещиноватости массива</p>
-        </a>
-        <div class="rounded-2xl border border-slate-200 p-8">
-          <h3 class="text-xl font-semibold text-night-950">Видео</h3>
-          <ul class="mt-3 space-y-2 text-sm text-slate-600">
-            <li>Общее описание Prorock 2.0: возможности, преимущества, модули</li>
-            <li>Видеоурок по Prorock 2.0: построение модели и просмотр результатов расчётов</li>
-          </ul>
-        </div>
-      </div>
-
-      <div class="mt-12 grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
-        {gallery.map((src) => (
-          <img src={src} alt="Prorock 2.0 — пример модели" class="aspect-[4/3] w-full rounded-xl border border-slate-200 object-cover" loading="lazy" />
-        ))}
-      </div>
-
-      <div class="mt-12 rounded-2xl bg-slate-50 p-6 text-sm leading-relaxed text-slate-700">
-        <strong class="font-semibold text-night-950">Системные требования:</strong>
-        ОС: Windows 7 или более поздняя · Видеокарта: NVIDIA с поддержкой технологии CUDA
-        (видеопамять более 1 Гб) · Оперативная память: 4+ Гб · Место на диске: 1+ Гб / проект
-      </div>
-    </div>
-  </section>
-
-  <CTAForm
-    title="Если хотите узнать про Prorock больше, пожалуйста, заполните форму"
-    subtitle="Мы ответим на все вопросы и проведём демонстрацию возможностей программы."
-  />
-</Base>
+<ProrockPage locale="en" />

+ 2 - 32
src/pages/prorock_updates.astro

@@ -1,35 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import PageHero from "../components/PageHero.astro";
-import { prorockReleases } from "../data/prorock-updates";
+import ProrockUpdatesPage from "../components/pages/ProrockUpdatesPage.astro";
 ---
 
-<Base title="Обновления Prorock" description="История обновлений ПО Prorock">
-  <PageHero title="Обновления Prorock" subtitle="История изменений программного комплекса Prorock" />
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
-      {prorockReleases.map((r) => (
-        <article class="rounded-2xl border border-slate-200 p-8">
-          <header class="flex flex-wrap items-baseline justify-between gap-2 border-b border-slate-200 pb-5">
-            <h2 class="text-2xl font-bold text-night-950">Release {r.version}</h2>
-            <time class="text-sm font-medium text-slate-500">{r.date}</time>
-          </header>
-          {r.sections.map((s) => (
-            <div class="mt-7">
-              <h3 class="text-lg font-semibold text-accent-600">{s.title}</h3>
-              <ul class="mt-3 space-y-2.5">
-                {s.items.map((item) => (
-                  <li class="flex gap-3 text-sm leading-relaxed text-slate-700">
-                    <span class="mt-2 h-1.5 w-1.5 shrink-0 rounded-full bg-accent-400" aria-hidden="true" />
-                    {item}
-                  </li>
-                ))}
-              </ul>
-            </div>
-          ))}
-        </article>
-      ))}
-    </div>
-  </section>
-</Base>
+<ProrockUpdatesPage locale="en" />

+ 2 - 62
src/pages/prorockfeatures.astro

@@ -1,65 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import PageHero from "../components/PageHero.astro";
-
-const sections = [
-  {
-    title: "Высокая реалистичность моделирования",
-    body: [
-      "Математический аппарат программы позволяет, в отличие от общепринятых способов расчетов любых задач геомеханики, выполнять явное моделирование процессов разрушения горных пород: образование трещин рассчитывается в явном виде как изменение формы и исчезновение трещинных элементов. Дальнейшее взаимодействие отдельных элементов рассчитывается алгоритмами учета механических взаимодействий.",
-      "Учет трещиноватости массивов горных пород. Модель возможно заселить системами трещин любой структуры с механическими параметрами, отличными от параметров горных пород. Таким образом учитывается значительное влияние трещиноватости на геомеханические процессы, которое сложно учесть традиционными способами.",
-      "Программа PROROCK позволяет учесть стадийность образования выработок, то есть выполнять прогноз развития деформаций на каждом этапе развития горных работ.",
-      "В PROROCK можно анализировать динамические процессы, например перемещение и остановку тел обрушения.",
-    ],
-  },
-  {
-    title: "Низкая стоимость отдельного решения",
-    body: [
-      "Программа PROROCK будет распространяться по подписке, то есть пользователи будут платить за время пользования программой, а не за ее приобретение. Стоимость ее использования на порядок ниже среднего чека по договорам на выполнение геомеханических обоснований. Поэтому позволить себе воспользоваться ею смогут специалисты любых компаний, в том числе молодых и небольших.",
-      "Для выполнения расчетов используются облачные вычисления. Программа-процессор производит вычисления на облаке, благодаря чему отпадает необходимость приобретения дорогостоящих вычислительных устройств.",
-    ],
-  },
-  {
-    title: "Удобство и простота использования",
-    body: [
-      "Графический интерфейс программы PROROCK интуитивно понятнее и удобнее большинства существующих решений для численного моделирования в геомеханике.",
-      "Применение производительных графических процессоров, расположенных в облаке, позволит выполнять расчеты быстрее, чем в приложениях, работающих только на десктопе.",
-    ],
-  },
-  {
-    title: "Большая полнота выходных данных",
-    body: [
-      "Численный метод механики, лежащий в основе программы-процессора, позволяет получать данные, которые невозможно получить другими способами. В качестве примеров можно привести сведения о раскрытии трещин, о величине заколов, о размерах зоны разрушений, о безопасности подрабатываемых водных объектов и т.д.",
-    ],
-  },
-  {
-    title: "Мощный функционал для анализа результатов расчетов",
-    body: [
-      "Для удобства пользователя в программе PROROCK предусмотрены встроенные средства для построения графиков, диаграмм и множество способов отображения выходных данных. В программе PROROCK будут реализованы интуитивно понятные инструменты для генерации отчетов после выполненных расчетов, что будет сводить работу специалиста к минимуму.",
-    ],
-  },
-];
+import ProrockFeaturesPage from "../components/pages/ProrockFeaturesPage.astro";
 ---
 
-<Base title="Prorock: особенности" description="Особенности PROROCK: высокая реалистичность моделирования, низкая стоимость, удобство использования, полнота выходных данных">
-  <PageHero
-    title="Ключевые особенности"
-    subtitle="Далее описаны характеристики сервиса версии 1.0, находящегося в разработке"
-  />
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-4xl space-y-8 px-4 py-16 sm:px-6">
-      {sections.map((s, i) => (
-        <article class="rounded-2xl border border-slate-200 p-8">
-          <span class="text-sm font-bold uppercase tracking-wider text-accent-600">{String(i + 1).padStart(2, "0")}</span>
-          <h2 class="mt-2 text-2xl font-bold text-night-950">{s.title}</h2>
-          <div class="mt-4 space-y-4">
-            {s.body.map((p) => (
-              <p class="leading-relaxed text-slate-700">{p}</p>
-            ))}
-          </div>
-        </article>
-      ))}
-    </div>
-  </section>
-</Base>
+<ProrockFeaturesPage locale="en" />

+ 5 - 0
src/pages/ru/about.astro

@@ -0,0 +1,5 @@
+---
+import AboutPage from "../../components/pages/AboutPage.astro";
+---
+
+<AboutPage locale="ru" />

+ 5 - 0
src/pages/ru/digger.astro

@@ -0,0 +1,5 @@
+---
+import DiggerPage from "../../components/pages/DiggerPage.astro";
+---
+
+<DiggerPage locale="ru" />

+ 5 - 0
src/pages/ru/diggerslope_updates.astro

@@ -0,0 +1,5 @@
+---
+import DiggerslopeUpdatesPage from "../../components/pages/DiggerslopeUpdatesPage.astro";
+---
+
+<DiggerslopeUpdatesPage locale="ru" />

+ 5 - 0
src/pages/ru/education.astro

@@ -0,0 +1,5 @@
+---
+import EducationPage from "../../components/pages/EducationPage.astro";
+---
+
+<EducationPage locale="ru" />

+ 5 - 0
src/pages/ru/emergency_care.astro

@@ -0,0 +1,5 @@
+---
+import EmergencyCarePage from "../../components/pages/EmergencyCarePage.astro";
+---
+
+<EmergencyCarePage locale="ru" />

+ 5 - 0
src/pages/ru/geodesy.astro

@@ -0,0 +1,5 @@
+---
+import GeodesyPage from "../../components/pages/GeodesyPage.astro";
+---
+
+<GeodesyPage locale="ru" />

+ 5 - 0
src/pages/ru/index.astro

@@ -0,0 +1,5 @@
+---
+import HomePage from "../../components/pages/HomePage.astro";
+---
+
+<HomePage locale="ru" />

+ 5 - 0
src/pages/ru/joint_explorer.astro

@@ -0,0 +1,5 @@
+---
+import JointExplorerPage from "../../components/pages/JointExplorerPage.astro";
+---
+
+<JointExplorerPage locale="ru" />

+ 5 - 0
src/pages/ru/magicore.astro

@@ -0,0 +1,5 @@
+---
+import MagicorePage from "../../components/pages/MagicorePage.astro";
+---
+
+<MagicorePage locale="ru" />

+ 5 - 0
src/pages/ru/nur.astro

@@ -0,0 +1,5 @@
+---
+import NurPage from "../../components/pages/NurPage.astro";
+---
+
+<NurPage locale="ru" />

+ 5 - 0
src/pages/ru/personal_data.astro

@@ -0,0 +1,5 @@
+---
+import PersonalDataPage from "../../components/pages/PersonalDataPage.astro";
+---
+
+<PersonalDataPage locale="ru" />

+ 5 - 0
src/pages/ru/prorock.astro

@@ -0,0 +1,5 @@
+---
+import ProrockPage from "../../components/pages/ProrockPage.astro";
+---
+
+<ProrockPage locale="ru" />

+ 5 - 0
src/pages/ru/prorock_updates.astro

@@ -0,0 +1,5 @@
+---
+import ProrockUpdatesPage from "../../components/pages/ProrockUpdatesPage.astro";
+---
+
+<ProrockUpdatesPage locale="ru" />

+ 5 - 0
src/pages/ru/prorockfeatures.astro

@@ -0,0 +1,5 @@
+---
+import ProrockFeaturesPage from "../../components/pages/ProrockFeaturesPage.astro";
+---
+
+<ProrockFeaturesPage locale="ru" />

+ 5 - 0
src/pages/ru/scientiajoints.astro

@@ -0,0 +1,5 @@
+---
+import ScientiaJointsPage from "../../components/pages/ScientiaJointsPage.astro";
+---
+
+<ScientiaJointsPage locale="ru" />

+ 5 - 0
src/pages/ru/subscribe.astro

@@ -0,0 +1,5 @@
+---
+import SubscribePage from "../../components/pages/SubscribePage.astro";
+---
+
+<SubscribePage locale="ru" />

+ 2 - 69
src/pages/scientiajoints.astro

@@ -1,72 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import PageHero from "../components/PageHero.astro";
-
-const features = [
-  "С помощью плагина процесс картирования трещины стал гораздо нагляднее. Теперь в реальном времени можно увидеть диаграмму трещиноватости для всех измерений. Это позволит вам получать более репрезентативные данные во время съемки.",
-  "На основе фотореалистичных моделей можно собирать информацию о расстоянии между трещинами. Для этого была добавлена гистограмма распределения всех выполненных измерений, а также статистические параметры созданной выборки.",
-  "Также появилась возможность экспортировать измерения в формате CSV.",
-  "В плагине добавлены кольцевые шейдеры для улучшения визуализации модели.",
-];
+import ScientiaJointsPage from "../components/pages/ScientiaJointsPage.astro";
 ---
 
-<Base
-  title="ScientiaJoints"
-  description="Плагин для свободно распространяемого ПО Blender, предназначенный для цифрового картирования трещин на трёхмерных моделях"
->
-  <PageHero
-    title="ScientiaJoints"
-    subtitle="Плагин для свободно распространяемого ПО Blender, предназначенный для цифрового картирования трещин на трёхмерных моделях"
-    image="/images/1.jpg"
-  />
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-4xl px-4 py-16 sm:px-6">
-      <h2 class="text-3xl font-bold tracking-tight text-night-950">Возможности</h2>
-      <ul class="mt-8 space-y-5">
-        {features.map((f) => (
-          <li class="flex gap-4 leading-relaxed text-slate-700">
-            <svg class="mt-1 h-6 w-6 shrink-0 text-accent-500" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
-              <path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z" clip-rule="evenodd" />
-            </svg>
-            {f}
-          </li>
-        ))}
-      </ul>
-
-      <div class="mt-12 rounded-2xl bg-night-900 p-8 text-white">
-        <h2 class="text-2xl font-bold">Скачать бесплатно</h2>
-        <p class="mt-3 max-w-2xl text-slate-300">
-          Скачать ScientiaJoints плагин вы можете абсолютно бесплатно. В нашем телеграм-канале будут
-          появляться обновления плагина, мы оказываем помощь по его установке и использованию.
-        </p>
-        <div class="mt-6 flex flex-wrap gap-3">
-          <a
-            href="https://files.scientia.ru/public/588e8945a470"
-            target="_blank"
-            rel="noopener"
-            class="rounded-lg bg-accent-300 px-6 py-3 font-semibold text-night-950 transition-colors hover:bg-accent-400"
-          >
-            Скачать плагин
-          </a>
-          <a
-            href="https://t.me/scientia_ru"
-            target="_blank"
-            rel="noopener"
-            class="rounded-lg border border-white/25 px-6 py-3 font-semibold transition-colors hover:bg-white/10"
-          >
-            Телеграм-канал ↗
-          </a>
-        </div>
-      </div>
-
-      <div class="mt-10 rounded-2xl border border-slate-200 p-6">
-        <h3 class="font-semibold text-night-950">Гайд по установке и использованию плагина</h3>
-        <p class="mt-2 text-sm text-slate-600">
-          Инструкция доступна в телеграм-канале компании и в нашем
-          <a href="https://wiki.scientia.ru/" target="_blank" rel="noopener" class="text-accent-600 hover:text-accent-700">Wiki</a>.
-        </p>
-      </div>
-    </div>
-  </section>
-</Base>
+<ScientiaJointsPage locale="en" />

+ 2 - 64
src/pages/subscribe.astro

@@ -1,67 +1,5 @@
 ---
-import Base from "../layouts/Base.astro";
-import PageHero from "../components/PageHero.astro";
-import { site } from "../data/site";
+import SubscribePage from "../components/pages/SubscribePage.astro";
 ---
 
-<Base title="Рассылка" description="Получайте актуальные знания от экспертов-практиков и информацию о нашем программном обеспечении">
-  <PageHero
-    title="Рассылка"
-    subtitle="Получайте актуальные знания от экспертов-практиков и информацию о нашем программном обеспечении — обновления и практические кейсы"
-  />
-
-  <section class="bg-white">
-    <div class="mx-auto max-w-xl px-4 py-16 sm:px-6">
-      <!-- Static hosting: subscribe composes an email instead of posting to a backend. -->
-      <form id="subscribe-form" class="rounded-2xl border border-slate-200 p-8 shadow-sm">
-        <label class="block">
-          <span class="mb-1.5 block text-sm font-medium text-night-950">E-mail</span>
-          <input
-            required
-            type="email"
-            name="email"
-            autocomplete="email"
-            placeholder="you@company.ru"
-            class="w-full rounded-lg border border-slate-300 px-3.5 py-2.5 text-sm outline-none transition-colors focus:border-accent-400 focus:ring-2 focus:ring-accent-200"
-          />
-        </label>
-        <button
-          type="submit"
-          class="mt-5 w-full rounded-lg bg-accent-300 px-5 py-3 text-sm font-semibold text-night-950 transition-colors hover:bg-accent-400"
-        >
-          Подписаться
-        </button>
-        <p class="mt-4 text-xs leading-relaxed text-slate-500">
-          Нажимая на кнопку, вы даёте согласие на обработку персональных данных и соглашаетесь c
-          <a href="/personal_data" class="underline hover:text-night-900">политикой конфиденциальности</a>.
-        </p>
-      </form>
-
-      <div class="mt-10 rounded-2xl bg-slate-50 p-6 text-sm text-slate-700">
-        Также подписывайтесь на наши Телеграм-каналы:
-        <ul class="mt-3 space-y-1.5">
-          {site.telegram.map((t) => (
-            <li>
-              <a href={t.href} target="_blank" rel="noopener" class="font-medium text-accent-600 hover:text-accent-700">
-                {t.name} ↗
-              </a>
-            </li>
-          ))}
-        </ul>
-      </div>
-    </div>
-  </section>
-</Base>
-
-<script>
-  const form = document.getElementById("subscribe-form") as HTMLFormElement | null;
-  form?.addEventListener("submit", (e) => {
-    e.preventDefault();
-    const email = new FormData(form).get("email");
-    window.location.href =
-      "mailto:info@scientia.ru?subject=" +
-      encodeURIComponent("Подписка на рассылку scientia.ru") +
-      "&body=" +
-      encodeURIComponent("Прошу добавить в рассылку: " + email);
-  });
-</script>
+<SubscribePage locale="en" />

部分文件因为文件数量过多而无法显示