The palette lived as ~620 hex literals in inline styles plus a few hundred more in
the stylesheets, so there was no single thing to change. It is now 113 custom
properties in src/styles/theme.css, in two blocks.
src/scripts/theme-boot.js decides the theme before first paint — blocking, in <head>,
above the stylesheet, because a deferred script paints dark first and corrects itself.
It stores the mode ('system' | 'light' | 'dark'), never the colour it resolved to, and
stamps data-theme so an explicit choice can beat the media query. The switcher in the
header is a view onto it.
A filled accent stays the brand colour in both themes — the ink on it is near-black
either way — while an accent used as text darkens to clear 4.5:1 on white. A colour
reaches a fill by four routes (a style property, a constant, a helper argument, an SVG
source string), and tests/theme-switching.test.mjs covers all four.
The dark theme is unchanged: every colour declaration the previous build produced comes
out of this one identically once the properties are resolved.
Also: the roadmap drops its status chips on mobile, and Roadmap.jsx no longer splits a
colour with parseInt at runtime, which a var() reference cannot survive.
498 lines
41 KiB
HTML
498 lines
41 KiB
HTML
<!DOCTYPE html>
|
||
<!-- Generated by scripts/build-i18n.js from templates/index.template.html and
|
||
locales/*.json. Edits made here are overwritten by the next build. -->
|
||
<html lang="uk" dir="ltr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<!-- viewport-fit=cover is what makes env(safe-area-inset-*) resolve to anything
|
||
other than 0 on notched iPhones; the composer already pads for it.
|
||
interactive-widget=resizes-content is honoured by Chrome/Android; iOS
|
||
ignores it, which is why the shell also tracks visualViewport in JS. -->
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content">
|
||
<meta http-equiv="Content-Security-Policy"
|
||
content="default-src 'self';
|
||
script-src 'self';
|
||
style-src 'self' 'unsafe-inline';
|
||
font-src 'self' data:;
|
||
connect-src 'self' stun: stuns: turn: turns:;
|
||
img-src 'self' data:;
|
||
media-src 'self' blob:;
|
||
object-src 'none';
|
||
frame-src 'none';
|
||
worker-src 'self';
|
||
manifest-src 'self';
|
||
form-action 'self';
|
||
base-uri 'none';
|
||
upgrade-insecure-requests;">
|
||
<meta http-equiv="X-Content-Type-Options" content="nosniff">
|
||
<meta http-equiv="X-XSS-Protection" content="1; mode=block">
|
||
<meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin">
|
||
|
||
<!-- PWA Manifest -->
|
||
<link rel="manifest" href="/uk/manifest.json">
|
||
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1788557187846">
|
||
|
||
<!-- Blocking, and above the stylesheet on purpose: this stamps data-theme on <html>
|
||
from localStorage while the parser is still in <head>, so the page paints in the
|
||
chosen theme on the first frame instead of flashing dark and correcting itself.
|
||
Cannot be inline (CSP is script-src 'self') and cannot be a module (deferred). -->
|
||
<script src="/src/scripts/theme-boot.js?v=1788557187846"></script>
|
||
|
||
<!-- Blocking, and in <head> on purpose: beforeinstallprompt fires once and is
|
||
not replayed, so the listener has to exist before Chrome decides the page
|
||
is installable. Deferred/module scripts are already too late. -->
|
||
<script src="/src/scripts/pwa-install-capture.js?v=1788557187846"></script>
|
||
|
||
<!-- PWA Meta Tags -->
|
||
<meta name="mobile-web-app-capable" content="yes">
|
||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||
<meta name="format-detection" content="telephone=no">
|
||
<!-- "default", not "black-translucent", now that there are two themes.
|
||
black-translucent draws the clock and battery in white and lets the page run under
|
||
them; on a light page that is white on near-white, and the meta is read once at
|
||
launch so no script can correct it. With "default" iOS tints the status bar from
|
||
<meta name="theme-color"> below and picks the glyph colour to contrast with it, so
|
||
it follows the theme on its own. The trade is that the page no longer extends under
|
||
the bar, which makes env(safe-area-inset-top) 0 in standalone — src/styles/pwa.css
|
||
already derives --sb-safe-top from that env(), so it collapses to 0 and the header
|
||
sits where it does in a browser tab. -->
|
||
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
||
<meta name="apple-mobile-web-app-title" content="SecureBit">
|
||
<meta name="application-name" content="SecureBit">
|
||
<meta name="msapplication-TileColor" content="#ff6b35">
|
||
<meta name="msapplication-config" content="/browserconfig.xml">
|
||
|
||
<!-- iOS Splash Screens - Полная конфигурация с генератора -->
|
||
<!-- Landscape -->
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 440px) and (device-height: 956px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_17_Pro_Max__iPhone_16_Pro_Max_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 402px) and (device-height: 874px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_17_Pro__iPhone_17__iPhone_16_Pro_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 430px) and (device-height: 932px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_16_Plus__iPhone_15_Pro_Max__iPhone_15_Plus__iPhone_14_Pro_Max_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 420px) and (device-height: 912px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_Air_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 393px) and (device-height: 852px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_16__iPhone_15_Pro__iPhone_15__iPhone_14_Pro_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_14_Plus__iPhone_13_Pro_Max__iPhone_12_Pro_Max_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_16e__iPhone_14__iPhone_13_Pro__iPhone_13__iPhone_12_Pro__iPhone_12_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_13_mini__iPhone_12_mini__iPhone_11_Pro__iPhone_XS__iPhone_X_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_11_Pro_Max__iPhone_XS_Max_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_11__iPhone_XR_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_8_Plus__iPhone_7_Plus__iPhone_6s_Plus__iPhone_6_Plus_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/iPhone_8__iPhone_7__iPhone_6s__iPhone_6__4.7__iPhone_SE_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/4__iPhone_SE__iPod_touch_5th_generation_and_later_landscape.png">
|
||
|
||
<!-- iPad Landscape -->
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 1032px) and (device-height: 1376px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/13__iPad_Pro_M4_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/12.9__iPad_Pro_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 834px) and (device-height: 1210px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/11__iPad_Pro_M4_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/11__iPad_Pro__10.5__iPad_Pro_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 820px) and (device-height: 1180px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/10.9__iPad_Air_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/10.5__iPad_Air_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/10.2__iPad_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/9.7__iPad_Pro__7.9__iPad_mini__9.7__iPad_Air__9.7__iPad_landscape.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)" href="/logo/splash/splash_screens/8.3__iPad_Mini_landscape.png">
|
||
|
||
<!-- Portrait -->
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 440px) and (device-height: 956px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_17_Pro_Max__iPhone_16_Pro_Max_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 402px) and (device-height: 874px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_17_Pro__iPhone_17__iPhone_16_Pro_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 430px) and (device-height: 932px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_16_Plus__iPhone_15_Pro_Max__iPhone_15_Plus__iPhone_14_Pro_Max_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 420px) and (device-height: 912px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_Air_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 393px) and (device-height: 852px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_16__iPhone_15_Pro__iPhone_15__iPhone_14_Pro_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_14_Plus__iPhone_13_Pro_Max__iPhone_12_Pro_Max_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_16e__iPhone_14__iPhone_13_Pro__iPhone_13__iPhone_12_Pro__iPhone_12_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_13_mini__iPhone_12_mini__iPhone_11_Pro__iPhone_XS__iPhone_X_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_11_Pro_Max__iPhone_XS_Max_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_11__iPhone_XR_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_8_Plus__iPhone_7_Plus__iPhone_6s_Plus__iPhone_6_Plus_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/iPhone_8__iPhone_7__iPhone_6s__iPhone_6__4.7__iPhone_SE_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/4__iPhone_SE__iPod_touch_5th_generation_and_later_portrait.png">
|
||
|
||
<!-- iPad Portrait -->
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 1032px) and (device-height: 1376px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/13__iPad_Pro_M4_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/12.9__iPad_Pro_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 834px) and (device-height: 1210px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/11__iPad_Pro_M4_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/11__iPad_Pro__10.5__iPad_Pro_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 820px) and (device-height: 1180px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/10.9__iPad_Air_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/10.5__iPad_Air_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 810px) and (device-height: 1080px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/10.2__iPad_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/9.7__iPad_Pro__7.9__iPad_mini__9.7__iPad_Air__9.7__iPad_portrait.png">
|
||
<link rel="apple-touch-startup-image" media="screen and (device-width: 744px) and (device-height: 1133px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)" href="/logo/splash/splash_screens/8.3__iPad_Mini_portrait.png">
|
||
|
||
<!-- Apple Touch Icons -->
|
||
<link rel="apple-touch-icon" href="/logo/icon-180x180.png?v=1788557187846">
|
||
<link rel="apple-touch-icon" sizes="57x57" href="/logo/icon-57x57.png">
|
||
<link rel="apple-touch-icon" sizes="60x60" href="/logo/icon-60x60.png">
|
||
<link rel="apple-touch-icon" sizes="72x72" href="/logo/icon-72x72.png">
|
||
<link rel="apple-touch-icon" sizes="76x76" href="/logo/icon-76x76.png">
|
||
<link rel="apple-touch-icon" sizes="114x114" href="/logo/icon-114x114.png">
|
||
<link rel="apple-touch-icon" sizes="120x120" href="/logo/icon-120x120.png">
|
||
<link rel="apple-touch-icon" sizes="144x144" href="/logo/icon-144x144.png">
|
||
<link rel="apple-touch-icon" sizes="152x152" href="/logo/icon-152x152.png">
|
||
<link rel="apple-touch-icon" sizes="180x180" href="/logo/icon-180x180.png?v=1788557187846">
|
||
|
||
<!-- Microsoft Tiles -->
|
||
<meta name="msapplication-TileColor" content="#ff6b35">
|
||
<meta name="msapplication-TileImage" content="./logo/icon-144x144.png">
|
||
<meta name="msapplication-config" content="/browserconfig.xml">
|
||
|
||
<!-- Theme colors.
|
||
Two tags with media queries, which is how the browser answers before any script has
|
||
run and how a client with no JavaScript answers permanently. They are the page's
|
||
own ground (--sb-bg in src/styles/theme.css), not the brand orange: this paints the
|
||
Android address bar and the iOS status bar, and a strip in a different colour from
|
||
the page reads as a rendering fault rather than as branding.
|
||
Once theme-boot.js runs it drops the media attributes and writes the resolved
|
||
colour into both, because a media query cannot express "light on a dark system",
|
||
which is exactly what someone who picked a theme by hand has asked for. -->
|
||
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#0f0f11">
|
||
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#f6f7f8">
|
||
<meta name="msapplication-navbutton-color" content="#0f0f11">
|
||
|
||
<!-- Security Headers for PWA - CSP is already defined above -->
|
||
|
||
|
||
<!-- SEO -->
|
||
<title>SecureBit.chat - месенджер із наскрізним шифруванням</title>
|
||
<meta name="description" content="Безкоштовний P2P-месенджер із наскрізним шифруванням просто у браузері. Без облікових записів і без серверів, що зберігають ваші повідомлення.">
|
||
<meta name="author" content="Volodymyr">
|
||
<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1">
|
||
<link rel="canonical" href="https://securebit.chat/uk/">
|
||
<link rel="alternate" hreflang="en" href="https://securebit.chat/">
|
||
<link rel="alternate" hreflang="de" href="https://securebit.chat/de/">
|
||
<link rel="alternate" hreflang="fr" href="https://securebit.chat/fr/">
|
||
<link rel="alternate" hreflang="es" href="https://securebit.chat/es/">
|
||
<link rel="alternate" hreflang="uk" href="https://securebit.chat/uk/">
|
||
<link rel="alternate" hreflang="ru" href="https://securebit.chat/ru/">
|
||
<link rel="alternate" hreflang="zh-Hans" href="https://securebit.chat/zh/">
|
||
<link rel="alternate" hreflang="ko" href="https://securebit.chat/ko/">
|
||
<link rel="alternate" hreflang="hi" href="https://securebit.chat/hi/">
|
||
<link rel="alternate" hreflang="ar" href="https://securebit.chat/ar/">
|
||
<link rel="alternate" hreflang="he" href="https://securebit.chat/he/">
|
||
<link rel="alternate" hreflang="fa" href="https://securebit.chat/fa/">
|
||
<link rel="alternate" hreflang="ur" href="https://securebit.chat/ur/">
|
||
<link rel="alternate" hreflang="x-default" href="https://securebit.chat/">
|
||
|
||
<!-- Open Graph -->
|
||
<meta property="og:site_name" content="SecureBit.chat">
|
||
<meta property="og:title" content="SecureBit.chat - одноранговий чат із наскрізним шифруванням">
|
||
<meta property="og:description" content="Захищений месенджер, який працює повністю у вашому браузері. Без облікових записів і без серверів, що зберігають ваші повідомлення. Підключайте власні STUN/TURN-сервери - ми нічого не нав'язуємо.">
|
||
<meta property="og:url" content="https://securebit.chat/uk/">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:locale" content="uk_UA">
|
||
<meta property="og:locale:alternate" content="en_US">
|
||
<meta property="og:locale:alternate" content="de_DE">
|
||
<meta property="og:locale:alternate" content="fr_FR">
|
||
<meta property="og:locale:alternate" content="es_ES">
|
||
<meta property="og:locale:alternate" content="ru_RU">
|
||
<meta property="og:locale:alternate" content="zh_CN">
|
||
<meta property="og:locale:alternate" content="ko_KR">
|
||
<meta property="og:locale:alternate" content="hi_IN">
|
||
<meta property="og:locale:alternate" content="ar_AR">
|
||
<meta property="og:locale:alternate" content="he_IL">
|
||
<meta property="og:locale:alternate" content="fa_IR">
|
||
<meta property="og:locale:alternate" content="ur_PK">
|
||
<meta property="og:image" content="https://securebit.chat/assets/social-card.png">
|
||
<meta property="og:image:secure_url" content="https://securebit.chat/assets/social-card.png">
|
||
<meta property="og:image:type" content="image/png">
|
||
<meta property="og:image:width" content="1200">
|
||
<meta property="og:image:height" content="630">
|
||
<meta property="og:image:alt" content="SecureBit.chat - одноранговий чат із наскрізним шифруванням">
|
||
|
||
<!-- Twitter Card -->
|
||
<meta name="twitter:card" content="summary_large_image">
|
||
<meta name="twitter:title" content="SecureBit.chat - одноранговий чат із наскрізним шифруванням">
|
||
<meta name="twitter:description" content="Захищений месенджер, який працює повністю у вашому браузері. Без облікових записів і без серверів, що зберігають ваші повідомлення.">
|
||
<meta name="twitter:image" content="https://securebit.chat/assets/social-card.png">
|
||
<meta name="twitter:image:alt" content="SecureBit.chat - одноранговий чат із наскрізним шифруванням">
|
||
|
||
<!-- Structured data (schema.org) -->
|
||
<script type="application/ld+json">
|
||
{
|
||
"@context": "https://schema.org",
|
||
"@graph": [
|
||
{
|
||
"@type": "Organization",
|
||
"@id": "https://securebit.chat/#organization",
|
||
"name": "SecureBit.chat",
|
||
"url": "https://securebit.chat/",
|
||
"logo": "https://securebit.chat/logo/icon-512x512.png",
|
||
"sameAs": [
|
||
"https://github.com/SecureBitChat/securebit-chat",
|
||
"https://snapcraft.io/securebit-chat"
|
||
]
|
||
},
|
||
{
|
||
"@type": "WebSite",
|
||
"@id": "https://securebit.chat/#website",
|
||
"name": "SecureBit.chat",
|
||
"url": "https://securebit.chat/",
|
||
"description": "Однорангові чат із наскрізним шифруванням, який працює повністю у браузері.",
|
||
"inLanguage": "uk",
|
||
"publisher": {
|
||
"@id": "https://securebit.chat/#organization"
|
||
}
|
||
},
|
||
{
|
||
"@type": "WebApplication",
|
||
"name": "SecureBit.chat",
|
||
"url": "https://securebit.chat/uk/",
|
||
"applicationCategory": "CommunicationApplication",
|
||
"operatingSystem": "Будь-яка (сучасний веббраузер)",
|
||
"browserRequirements": "Потребує WebRTC і Web Crypto API",
|
||
"description": "Безкоштовний одноранговий месенджер із наскрізним шифруванням. Без облікових записів і без серверів, що зберігають повідомлення: ECDH P-384, AES-256-GCM та особиста SAS-звірка.",
|
||
"inLanguage": "uk",
|
||
"image": "https://securebit.chat/assets/social-card.png",
|
||
"license": "https://opensource.org/licenses/MIT",
|
||
"isAccessibleForFree": true,
|
||
"offers": {
|
||
"@type": "Offer",
|
||
"price": "0",
|
||
"priceCurrency": "USD"
|
||
},
|
||
"featureList": [
|
||
"Наскрізне шифрування (ECDH P-384, AES-256-GCM)",
|
||
"Однорангове з'єднання через WebRTC, без серверів для повідомлень",
|
||
"Особиста SAS-звірка проти атак «людина посередині»",
|
||
"Власні STUN/TURN-сервери та режим приватності лише через relay",
|
||
"Зашифрована передача файлів",
|
||
"Прогресивний вебзастосунок, який можна встановити й використовувати офлайн"
|
||
],
|
||
"sameAs": [
|
||
"https://github.com/SecureBitChat/securebit-chat"
|
||
]
|
||
}
|
||
]
|
||
}
|
||
</script>
|
||
<!-- Render-blocking JS is deferred: classic deferred scripts and module scripts
|
||
both execute in document order after parsing, so React still runs before the
|
||
app modules below, but the parser / first paint is no longer blocked. -->
|
||
<script defer src="/config/ice-servers.js?v=1788557187846"></script>
|
||
<script defer src="/libs/react/react.production.min.js"></script>
|
||
<script defer src="/libs/react-dom/react-dom.production.min.js"></script>
|
||
<!-- Prism syntax highlighting (vendored, offline). Tokenizes code as TEXT only —
|
||
it never executes the snippet. Loaded in manual mode (no auto-highlight).
|
||
Its CSS is loaded async via load-async-css.js (not paint-critical). -->
|
||
<script defer src="/libs/prism/prism.js"></script>
|
||
<!-- One render-blocking stylesheet, built by scripts/build-css.js from the Tailwind
|
||
output, the Inter @font-face declarations and the five hand-written sheets, in
|
||
that order — they argue with each other on source order, and concatenation
|
||
preserves it exactly. There used to be eight separate <link> tags here and at
|
||
the end of <body>: 21 KB of CSS in total, but eight round trips before the
|
||
browser could paint, which GTmetrix measured at 441 ms on a throttled mobile
|
||
connection. Bytes were never the problem; requests were. -->
|
||
<link rel="stylesheet" href="/assets/app.css?v=1788557187846">
|
||
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico?v=1788557187846">
|
||
<!-- Preload only the fonts needed for first paint. Inter is one variable file that
|
||
answers for every weight, so there is one to preload rather than the two of five
|
||
copies this used to name. fa-solid covers the bulk of UI icons; fa-regular and
|
||
fa-brands are loaded on demand by their CSS, rarely on the first screen. -->
|
||
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.subset.woff2" as="font" type="font/woff2" crossorigin>
|
||
<link rel="preload" href="/assets/fonts/inter/files/inter-latin.woff2" as="font" type="font/woff2" crossorigin>
|
||
<!-- Non-critical CSS (FontAwesome ~102KB, Prism) loaded async — no longer blocks paint. -->
|
||
<script defer src="/src/scripts/load-async-css.js?v=1788557187846"></script>
|
||
<noscript>
|
||
<link rel="stylesheet" href="/libs/prism/prism.css">
|
||
</noscript>
|
||
<script defer src="/src/scripts/fa-check.js?v=1788557187846"></script>
|
||
<!-- This locale's dictionary, registered before anything can ask for a string.
|
||
Only the default locale's is bundled (src/i18n/index.js imports it, because t()
|
||
falls back to it); every other page loads its own here instead of all thirteen
|
||
riding along inside dist/app.js. Absent on the default locale's own page. -->
|
||
<script type="module" src="/src/i18n/dict/uk.js?v=1788557187846"></script>
|
||
<!-- Update Manager - система принудительного обновления -->
|
||
<script defer src="/src/utils/updateManager.js?v=1788557187846"></script>
|
||
<script type="module" src="/src/components/UpdateChecker.jsx?v=1788557187846"></script>
|
||
<!-- /dist/qr-local.js is deliberately absent: app-boot.js fetches it once the
|
||
app has mounted and the browser is idle, so the 142 KB it weighs is off the
|
||
first load. src/components/QRScanner.js used to be here too and registered
|
||
window.QRScanner, which nothing has ever read. -->
|
||
</head>
|
||
<body>
|
||
<div id="root">
|
||
<style>
|
||
.sb-pre{display:none}
|
||
.sb-boot{display:flex;align-items:center;justify-content:center;min-height:100vh;min-height:100svh;margin:0;background:var(--sb-bg)}
|
||
.sb-boot svg{width:62px;height:auto;display:block;animation:sbBootPulse 1.8s ease-in-out infinite}
|
||
@keyframes sbBootPulse{0%,100%{opacity:.32;transform:scale(.97)}50%{opacity:1;transform:scale(1)}}
|
||
@media (prefers-reduced-motion:reduce){.sb-boot svg{animation:none;opacity:.75}}
|
||
</style>
|
||
<noscript><style>
|
||
.sb-pre{display:block}
|
||
.sb-boot{display:none}
|
||
</style></noscript>
|
||
<style>
|
||
.sb-pre{background:var(--sb-bg);color:var(--sb-text-2);font-family:Inter,system-ui,-apple-system,"Segoe UI",sans-serif;line-height:1.6;padding:56px 24px 72px;margin:0}
|
||
.sb-pre .sb-pre-in{max-width:940px;margin:0 auto;display:flex;flex-direction:column;gap:56px}
|
||
.sb-pre .sb-pre-brand{font-size:13px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--sb-orange);margin:0 0 18px}
|
||
.sb-pre h1{font-size:clamp(28px,5vw,40px);font-weight:800;letter-spacing:-1.1px;line-height:1.12;color:var(--sb-text-1);margin:0 0 14px}
|
||
.sb-pre h2{font-size:23px;font-weight:700;letter-spacing:-.5px;color:var(--sb-text-1);margin:0 0 8px}
|
||
.sb-pre h3{font-size:17px;font-weight:700;letter-spacing:-.2px;color:var(--sb-text-2);margin:0 0 6px}
|
||
.sb-pre p{margin:0 0 10px;color:var(--sb-text-7);font-size:15px;max-width:62ch}
|
||
.sb-pre .sb-pre-lead{font-size:16px;color:var(--sb-text-5);max-width:52ch}
|
||
.sb-pre .sb-pre-eyebrow{font-size:11px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--sb-text-9);margin:0 0 6px}
|
||
.sb-pre .sb-pre-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:18px;margin-top:22px;padding:0;list-style:none}
|
||
.sb-pre .sb-pre-card{background:var(--sb-surface);border:1px solid rgba(var(--sb-ink),.07);border-radius:10px;padding:18px 20px}
|
||
.sb-pre .sb-pre-tags{margin:10px 0 0;padding:0;list-style:none;display:flex;flex-wrap:wrap;gap:6px}
|
||
.sb-pre .sb-pre-tags li{font-size:11.5px;color:var(--sb-green);background:rgba(var(--sb-green-rgb),.09);border:1px solid rgba(var(--sb-green-rgb),.18);border-radius:4px;padding:2px 7px}
|
||
.sb-pre .sb-pre-steps{margin:22px 0 0;padding:0;list-style:none;display:flex;flex-direction:column;gap:2px}
|
||
.sb-pre .sb-pre-steps li{border-top:1px solid rgba(var(--sb-ink),.06);padding:13px 0;display:flex;flex-wrap:wrap;gap:2px 14px;align-items:baseline}
|
||
.sb-pre .sb-pre-steps h3{margin:0;font-size:15.5px}
|
||
.sb-pre .sb-pre-steps .sb-pre-when{font-size:12px;color:var(--sb-text-9);margin-inline-start:auto;white-space:nowrap}
|
||
.sb-pre .sb-pre-steps p{flex:1 1 100%;margin:2px 0 0;font-size:14px}
|
||
.sb-pre .sb-pre-docs{margin:14px 0 0;padding:0;list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:2px 24px}
|
||
.sb-pre .sb-pre-docs li{padding:8px 0;border-top:1px solid rgba(var(--sb-ink),.06);font-size:14.5px}
|
||
.sb-pre a{color:var(--sb-orange);text-underline-offset:2px}
|
||
@media (prefers-reduced-motion:reduce){.sb-pre *{animation:none!important;transition:none!important}}
|
||
</style>
|
||
<div class="sb-boot" aria-hidden="true">
|
||
<svg viewBox="276 240 700 760" xmlns="http://www.w3.org/2000/svg" focusable="false">
|
||
<defs>
|
||
<linearGradient id="sbBootSilver" x1="0" y1="0" x2="0.35" y2="1"><stop offset="0" stop-color="#fdfdff"/><stop offset="0.20" stop-color="#e7e7ec"/><stop offset="0.46" stop-color="#c4c4cb"/><stop offset="0.72" stop-color="#a4a4ac"/><stop offset="1" stop-color="#86868d"/></linearGradient>
|
||
<linearGradient id="sbBootOrange" x1="0" y1="0" x2="0.25" y2="1"><stop offset="0" stop-color="#ffb84d"/><stop offset="0.27" stop-color="#ff9a33"/><stop offset="0.58" stop-color="#fb7d16"/><stop offset="1" stop-color="#db5d04"/></linearGradient>
|
||
</defs>
|
||
<path fill="url(#sbBootSilver)" fill-rule="nonzero" d="m 835.26446,352.56633 102.39051,-103.90366 -418.64101,1.00877 c 0,0 -171.69323,1.22309 -222.43455,167.96079 -52.34251,171.99925 77.67556,253.20215 77.67556,253.20215 0,0 35.54922,23.82856 79.77792,31.68982 15.73869,2.39372 79.16695,1.09532 79.16695,1.09532 54.47377,-10.08773 41.40629,-81.22528 -10.65516,-77.67557 C 492.06451,630.5166 372.5156,615.45079 386.86464,469.07968 415.02639,353.31661 520.52712,353.57511 520.52712,353.57511 Z"/>
|
||
<path fill="url(#sbBootOrange)" fill-rule="nonzero" d="m 289.24744,881.29522 95.22696,-95.94027 369.13823,1.06997 C 873.15229,774.31964 863.51011,647.63259 863.51011,647.63259 846.7608,546.1216 749.51871,545.49427 749.51871,545.49427 l -232.01791,0.25219 c -37.80546,-8.91638 -37.85435,-49.4299 -37.85435,-49.4299 0,0 -1.56131,-38.07813 40.52401,-46.63785 l 260.62023,-0.7745 c 170.83788,24.60922 185.61432,187.63187 185.61432,187.63187 0,0 18.85523,117.07655 -90.63794,200.89054 l -0.62454,154.4184 -144.79052,-110.68137 z"/>
|
||
<path fill="url(#sbBootOrange)" d="m 658.38568,658.74237 a 27.462458,27.462458 0 0 1 -27.43073,27.46244 27.462458,27.462458 0 0 1 -27.49412,-27.39898 27.462458,27.462458 0 0 1 27.36719,-27.52575 27.462458,27.462458 0 0 1 27.55736,27.33536 z"/>
|
||
<path fill="url(#sbBootOrange)" d="m 748.42871,659.07971 a 27.462458,27.462458 0 0 1 -27.43073,27.46244 27.462458,27.462458 0 0 1 -27.49412,-27.39898 27.462458,27.462458 0 0 1 27.36719,-27.52575 27.462458,27.462458 0 0 1 27.55736,27.33537 z"/>
|
||
</svg>
|
||
</div>
|
||
<div class="sb-pre">
|
||
<div class="sb-pre-in">
|
||
<header>
|
||
<p class="sb-pre-brand">SecureBit.chat</p>
|
||
<h1>Пряма лінія,<br>яку прочитаєте лише ви двоє.</h1>
|
||
<p class="sb-pre-lead">Ключі створюються на вашому пристрої й передаються напряму між учасниками. Без облікових записів і без серверів, що зберігають ваші повідомлення.</p>
|
||
</header>
|
||
<section>
|
||
<p class="sb-pre-eyebrow">Чим ми вирізняємось</p>
|
||
<h2>Чому SecureBit - особливий</h2>
|
||
<ul class="sb-pre-grid">
|
||
<li class="sb-pre-card">
|
||
<h3>Багатошарове ядро шифрування</h3>
|
||
<p>Обмін ключами ECDH P-384, корисне навантаження в AES-256-GCM, підписи ECDSA і повна валідація ASN.1 - зведені в один загартований конвеєр.</p>
|
||
<ul class="sb-pre-tags"><li>ECDH P-384</li><li>AES-256-GCM</li><li>ECDSA</li><li>ASN.1</li></ul>
|
||
</li>
|
||
<li class="sb-pre-card">
|
||
<h3>Чистий P2P через WebRTC</h3>
|
||
<p>Повідомлення йдуть напряму між пристроями через WebRTC. Жоден relay не тримає ваших даних - сервер лише допомагає двом учасникам знайти одне одного.</p>
|
||
<ul class="sb-pre-tags"><li>DTLS 1.3</li><li>Без relay</li></ul>
|
||
</li>
|
||
<li class="sb-pre-card">
|
||
<h3>Досконала пряма секретність</h3>
|
||
<p>Сеансові ключі змінюються безперервно й відкидаються після використання, тож один скомпрометований ключ ніколи не відкриє попередніх розмов.</p>
|
||
<ul class="sb-pre-tags"><li>Ефемерні ключі</li><li>Автоматична зміна</li></ul>
|
||
</li>
|
||
<li class="sb-pre-card">
|
||
<h3>Маскування трафіку</h3>
|
||
<p>Розміри пакетів і паузи між ними доповнюються та рандомізуються, тож метадані не складаються в помітний візерунок навіть для того, хто стежить за каналом.</p>
|
||
<ul class="sb-pre-tags"><li>Доповнення пакетів</li><li>Розкид у часі</li></ul>
|
||
</li>
|
||
<li class="sb-pre-card">
|
||
<h3>Жодного збору даних</h3>
|
||
<p>Без облікових записів, без журналів, без збереження повідомлень. На сервері немає нічого, що можна злити, вилучити за ухвалою чи продати.</p>
|
||
<ul class="sb-pre-tags"><li>Без облікових записів</li><li>Без журналів</li></ul>
|
||
</li>
|
||
</ul>
|
||
</section>
|
||
<section>
|
||
<p class="sb-pre-eyebrow">Дорожня карта</p>
|
||
<h2>Як розвивався SecureBit</h2>
|
||
<p>Від першого прототипу до децентралізованої мережі, стійкої до квантових обчислень, з повною валідацією ASN.1 на кожному рівні.</p>
|
||
<ol class="sb-pre-steps">
|
||
<li>
|
||
<h3>Початок розробки</h3>
|
||
<span class="sb-pre-when">Початок 2025</span>
|
||
<p>Ідея, прототип і налаштування інфраструктури</p>
|
||
</li>
|
||
<li>
|
||
<h3>Альфа-версія</h3>
|
||
<span class="sb-pre-when">Весна 2025</span>
|
||
<p>Перша публічна альфа: базовий чат і обмін ключами</p>
|
||
</li>
|
||
<li>
|
||
<h3>Посилений захист</h3>
|
||
<span class="sb-pre-when">Літо 2025</span>
|
||
<p>Зміцнення безпеки та випуск стабільної гілки</p>
|
||
</li>
|
||
<li>
|
||
<h3>Масштабування та стабільність</h3>
|
||
<span class="sb-pre-when">Осінь 2025</span>
|
||
<p>Масштабування мережі та підвищення стабільності</p>
|
||
</li>
|
||
<li>
|
||
<h3>Приватність передусім</h3>
|
||
<span class="sb-pre-when">Зима 2025</span>
|
||
<p>Фокус на приватності: зменшення метаданих</p>
|
||
</li>
|
||
<li>
|
||
<h3>Enhanced Security Edition</h3>
|
||
<span class="sb-pre-when">Кінець 2025</span>
|
||
<p>18-шарова криптографія військового рівня з повною валідацією ASN.1</p>
|
||
</li>
|
||
<li>
|
||
<h3>Desktop Edition</h3>
|
||
<span class="sb-pre-when">Початок 2026</span>
|
||
<p>Власні застосунки для Windows, macOS і Linux</p>
|
||
</li>
|
||
<li>
|
||
<h3>Захищений голос і дзвінки</h3>
|
||
<span class="sb-pre-when">Початок 2026</span>
|
||
<p>Зашифровані голосові повідомлення, аудіо- та відеодзвінки</p>
|
||
</li>
|
||
<li>
|
||
<h3>Групове спілкування</h3>
|
||
<span class="sb-pre-when">Зараз</span>
|
||
<p>Групові чати без втрати приватності</p>
|
||
</li>
|
||
<li>
|
||
<h3>Mobile Edition</h3>
|
||
<span class="sb-pre-when">II квартал 2027</span>
|
||
<p>Власні застосунки для iOS та Android</p>
|
||
</li>
|
||
<li>
|
||
<h3>Стійкість до квантових обчислень</h3>
|
||
<span class="sb-pre-when">IV квартал 2027</span>
|
||
<p>Захист від квантових комп'ютерів</p>
|
||
</li>
|
||
<li>
|
||
<h3>Децентралізована мережа</h3>
|
||
<span class="sb-pre-when">2028</span>
|
||
<p>Повністю децентралізована мережа</p>
|
||
</li>
|
||
<li>
|
||
<h3>ШІ-помічник із приватності</h3>
|
||
<span class="sb-pre-when">2028+</span>
|
||
<p>Штучний інтелект для приватності та безпеки</p>
|
||
</li>
|
||
</ol>
|
||
</section>
|
||
<section lang="en" dir="ltr">
|
||
<p class="sb-pre-eyebrow">Documentation</p>
|
||
<ul class="sb-pre-docs">
|
||
<li><a href="/docs/" hreflang="en">Documentation</a></li>
|
||
<li><a href="/docs/faq/" hreflang="en">Frequently asked questions</a></li>
|
||
<li><a href="/docs/architecture/" hreflang="en">Architecture</a></li>
|
||
<li><a href="/docs/cryptography/" hreflang="en">Cryptography</a></li>
|
||
<li><a href="/docs/descriptor-sbq2/" hreflang="en">SBQ2 — connection descriptor v2</a></li>
|
||
<li><a href="/docs/configuration/" hreflang="en">Configuration</a></li>
|
||
<li><a href="/docs/calls/" hreflang="en">Voice and video calls</a></li>
|
||
<li><a href="/docs/api/" hreflang="en">API Notes</a></li>
|
||
<li><a href="/docs/contributing/" hreflang="en">Contributing</a></li>
|
||
<li><a href="/docs/use-policy/" hreflang="en">Use policy and limitations</a></li>
|
||
</ul>
|
||
</section>
|
||
<section>
|
||
<h2>Долучайтеся до майбутнього приватності</h2>
|
||
<p>SecureBit росте завдяки своїй спільноті. Ваші ідеї та відгуки формують майбутнє захищеного спілкування - розробка ведеться відкрито, з повною валідацією ASN.1 на всьому шляху.</p>
|
||
<p><a href="https://github.com/SecureBitChat/securebit-chat" rel="noopener">Репозиторій на GitHub</a></p>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<script type="module" src="/dist/app-boot.js?v=1788557187846"></script>
|
||
<script type="module" src="/dist/app.js?v=1788557187846"></script>
|
||
|
||
<script defer src="/src/scripts/pwa-register.js?v=1788557187846"></script>
|
||
<script src="/src/pwa/install-prompt.js?v=1788557187846" type="module"></script>
|
||
<script src="/src/pwa/pwa-manager.js?v=1788557187846" type="module"></script>
|
||
<script defer src="/src/scripts/pwa-offline-test.js?v=1788557187846"></script>
|
||
</body>
|
||
</html> |