Сайт-визитка: главная, архитектура, проекты

- Главная: фото, факты, соцсети, форма связи, анимации
- Архитектура: карточки проектов и отдельные страницы (Тихий двор, павильон, «Лофт»)
- Проекты: Aman's World (скриншоты, описание) и хоумлаб
- Меню из config.json, шаблон новых страниц, черновики training/work/fixed
- Чистый HTML/CSS/JS без сборки, шрифты и картинки локально

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-04 16:35:52 +05:00
co-authored by Claude Sonnet 5.5
commit 152f1d60b5
94 changed files with 1517 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>404: такой страницы нет</title>
<meta name="robots" content="noindex">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<div class="blob blob--a" aria-hidden="true"></div>
<div class="blob blob--b" aria-hidden="true"></div>
<main class="page">
<section class="talk">
<h2>404</h2>
<p class="cta">Такой страницы нет. Либо ссылка устарела, либо я её переименовал. Скорее второе.</p>
<ul class="links"><li><a class="link link--mail" href="/"><span class="ic" aria-hidden="true">←</span><span class="lk">На главную</span></a></li></ul>
</section>
</main>
</body>
</html>
+86
View File
@@ -0,0 +1,86 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Выставочный павильон: Аман Ибраш</title>
<meta name="description" content="Выставочный павильон в Алматы: двухэтажная галерея в парке со стеклянным первым этажом и террасой для скульптур.">
<meta name="theme-color" content="#f4f6fb">
<meta property="og:type" content="website">
<meta property="og:locale" content="ru_RU">
<meta property="og:title" content="Выставочный павильон: Аман Ибраш">
<meta property="og:description" content="Выставочный павильон в Алматы: двухэтажная галерея в парке со стеклянным первым этажом и террасой для скульптур.">
<meta property="og:image" content="https://example.com/og/arch-exhibition-pavilion.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Выставочный павильон: Аман Ибраш">
<meta name="twitter:description" content="Выставочный павильон в Алматы: двухэтажная галерея в парке со стеклянным первым этажом и террасой для скульптур.">
<meta name="twitter:image" content="https://example.com/og/arch-exhibition-pavilion.jpg">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="preload" href="/fonts/onest-cyrillic-wght-normal.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/css/style.css">
<script src="/js/boot.js"></script>
</head>
<body class="doc has-nav">
<div class="blob blob--a" aria-hidden="true"></div>
<div class="blob blob--b" aria-hidden="true"></div>
<nav class="topnav" id="topnav" aria-label="Страницы"></nav>
<main class="page page--wide">
<p class="back"><a href="/arch/">← Архитектура</a></p>
<header class="case-head">
<ul class="meta"><li>2026</li><li>Алматы</li><li>общественное здание</li></ul>
<h1>Выставочный павильон</h1>
<p class="lead">Галерея в парке</p>
</header>
<div class="gallery gallery--one">
<figure class="shot shot--cover shot--lead">
<a href="/img/arch/pav-2.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Главный фасад"><img src="/img/arch/pav-2-md.webp" srcset="/img/arch/pav-2-sm.webp 640w, /img/arch/pav-2-md.webp 960w, /img/arch/pav-2.webp 1400w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1400" height="784" alt="Главный фасад" fetchpriority="high"></a>
<figcaption>Главный фасад</figcaption>
</figure>
</div>
<ul class="case-stats"><li class="stat"><b data-count="2">2</b><span>этажа</span></li><li class="stat"><b data-count="26">26</b><span>м длина здания</span></li><li class="stat"><b data-count="2">2</b><span>галереи</span></li><li class="stat"><b data-count="1">1</b><span>терраса для скульптур</span></li></ul>
<section class="case-body">
<p class="intro">Витрина, которую видно с аллеи ещё до входа.</p>
<h2>Первый этаж как витрина</h2><p>Павильон стоит в парке и работает как витрина: первый этаж почти целиком остеклён, поэтому экспозицию видно с аллеи ещё до входа. Входишь, и сразу попадаешь в холл, из которого открываются обе галереи.</p><h2>Спокойный план</h2><p>Из холла гости идут в две галереи, а лестница ведёт на второй уровень с открытой террасой для скульптур. Служебные помещения собраны в одном крыле, поэтому залы остаются свободными и чистыми для выставок.</p><h2>Три материала</h2><p>Фасад собран из трёх материалов: стеклянная витрина, плоскости бетона и тёплые деревянные ламели. Они держат один спокойный ритм и не спорят с парком вокруг.</p>
</section>
<section class="case-block" aria-label="Визуализации">
<h2 class="block-title">Кадры</h2>
<div class="gallery">
<figure class="shot">
<a href="/img/arch/pav-1.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Вход и холл"><img src="/img/arch/pav-1-md.webp" srcset="/img/arch/pav-1-sm.webp 640w, /img/arch/pav-1-md.webp 960w, /img/arch/pav-1.webp 1400w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1400" height="781" alt="Вход и холл" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>Вход и холл</figcaption>
</figure>
<figure class="shot">
<a href="/img/arch/pav-3.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Вид сверху на парк"><img src="/img/arch/pav-3-md.webp" srcset="/img/arch/pav-3-sm.webp 640w, /img/arch/pav-3-md.webp 960w, /img/arch/pav-3.webp 1400w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1400" height="781" alt="Вид сверху на парк" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>Вид сверху на парк</figcaption>
</figure>
</div>
</section>
<section class="case-block" aria-label="Чертежи">
<h2 class="block-title">Чертежи и схемы</h2>
<div class="gallery">
<figure class="shot shot--wide">
<a href="/img/arch/pav-plan.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: План первого этажа: две галереи и холл"><img src="/img/arch/pav-plan-md.webp" srcset="/img/arch/pav-plan-sm.webp 640w, /img/arch/pav-plan-md.webp 960w, /img/arch/pav-plan.webp 1400w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1400" height="738" alt="План первого этажа: две галереи и холл" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>План первого этажа: две галереи и холл</figcaption>
</figure>
</div>
</section>
<a class="next-case" href="/arch/loft-complex/">
<span class="muted-w">Следующий проект</span>
<span class="next-title">Жилой комплекс «Лофт»</span>
<span class="next-arrow" aria-hidden="true">→</span>
</a>
</main>
<script src="/js/nav.js" defer></script>
<script src="/js/count.js" defer></script>
</body>
</html>
+76
View File
@@ -0,0 +1,76 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Архитектура: Аман Ибраш</title>
<meta name="description" content="Учусь архитектуре в KazGASA, Алматы. Мои лучшие проекты: Тихий двор, выставочный павильон и жилой комплекс.">
<meta name="theme-color" content="#f4f6fb">
<meta property="og:type" content="website">
<meta property="og:locale" content="ru_RU">
<meta property="og:title" content="Архитектура: Аман Ибраш">
<meta property="og:description" content="Учусь архитектуре в KazGASA, Алматы. Мои лучшие проекты: Тихий двор, выставочный павильон и жилой комплекс.">
<meta property="og:image" content="https://example.com/og/arch.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Архитектура: Аман Ибраш">
<meta name="twitter:description" content="Учусь архитектуре в KazGASA, Алматы. Мои лучшие проекты: Тихий двор, выставочный павильон и жилой комплекс.">
<meta name="twitter:image" content="https://example.com/og/arch.jpg">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="preload" href="/fonts/onest-cyrillic-wght-normal.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/css/style.css">
<script src="/js/boot.js"></script>
</head>
<body class="doc has-nav">
<div class="blob blob--a" aria-hidden="true"></div>
<div class="blob blob--b" aria-hidden="true"></div>
<nav class="topnav" id="topnav" aria-label="Страницы"></nav>
<main class="page page--wide">
<header class="page-intro">
<p class="hello">Архитектура</p>
<h1>Рисую здания</h1>
<p class="lead">Я студент KazGASA в Алматы. Здесь проекты, которыми горжусь больше всего. Выбери любой и загляни внутрь.</p>
</header>
<section class="works" aria-label="Проекты">
<a class="work work--lead" href="/arch/quiet-courtyard/">
<div class="pic"><img src="/img/arch/house-pond-md.webp" srcset="/img/arch/house-pond-sm.webp 640w, /img/arch/house-pond-md.webp 960w, /img/arch/house-pond.webp 1200w" sizes="(min-width: 62rem) 50vw, calc(100vw - 2.2rem)" width="1200" height="896" alt="Тихий двор" fetchpriority="high"></div>
<div class="info">
<ul class="meta"><li>2026</li><li>Конаев</li></ul>
<h2>Тихий двор</h2>
<p>Бетон, дерево и двор, в который приходят небо и свет.</p>
<span class="more">Смотреть проект <span aria-hidden="true">→</span></span>
</div>
</a>
<a class="work" href="/arch/exhibition-pavilion/">
<div class="pic"><img src="/img/arch/pav-2-md.webp" srcset="/img/arch/pav-2-sm.webp 640w, /img/arch/pav-2-md.webp 960w, /img/arch/pav-2.webp 1400w" sizes="(min-width: 62rem) 50vw, calc(100vw - 2.2rem)" width="1400" height="784" alt="Выставочный павильон" loading="lazy" decoding="async" fetchpriority="low"></div>
<div class="info">
<ul class="meta"><li>2026</li><li>Алматы</li></ul>
<h2>Выставочный павильон</h2>
<p>Стеклянная витрина среди деревьев и терраса для скульптур.</p>
<span class="more">Смотреть проект <span aria-hidden="true">→</span></span>
</div>
</a>
<a class="work" href="/arch/loft-complex/">
<div class="pic"><img src="/img/arch/loft-0-md.webp" srcset="/img/arch/loft-0-sm.webp 640w, /img/arch/loft-0-md.webp 960w, /img/arch/loft-0.webp 1400w" sizes="(min-width: 62rem) 50vw, calc(100vw - 2.2rem)" width="1400" height="1048" alt="Жилой комплекс «Лофт»" loading="lazy" decoding="async" fetchpriority="low"></div>
<div class="info">
<ul class="meta"><li>2026</li><li>Алматы</li></ul>
<h2>Жилой комплекс «Лофт»</h2>
<p>Красный кирпич и общий двор, свободный от машин.</p>
<span class="more">Смотреть проект <span aria-hidden="true">→</span></span>
</div>
</a>
</section>
<aside class="soon">
<p class="hello">Дальше</p>
<p>Здесь будет больше: учёба, эскизы и то, что я вижу и фотографирую. Загляни позже.</p>
</aside>
</main>
<script src="/js/nav.js" defer></script>
<script src="/js/count.js" defer></script>
</body>
</html>
+72
View File
@@ -0,0 +1,72 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Жилой комплекс «Лофт»: Аман Ибраш</title>
<meta name="description" content="Жилой комплекс «Лофт» в Алматы: три корпуса из красного кирпича вокруг общего двора без машин.">
<meta name="theme-color" content="#f4f6fb">
<meta property="og:type" content="website">
<meta property="og:locale" content="ru_RU">
<meta property="og:title" content="Жилой комплекс «Лофт»: Аман Ибраш">
<meta property="og:description" content="Жилой комплекс «Лофт» в Алматы: три корпуса из красного кирпича вокруг общего двора без машин.">
<meta property="og:image" content="https://example.com/og/arch-loft-complex.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Жилой комплекс «Лофт»: Аман Ибраш">
<meta name="twitter:description" content="Жилой комплекс «Лофт» в Алматы: три корпуса из красного кирпича вокруг общего двора без машин.">
<meta name="twitter:image" content="https://example.com/og/arch-loft-complex.jpg">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="preload" href="/fonts/onest-cyrillic-wght-normal.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/css/style.css">
<script src="/js/boot.js"></script>
</head>
<body class="doc has-nav">
<div class="blob blob--a" aria-hidden="true"></div>
<div class="blob blob--b" aria-hidden="true"></div>
<nav class="topnav" id="topnav" aria-label="Страницы"></nav>
<main class="page page--wide">
<p class="back"><a href="/arch/">← Архитектура</a></p>
<header class="case-head">
<ul class="meta"><li>2026</li><li>Алматы</li><li>жилой комплекс</li></ul>
<h1>Жилой комплекс «Лофт»</h1>
<p class="lead">Три корпуса вокруг двора без машин</p>
</header>
<div class="gallery gallery--one">
<figure class="shot shot--cover shot--lead">
<a href="/img/arch/loft-0.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Общий вид комплекса"><img src="/img/arch/loft-0-md.webp" srcset="/img/arch/loft-0-sm.webp 640w, /img/arch/loft-0-md.webp 960w, /img/arch/loft-0.webp 1400w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1400" height="1048" alt="Общий вид комплекса" fetchpriority="high"></a>
<figcaption>Общий вид комплекса</figcaption>
</figure>
</div>
<ul class="case-stats"><li class="stat"><b data-count="3">3</b><span>корпуса</span></li><li class="stat"><b data-count="2.11">2,11</b><span>га участок</span></li><li class="stat"><b data-count="7">7</b><span>этажей, корпус 1</span></li><li class="stat"><b data-count="1">1</b><span>подземный паркинг</span></li></ul>
<section class="case-body">
<p class="intro">Красный кирпич, арки на первом этаже и двор, где можно гулять.</p>
<h2>Двор без машин</h2><p>Комплекс стоит на участке 2,11 га в Турксибском районе Алматы. Три корпуса образуют общий двор, и машин в нём нет: парковка спрятана под землёй, а на поверхности остались площадки и озеленение.</p><h2>Кирпич и арки</h2><p>На первом этаже коммерция за арочными стальными витражами. Выше идут жилые этажи с окнами в стальных рамах. Фасад корпуса 1 выполнен из красного лицевого кирпича, а стальной пояс отделяет коммерческий этаж от квартир.</p>
</section>
<section class="case-block" aria-label="Чертежи">
<h2 class="block-title">Чертежи и схемы</h2>
<div class="gallery">
<figure class="shot shot--wide">
<a href="/img/arch/loft-facade.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Боковые фасады корпуса 1"><img src="/img/arch/loft-facade-md.webp" srcset="/img/arch/loft-facade-sm.webp 640w, /img/arch/loft-facade-md.webp 960w, /img/arch/loft-facade.webp 1400w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1400" height="768" alt="Боковые фасады корпуса 1" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>Боковые фасады корпуса 1</figcaption>
</figure>
</div>
</section>
<a class="next-case" href="/arch/quiet-courtyard/">
<span class="muted-w">Следующий проект</span>
<span class="next-title">Тихий двор</span>
<span class="next-arrow" aria-hidden="true">→</span>
</a>
</main>
<script src="/js/nav.js" defer></script>
<script src="/js/count.js" defer></script>
</body>
</html>
+106
View File
@@ -0,0 +1,106 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Тихий двор: Аман Ибраш</title>
<meta name="description" content="Тихий двор: одноэтажный бетонный дом в Конаеве вокруг внутреннего двора. Проект в диалоге с архитектурой Тадао Андо.">
<meta name="theme-color" content="#f4f6fb">
<meta property="og:type" content="website">
<meta property="og:locale" content="ru_RU">
<meta property="og:title" content="Тихий двор: Аман Ибраш">
<meta property="og:description" content="Тихий двор: одноэтажный бетонный дом в Конаеве вокруг внутреннего двора. Проект в диалоге с архитектурой Тадао Андо.">
<meta property="og:image" content="https://example.com/og/arch-quiet-courtyard.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Тихий двор: Аман Ибраш">
<meta name="twitter:description" content="Тихий двор: одноэтажный бетонный дом в Конаеве вокруг внутреннего двора. Проект в диалоге с архитектурой Тадао Андо.">
<meta name="twitter:image" content="https://example.com/og/arch-quiet-courtyard.jpg">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="preload" href="/fonts/onest-cyrillic-wght-normal.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/css/style.css">
<script src="/js/boot.js"></script>
</head>
<body class="doc has-nav">
<div class="blob blob--a" aria-hidden="true"></div>
<div class="blob blob--b" aria-hidden="true"></div>
<nav class="topnav" id="topnav" aria-label="Страницы"></nav>
<main class="page page--wide">
<p class="back"><a href="/arch/">← Архитектура</a></p>
<header class="case-head">
<ul class="meta"><li>2026</li><li>Конаев</li><li>жилой дом</li></ul>
<h1>Тихий двор</h1>
<p class="lead">Дом в Конаеве вокруг внутреннего двора</p>
</header>
<div class="gallery gallery--one">
<figure class="shot shot--cover shot--lead">
<a href="/img/arch/house-pond.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Фасад в сад: бетон, вода и зелень"><img src="/img/arch/house-pond-md.webp" srcset="/img/arch/house-pond-sm.webp 640w, /img/arch/house-pond-md.webp 960w, /img/arch/house-pond.webp 1200w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1200" height="896" alt="Фасад в сад: бетон, вода и зелень" fetchpriority="high"></a>
<figcaption>Фасад в сад: бетон, вода и зелень</figcaption>
</figure>
</div>
<ul class="case-stats"><li class="stat"><b data-count="1">1</b><span>этаж</span></li><li class="stat"><b data-count="32">32</b><span>м² внутренний двор</span></li><li class="stat"><b data-count="41">41</b><span>м² гостиная-кухня</span></li><li class="stat"><b data-count="3">3</b><span>спальни</span></li></ul>
<section class="case-body">
<p class="intro">Дом, который отвернулся от улицы и повернулся к небу.</p>
<h2>Улица остаётся снаружи</h2><p>Со стороны улицы это глухая бетонная стена с одной узкой щелью света. Она прячет вход от чужих глаз: чтобы попасть в дом, нужно пройти вдоль сада и только потом повернуть к двери. Рядом под бетонным навесом стоит машина, а сам дом остаётся спокойным и закрытым.</p><h2>Всё собрано вокруг двора</h2><p>Внутри всё держится на дворе площадью 32 м². Утреннее солнце заходит в него, галерея обходит двор по кругу, а комнаты открываются на гравий, воду и тонкие деревья. Над центром плана стоит зенитный фонарь: он приносит верхний свет в самую глубину дома.</p><h2>Бетон и тёплое дерево</h2><p>Главный материал один: бетон с отпечатками опалубки. Рядом с ним тёплое дерево дверей и потолочных обшивок, чёрный металл рам и зелень. Проект сделан в диалоге с архитектурой Тадао Андо: меньше деталей, больше света, тишины и тени.</p>
</section>
<section class="case-block" aria-label="Визуализации">
<h2 class="block-title">Кадры</h2>
<div class="gallery">
<figure class="shot">
<a href="/img/arch/house-street.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Фасад с улицы: глухая стена и въезд под навес"><img src="/img/arch/house-street-md.webp" srcset="/img/arch/house-street-sm.webp 640w, /img/arch/house-street-md.webp 960w, /img/arch/house-street.webp 1200w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1200" height="896" alt="Фасад с улицы: глухая стена и въезд под навес" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>Фасад с улицы: глухая стена и въезд под навес</figcaption>
</figure>
<figure class="shot">
<a href="/img/arch/house-courtyard.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Двор: стекло, дерево и гравий"><img src="/img/arch/house-courtyard-md.webp" srcset="/img/arch/house-courtyard-sm.webp 640w, /img/arch/house-courtyard-md.webp 960w, /img/arch/house-courtyard.webp 1200w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1200" height="896" alt="Двор: стекло, дерево и гравий" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>Двор: стекло, дерево и гравий</figcaption>
</figure>
<figure class="shot">
<a href="/img/arch/house-gallery.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Галерея вокруг двора"><img src="/img/arch/house-gallery-md.webp" srcset="/img/arch/house-gallery-sm.webp 640w, /img/arch/house-gallery-md.webp 960w, /img/arch/house-gallery.webp 1200w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1200" height="896" alt="Галерея вокруг двора" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>Галерея вокруг двора</figcaption>
</figure>
<figure class="shot">
<a href="/img/arch/house-corridor.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Коридор вдоль двора"><img src="/img/arch/house-corridor-md.webp" srcset="/img/arch/house-corridor-sm.webp 640w, /img/arch/house-corridor-md.webp 960w, /img/arch/house-corridor.webp 1200w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1200" height="896" alt="Коридор вдоль двора" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>Коридор вдоль двора</figcaption>
</figure>
<figure class="shot">
<a href="/img/arch/house-entry.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Вход: свет и тени на бетоне"><img src="/img/arch/house-entry-md.webp" srcset="/img/arch/house-entry-sm.webp 640w, /img/arch/house-entry-md.webp 960w, /img/arch/house-entry.webp 1200w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1200" height="896" alt="Вход: свет и тени на бетоне" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>Вход: свет и тени на бетоне</figcaption>
</figure>
</div>
</section>
<section class="case-block" aria-label="Чертежи">
<h2 class="block-title">Чертежи и схемы</h2>
<div class="gallery">
<figure class="shot shot--portrait">
<a href="/img/arch/house-concept.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Путь и свет: вход с улицы, щель света, путь вдоль сада, зенитный фонарь и утреннее солнце во двор"><img src="/img/arch/house-concept-md.webp" srcset="/img/arch/house-concept-sm.webp 640w, /img/arch/house-concept-md.webp 960w, /img/arch/house-concept.webp 981w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="981" height="1100" alt="Путь и свет: вход с улицы, щель света, путь вдоль сада, зенитный фонарь и утреннее солнце во двор" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>Путь и свет: вход с улицы, щель света, путь вдоль сада, зенитный фонарь и утреннее солнце во двор</figcaption>
</figure>
<figure class="shot shot--portrait">
<a href="/img/arch/house-plan.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: План первого этажа с зонированием"><img src="/img/arch/house-plan-md.webp" srcset="/img/arch/house-plan-sm.webp 640w, /img/arch/house-plan.webp 722w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="722" height="1000" alt="План первого этажа с зонированием" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>План первого этажа с зонированием</figcaption>
</figure>
<figure class="shot shot--wide">
<a href="/img/arch/house-axo.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Аксонометрия со срезом"><img src="/img/arch/house-axo-md.webp" srcset="/img/arch/house-axo-sm.webp 640w, /img/arch/house-axo-md.webp 960w, /img/arch/house-axo.webp 1400w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1400" height="1088" alt="Аксонометрия со срезом" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>Аксонометрия со срезом</figcaption>
</figure>
</div>
</section>
<a class="next-case" href="/arch/exhibition-pavilion/">
<span class="muted-w">Следующий проект</span>
<span class="next-title">Выставочный павильон</span>
<span class="next-arrow" aria-hidden="true">→</span>
</a>
</main>
<script src="/js/nav.js" defer></script>
<script src="/js/count.js" defer></script>
</body>
</html>
+80
View File
@@ -0,0 +1,80 @@
{
"_note": "TODO: заменить всё своим. Страница читает только этот файл.",
"name": "Аман Ибраш",
"photo": "/img/me.webp",
"status": "на связи",
"tagline": "Админю серверы, качаюсь, кручу педали на фиксе и рисую здания. Скучать некогда.",
"tags": [
{
"emoji": "🏋️",
"text": "тренировки"
},
{
"emoji": "💻",
"text": "работа"
},
{
"emoji": "🚴",
"text": "фикс"
}
],
"cta": "Хочешь пообщаться? Пиши, отвечу в течение пары часов.",
"email": "amnibrash@gmail.com",
"socials": [
{
"label": "Telegram",
"url": "https://t.me/aibrash",
"handle": "@aibrash"
},
{
"label": "Instagram",
"url": "https://www.instagram.com/aman_ibrash/",
"handle": "@aman_ibrash"
},
{
"label": "TikTok",
"url": "https://www.tiktok.com/@aman_ibrash",
"handle": "@aman_ibrash"
}
],
"_pages_note": "Страницы лежат в web/<имя>/. \"draft\": true прячет страницу из меню. Чтобы опубликовать: уберите draft, удалите noindex в самой странице, добавьте адрес в sitemap.xml.",
"pages": [
{
"label": "Архитектура",
"url": "/arch/"
},
{
"label": "Проекты",
"url": "/projects/"
},
{
"label": "Тренировки",
"url": "/training/",
"draft": true
},
{
"label": "Работа",
"url": "/work/",
"draft": true
},
{
"label": "Фикс",
"url": "/fixed/",
"draft": true
}
],
"facts": [
{
"emoji": "🎓",
"text": "студент KazGASA"
},
{
"emoji": "📍",
"text": "Алматы"
},
{
"emoji": "🎂",
"text": "18 лет"
}
]
}
+307
View File
@@ -0,0 +1,307 @@
/* ===== Шрифт (локально) ===== */
@font-face { font-family: 'Onest'; font-weight: 100 900; font-display: swap;
src: url('/fonts/onest-cyrillic-wght-normal.woff2') format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; }
@font-face { font-family: 'Onest'; font-weight: 100 900; font-display: swap;
src: url('/fonts/onest-latin-wght-normal.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
:root {
--bg: #f4f6fb; --card: #ffffff; --ink: #121a2b; --muted: #55627a; --line: #e2e8f3;
--accent: #3556ff; --accent-soft: #e8edff; --pop: #ffd84d; --good: #1fb865;
--font: 'Onest', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
--shadow: 0 1px 2px rgba(18, 26, 43, .05), 0 10px 30px rgba(18, 26, 43, .07);
color-scheme: light;
}
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body { margin: 0; min-height: 100vh; min-height: 100dvh; display: grid; grid-template-columns: minmax(0, 1fr); place-items: center; padding: 2rem 1.1rem; background: var(--bg); color: var(--ink); font: 400 1.0625rem/1.55 var(--font); overflow-x: hidden; position: relative; }
h1, h2, p, ul { margin: 0; }
ul { padding: 0; list-style: none; }
a { color: inherit; }
:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; border-radius: 12px; }
/* мягкие цветные пятна на фоне: только CSS, без картинок */
.blob { position: fixed; border-radius: 50%; filter: blur(60px); opacity: .55; pointer-events: none; z-index: 0; }
.blob--a { width: 22rem; height: 22rem; background: var(--pop); top: -8rem; right: -6rem; }
.blob--b { width: 20rem; height: 20rem; background: #b9c8ff; bottom: -8rem; left: -7rem; }
.page { position: relative; z-index: 1; width: 100%; min-width: 0; max-width: 30rem; display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.75rem; }
/* ===== Блок «обо мне» ===== */
.hero { display: grid; grid-template-columns: minmax(0, 1fr); justify-items: start; gap: .6rem; }
.avatar { width: 6.5rem; height: 6.5rem; border-radius: 30px; background: var(--pop); display: grid; place-items: center; overflow: hidden; transform: rotate(-4deg); box-shadow: var(--shadow); margin-bottom: .6rem; }
.avatar span { font-size: 2.4rem; font-weight: 800; letter-spacing: -.04em; }
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.hello { font-size: 1.15rem; color: var(--muted); font-weight: 500; }
.wave { display: inline-block; transform-origin: 70% 70%; }
h1 { font-size: clamp(2.5rem, 12vw, 3.4rem); font-weight: 800; letter-spacing: -.035em; line-height: 1.02; }
.tagline { color: var(--muted); font-size: 1.15rem; max-width: 26rem; }
.tags { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .4rem; }
.tags li { display: inline-flex; align-items: center; gap: .15rem; padding: .45rem .9rem; background: var(--card); border: 1px solid var(--line); border-radius: 99px; font-weight: 600; font-size: .95rem; box-shadow: 0 1px 2px rgba(18, 26, 43, .04); }
/* ===== Блок «давай общаться» ===== */
.talk { display: grid; grid-template-columns: minmax(0, 1fr); gap: .8rem; padding: 1.5rem; background: var(--card); border-radius: 28px; box-shadow: var(--shadow); }
.status { display: inline-flex; align-items: center; gap: .5rem; justify-self: start; font-size: .85rem; font-weight: 600; color: #127a43; background: #e5f7ec; padding: .25rem .7rem; border-radius: 99px; }
.dot { width: .55rem; height: .55rem; border-radius: 50%; background: var(--good); }
h2 { font-size: 1.6rem; font-weight: 800; letter-spacing: -.025em; line-height: 1.1; }
.cta { color: var(--muted); }
.links { display: grid; grid-template-columns: minmax(0, 1fr); gap: .6rem; margin-top: .6rem; }
.link { min-width: 0; display: flex; align-items: center; gap: .85rem; min-height: 3.75rem; padding: .6rem 1rem .6rem .7rem; background: var(--bg); border: 1px solid var(--line); border-radius: 18px; text-decoration: none; -webkit-tap-highlight-color: transparent; transition: transform .15s, background .15s, border-color .15s, box-shadow .15s; }
.link .ic { flex: none; width: 2.4rem; height: 2.4rem; display: grid; place-items: center; border-radius: 12px; background: var(--accent-soft); color: var(--accent); font-weight: 800; }
.link .lk { font-weight: 700; white-space: nowrap; }
.link .lh { min-width: 0; margin-left: auto; color: var(--muted); font-size: .92rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.link::after { content: '→'; color: var(--accent); font-weight: 700; }
.link:hover { transform: translateY(-2px); background: var(--card); border-color: var(--accent); box-shadow: var(--shadow); }
.link:active { transform: scale(.98); }
.link--mail { background: var(--accent); border-color: var(--accent); color: #fff; }
.link--mail .ic { background: rgba(255, 255, 255, .2); color: #fff; }
.link--mail .lh, .link--mail::after { color: rgba(255, 255, 255, .9); }
.link--mail:hover { background: #2443e0; border-color: #2443e0; }
/* ===== Компьютер: две колонки ===== */
@media (min-width: 56rem) {
body { padding: 3rem 2rem; }
.page { max-width: 62rem; grid-template-columns: minmax(0, 1fr) 26rem; align-items: center; gap: 4.5rem; }
.avatar { width: 9rem; height: 9rem; border-radius: 40px; }
.avatar span { font-size: 3.3rem; }
h1 { font-size: clamp(3.4rem, 6vw, 4.6rem); }
.tagline { font-size: 1.3rem; }
.tags li { font-size: 1rem; }
.talk { padding: 2rem; }
}
@media (min-width: 40rem) and (max-width: 55.99rem) { .page { max-width: 34rem; } .talk { padding: 2rem; } }
/* ===== Анимация: один вход + приветственная «волна» ===== */
@keyframes rise { from { opacity: 0; transform: translateY(1rem); } to { opacity: 1; transform: none; } }
@keyframes wave { 0%, 60%, 100% { transform: rotate(0); } 10%, 30% { transform: rotate(16deg); } 20%, 40% { transform: rotate(-10deg); } 50% { transform: rotate(8deg); } }
@keyframes pop { from { opacity: 0; transform: rotate(-4deg) scale(.7); } to { opacity: 1; transform: rotate(-4deg) scale(1); } }
@media (prefers-reduced-motion: no-preference) {
.avatar { animation: pop .6s cubic-bezier(.3, 1.4, .5, 1) backwards; }
.hero > :not(.avatar):not(.tagline), .talk { animation: rise .6s cubic-bezier(.22, .8, .2, 1) both; }
.hello { animation-delay: .1s; } h1 { animation-delay: .16s; } .tagline { animation-delay: .22s; } .tags { animation-delay: .28s; }
.talk { animation-delay: .34s; }
.links li { animation: rise .5s cubic-bezier(.22, .8, .2, 1) both; }
.links li:nth-child(1) { animation-delay: .5s; } .links li:nth-child(2) { animation-delay: .56s; }
.links li:nth-child(3) { animation-delay: .62s; } .links li:nth-child(4) { animation-delay: .68s; }
.wave { animation: wave 1.8s .9s 2; }
}
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; } }
/* пока JS подгружает config.json, страница скрыта (вёрстка не прыгает); анимация входа стартует после показа */
html.js:not(.ready) body[data-hide] .page { visibility: hidden; }
html.js:not(.ready) body[data-hide] .page * { animation-play-state: paused !important; }
/* ===== Верхнее меню и внутренние страницы ===== */
.topnav { position: absolute; top: 0; left: 50%; transform: translateX(-50%); z-index: 3; width: 100%; max-width: 62rem; display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: .7rem 1.1rem; }
.topnav:empty { display: none; }
.topnav .brand { font-weight: 800; letter-spacing: -.02em; text-decoration: none; white-space: nowrap; min-height: 2.75rem; display: inline-flex; align-items: center; }
.topnav ul { display: flex; gap: .25rem; overflow-x: auto; scrollbar-width: none; min-width: 0; }
.topnav ul::-webkit-scrollbar { display: none; }
.topnav .pill { display: inline-flex; align-items: center; min-height: 2.75rem; padding: 0 .95rem; border-radius: 99px; text-decoration: none; font-weight: 600; font-size: .95rem; color: var(--muted); white-space: nowrap; transition: background .15s, color .15s; }
.topnav .pill:hover { color: var(--ink); }
.topnav .pill[aria-current='page'] { background: var(--card); color: var(--ink); box-shadow: var(--shadow); }
body.has-nav { padding-top: 5rem; }
body.doc { place-items: start center; }
.page.page--doc { max-width: 40rem; grid-template-columns: minmax(0, 1fr); align-items: start; }
.doc-card { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; padding: 1.5rem; background: var(--card); border-radius: 28px; box-shadow: var(--shadow); }
.doc-card h1 { font-size: clamp(2rem, 8vw, 2.8rem); }
.prose { display: grid; gap: 1rem; color: var(--muted); }
.prose h2 { color: var(--ink); margin-top: .5rem; }
.prose a { color: var(--accent); }
@media (min-width: 56rem) { .doc-card { padding: 2.5rem; } body.has-nav { padding-top: 6rem; } }
/* с настоящим фото аватар крупнее, чтобы лицо было видно */
.avatar.has-photo { width: 8.5rem; height: 8.5rem; background: var(--card); }
.avatar.has-photo img { object-position: 50% 22%; }
@media (min-width: 56rem) { .avatar.has-photo { width: 13rem; height: 13rem; } }
/* ===== Факты, слова тэглайна, живые детали ===== */
.facts { display: flex; flex-wrap: wrap; gap: .35rem .9rem; font-size: .95rem; font-weight: 600; color: var(--ink); }
.facts li { display: inline-flex; align-items: center; gap: .3rem; }
.em { font-style: normal; }
.tagline .w { display: inline-block; }
.avatar { transition: transform .35s cubic-bezier(.3, 1.4, .5, 1); }
.avatar:hover { transform: rotate(3deg) scale(1.05); }
.link { position: relative; overflow: hidden; }
.link::before { content: ''; position: absolute; inset: 0 auto 0 -60%; width: 40%; background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .55), transparent); transform: skewX(-18deg) translateX(0); opacity: 0; pointer-events: none; }
.link:hover::before { opacity: 1; transform: skewX(-18deg) translateX(420%); transition: transform .8s ease, opacity .2s; }
/* ===== Внутренние страницы: шапка, проекты, галерея ===== */
.page.page--wide { max-width: 62rem; grid-template-columns: minmax(0, 1fr); align-items: start; gap: 3.5rem; }
.page-intro { display: grid; gap: .6rem; justify-items: start; }
.page-intro h1 { font-size: clamp(2.6rem, 11vw, 4.4rem); }
.lead { font-size: 1.2rem; color: var(--muted); max-width: 40rem; }
.proj { display: grid; gap: 1.5rem; }
.proj-head { display: grid; gap: .7rem; justify-items: start; max-width: 40rem; }
.proj-head h2 { font-size: clamp(1.8rem, 7vw, 2.6rem); }
.proj-head p { color: var(--muted); }
.meta { display: flex; flex-wrap: wrap; gap: .4rem; }
.meta li { padding: .25rem .7rem; border-radius: 99px; background: var(--accent-soft); color: var(--accent); font-weight: 700; font-size: .82rem; }
.gallery { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.1rem; }
.shot { margin: 0; min-width: 0; }
.shot a { display: block; overflow: hidden; border-radius: 22px; background: var(--card); box-shadow: var(--shadow); }
.shot img { width: 100%; height: auto; transition: transform .7s cubic-bezier(.22, .8, .2, 1); }
.shot a:hover img { transform: scale(1.03); }
.shot--plan img { padding: .8rem; background: #fff; }
.shot--portrait { max-width: 26rem; }
.shot figcaption { margin-top: .55rem; padding-inline: .35rem; font-size: .9rem; color: var(--muted); }
.soon { display: grid; gap: .3rem; padding: 1.4rem 1.5rem; border: 2px dashed var(--line); border-radius: 24px; color: var(--muted); }
.soon .hello { font-size: 1rem; color: var(--ink); font-weight: 700; }
@media (min-width: 48rem) {
.gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.4rem; }
.shot--lead, .shot--plan { grid-column: 1 / -1; }
.shot--portrait { grid-column: auto; }
.page.page--wide { gap: 5rem; }
}
/* ===== Страница проектов: игра ===== */
.game-feature { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.5rem; }
.game-shot { position: relative; display: block; border-radius: 26px; overflow: hidden; background: #0a0a0c; box-shadow: var(--shadow); }
.game-shot img { width: 100%; height: auto; transition: transform .8s cubic-bezier(.22, .8, .2, 1); }
.game-shot:hover img { transform: scale(1.04); }
.play { position: absolute; right: 1rem; bottom: 1rem; width: 3.4rem; height: 3.4rem; display: grid; place-items: center; border-radius: 50%; background: rgba(255, 255, 255, .92); color: #121a2b; font-size: 1.2rem; padding-left: .2rem; box-shadow: 0 10px 30px rgba(0, 0, 0, .35); transition: transform .25s cubic-bezier(.3, 1.4, .5, 1); }
.game-shot:hover .play { transform: scale(1.12); }
.game-body { display: grid; gap: .9rem; justify-items: start; }
.game-body h2 { font-size: clamp(2rem, 8vw, 3rem); }
.game-body p { color: var(--muted); max-width: 40rem; }
.game-body .lead { color: var(--ink); font-weight: 500; }
.actions { margin-top: .5rem; }
.btn { display: inline-flex; align-items: center; justify-content: center; min-height: 3.25rem; padding: 0 1.7rem; border-radius: 99px; font: 700 1.05rem var(--font); text-decoration: none; transition: transform .15s, box-shadow .2s, background .15s; -webkit-tap-highlight-color: transparent; }
.btn--primary { background: var(--accent); color: #fff; box-shadow: 0 8px 22px rgba(53, 86, 255, .35); }
.btn--primary:hover { background: #2443e0; transform: translateY(-2px); box-shadow: 0 12px 28px rgba(53, 86, 255, .4); }
.btn:active { transform: scale(.97); }
.game-extra { grid-column: 1 / -1; }
@media (min-width: 56rem) {
.game-feature { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: 2.5rem 3rem; align-items: center; }
.game-extra { grid-column: 1 / -1; max-width: 42rem; }
}
/* ===== Красивые анимации ===== */
@keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }
@keyframes drift-a { from { transform: translate(0, 0) scale(1); } to { transform: translate(-3rem, 4rem) scale(1.12); } }
@keyframes drift-b { from { transform: translate(0, 0) scale(1); } to { transform: translate(4rem, -3rem) scale(1.1); } }
@keyframes word { from { opacity: 0; transform: translateY(.7em) rotate(2deg); } to { opacity: 1; transform: none; } }
@keyframes pop-in { from { opacity: 0; transform: scale(.9) translateY(1rem); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: no-preference) {
.blob { will-change: transform; }
.blob--a { animation: drift-a 16s ease-in-out infinite alternate; }
.blob--b { animation: drift-b 20s ease-in-out infinite alternate; }
.tagline .w { animation: word .55s cubic-bezier(.22, .8, .2, 1) backwards; animation-delay: calc(.35s + var(--i, 0) * .06s); }
.facts li { animation: rise .5s cubic-bezier(.22, .8, .2, 1) backwards; }
.facts li:nth-child(1) { animation-delay: .25s; } .facts li:nth-child(2) { animation-delay: .3s; } .facts li:nth-child(3) { animation-delay: .35s; }
.tags li { animation: pop-in .5s cubic-bezier(.3, 1.4, .5, 1) backwards, float 4.5s ease-in-out infinite; }
.tags li:nth-child(1) { animation-delay: .8s, 1.4s; } .tags li:nth-child(2) { animation-delay: .9s, 2s; } .tags li:nth-child(3) { animation-delay: 1s, 2.6s; }
.page-intro > * { animation: rise .6s cubic-bezier(.22, .8, .2, 1) backwards; }
.page-intro > :nth-child(2) { animation-delay: .08s; } .page-intro > :nth-child(3) { animation-delay: .16s; }
.proj:first-of-type .proj-head > *, .game-body > * { animation: rise .6s cubic-bezier(.22, .8, .2, 1) backwards; }
.game-body > :nth-child(2) { animation-delay: .06s; } .game-body > :nth-child(3) { animation-delay: .12s; } .game-body > :nth-child(4) { animation-delay: .18s; }
.play { animation: pulse-ring 2.4s ease-out infinite; }
@keyframes pulse-ring { 0% { box-shadow: 0 10px 30px rgba(0, 0, 0, .35), 0 0 0 0 rgba(255, 255, 255, .6); } 70%, 100% { box-shadow: 0 10px 30px rgba(0, 0, 0, .35), 0 0 0 1.4rem rgba(255, 255, 255, 0); } }
}
/* появление по мере прокрутки: только там, где браузер умеет, без поддержки просто статика */
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {
.shot, .proj-head, .soon, .game-extra { animation: scroll-in linear both; animation-timeline: view(); animation-range: entry 0% entry 55%; }
.shot img { animation: img-settle linear both; animation-timeline: view(); animation-range: entry 0% cover 55%; }
@keyframes scroll-in { from { opacity: 0; transform: translateY(2.2rem) scale(.97); } to { opacity: 1; transform: none; } }
@keyframes img-settle { from { scale: 1.12; } to { scale: 1; } }
}
}
/* плавные переходы между страницами (Chrome, Safari 18.2+; в остальных просто обычный переход) */
@view-transition { navigation: auto; }
::view-transition-old(root) { animation: .22s ease both vt-out; }
::view-transition-new(root) { animation: .32s ease both vt-in; }
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; } }
/* компактное меню на узких телефонах, чтобы влезали все пункты */
@media (max-width: 30rem) {
.topnav { gap: .4rem; padding-inline: .8rem; }
.topnav .brand { font-size: .95rem; }
.topnav ul { gap: .1rem; }
.topnav .pill { padding: 0 .65rem; font-size: .9rem; }
}
/* первый кадр страницы виден сразу: без появления по прокрутке (быстрее LCP) */
@supports (animation-timeline: view()) { .proj:first-of-type .shot--lead, .proj:first-of-type .shot--lead img, .proj:first-of-type .proj-head { animation: none; } }
/* ===== Список проектов (карточки) ===== */
.works { display: grid; gap: 1.4rem; }
.work { display: grid; min-width: 0; overflow: hidden; border-radius: 28px; background: var(--card); color: inherit; text-decoration: none; box-shadow: var(--shadow); transition: transform .4s cubic-bezier(.22, .8, .2, 1), box-shadow .4s; -webkit-tap-highlight-color: transparent; }
.work .pic { aspect-ratio: 4 / 3; overflow: hidden; background: var(--bg); }
.work .pic img { width: 100%; height: 100%; object-fit: cover; transition: transform .9s cubic-bezier(.22, .8, .2, 1); }
.work .info { display: grid; gap: .55rem; justify-items: start; padding: 1.2rem 1.4rem 1.5rem; }
.work h2 { font-size: clamp(1.5rem, 6vw, 2rem); }
.work p { color: var(--muted); }
.work .more { margin-top: .3rem; font-weight: 700; color: var(--accent); }
.work .more span { display: inline-block; transition: transform .25s; }
.work:hover { transform: translateY(-5px); box-shadow: 0 20px 46px rgba(18, 26, 43, .15); }
.work:hover .pic img { transform: scale(1.06); }
.work:hover .more span { transform: translateX(5px); }
.work:active { transform: scale(.985); }
@media (min-width: 48rem) {
.works { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.6rem; }
.work--lead { grid-column: 1 / -1; grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); }
.work--lead .pic { aspect-ratio: auto; min-height: 24rem; }
.work--lead .info { align-content: center; padding: 2.2rem; }
.work--lead h2 { font-size: 2.6rem; }
}
/* ===== Страница проекта ===== */
.back { font-weight: 600; }
.back a { color: var(--muted); text-decoration: none; }
.back a:hover { color: var(--accent); }
.case-head { display: grid; gap: .8rem; justify-items: start; margin-top: -1.2rem; }
.case-head h1 { font-size: clamp(2.5rem, 11vw, 4.6rem); }
.gallery--one { grid-template-columns: minmax(0, 1fr); }
.shot--cover a { border-radius: 28px; }
.case-stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .8rem; }
.stat { display: grid; gap: .1rem; padding: 1rem 1.1rem; border-radius: 20px; background: var(--card); box-shadow: var(--shadow); }
.stat b { font-size: clamp(1.8rem, 8vw, 2.4rem); font-weight: 800; letter-spacing: -.03em; line-height: 1.1; color: var(--accent); font-variant-numeric: tabular-nums; }
.stat span { color: var(--muted); font-size: .9rem; }
.case-body { display: grid; gap: 1.1rem; max-width: 44rem; }
.case-body .intro { font-size: clamp(1.4rem, 5.5vw, 2rem); font-weight: 700; letter-spacing: -.02em; line-height: 1.2; color: var(--ink); max-width: none; }
.case-body h2 { margin-top: 1rem; font-size: clamp(1.4rem, 5vw, 1.8rem); }
.case-body p { color: var(--muted); font-size: 1.1rem; max-width: none; }
.case-block { display: grid; gap: 1.2rem; }
.block-title { font-size: clamp(1.5rem, 6vw, 2rem); }
.next-case { position: relative; display: grid; gap: .4rem; padding: 1.7rem; border-radius: 28px; background: var(--ink); color: #fff; text-decoration: none; overflow: hidden; transition: transform .3s cubic-bezier(.22, .8, .2, 1); }
.next-case .muted-w { color: rgba(255, 255, 255, .7); font-weight: 600; }
.next-title { font-size: clamp(1.8rem, 7vw, 3rem); font-weight: 800; letter-spacing: -.03em; line-height: 1.05; max-width: 90%; }
.next-arrow { position: absolute; right: 1.5rem; bottom: 1.4rem; font-size: 2rem; transition: transform .3s; }
.next-case:hover { transform: translateY(-3px); }
.next-case:hover .next-arrow { transform: translateX(8px); }
@media (min-width: 48rem) {
.case-head { margin-top: -2rem; }
.case-stats { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.shot--portrait { max-width: none; }
.next-case { padding: 2.4rem; }
}
/* первый кадр страницы проекта виден сразу, без анимации появления (быстрее LCP) */
@supports (animation-timeline: view()) { .gallery--one .shot, .gallery--one .shot img, .case-head, .back { animation: none; } }
/* если кадров нечётное число, последний занимает всю строку */
@media (min-width: 48rem) { .gallery > .shot:last-child:nth-child(odd) { grid-column: 1 / -1; } }
/* подсказка под кнопкой «Играть» */
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem 1.1rem; }
.note { font-size: .92rem; color: var(--muted); max-width: 24rem; }
/* на узких телефонах в шапке только имя, фамилия прячется, чтобы влезали все пункты */
@media (max-width: 26rem) { .topnav .brand-rest { display: none; } }
/* плитки «что живёт на сервере» */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: .9rem; }
.tile { display: grid; gap: .4rem; align-content: start; padding: 1.2rem 1.3rem; border-radius: 22px; background: var(--card); box-shadow: var(--shadow); color: inherit; text-decoration: none; transition: transform .3s cubic-bezier(.22, .8, .2, 1), box-shadow .3s; }
.tile h3 { font-size: 1.2rem; font-weight: 800; letter-spacing: -.02em; }
.tile p { color: var(--muted); font-size: .98rem; }
a.tile:hover { transform: translateY(-4px); box-shadow: 0 16px 36px rgba(18, 26, 43, .14); }
.tile .more { color: var(--accent); font-weight: 700; }
/* последняя плитка: «список открытый» */
.tile--more { background: transparent; box-shadow: none; border: 2px dashed var(--line); align-content: center; }
.tile--more h3 { color: var(--accent); }
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="9" fill="#ffd84d"/><text x="16" y="22.5" font-family="Arial, sans-serif" font-weight="800" font-size="17" text-anchor="middle" fill="#121a2b">А</text></svg>

After

Width:  |  Height:  |  Size: 251 B

+40
View File
@@ -0,0 +1,40 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Фикс: Аман Ибраш</title>
<meta name="description" content="Тут будет про фикс: байк, маршруты и километры.">
<meta name="robots" content="noindex"><!-- черновик: удалите эту строку при публикации -->
<meta name="theme-color" content="#f4f6fb">
<meta property="og:type" content="website">
<meta property="og:locale" content="ru_RU">
<meta property="og:title" content="Фикс: Аман Ибраш">
<meta property="og:description" content="Тут будет про фикс: байк, маршруты и километры.">
<meta property="og:image" content="https://example.com/og/home.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="preload" href="/fonts/onest-cyrillic-wght-normal.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/css/style.css">
<script src="/js/boot.js"></script>
</head>
<body class="doc has-nav">
<div class="blob blob--a" aria-hidden="true"></div>
<div class="blob blob--b" aria-hidden="true"></div>
<nav class="topnav" id="topnav" aria-label="Страницы"></nav>
<main class="page page--doc">
<article class="doc-card">
<h1>Фикс</h1>
<div class="prose">
<p>Тут будет про фикс: байк, маршруты и километры.</p>
<p>Страница в работе, скоро заполню. А пока <a href="/">вернись на главную</a>.</p>
</div>
</article>
</main>
<script src="/js/nav.js" defer></script>
</body>
</html>
+93
View File
@@ -0,0 +1,93 @@
Copyright 2021 The Onest Project Authors (https://github.com/simpals/onest)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

+34
View File
@@ -0,0 +1,34 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 630" role="img" aria-label="Иллюстрация: домашний сервер с тремя сервисами">
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#e8edff"/><stop offset="1" stop-color="#fdf3c8"/></linearGradient>
<linearGradient id="rack" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#1c2740"/><stop offset="1" stop-color="#101827"/></linearGradient>
</defs>
<rect width="1200" height="630" fill="url(#bg)"/>
<circle cx="1020" cy="110" r="150" fill="#ffd84d" opacity=".55"/>
<circle cx="150" cy="560" r="170" fill="#b9c8ff" opacity=".6"/>
<ellipse cx="600" cy="560" rx="250" ry="22" fill="#121a2b" opacity=".12"/>
<rect x="400" y="90" width="400" height="450" rx="30" fill="url(#rack)"/>
<g>
<rect x="428" y="120" width="344" height="86" rx="14" fill="#233152"/>
<rect x="428" y="222" width="344" height="86" rx="14" fill="#233152"/>
<rect x="428" y="324" width="344" height="86" rx="14" fill="#233152"/>
<rect x="428" y="426" width="344" height="86" rx="14" fill="#233152"/>
</g>
<g fill="#1fb865"><circle cx="458" cy="163" r="7"/><circle cx="458" cy="265" r="7"/><circle cx="458" cy="367" r="7"/></g>
<g fill="#3556ff"><circle cx="486" cy="163" r="7"/><circle cx="486" cy="265" r="7"/></g>
<g fill="#ffd84d"><circle cx="514" cy="163" r="7"/><circle cx="486" cy="469" r="7"/></g>
<g stroke="#3b4a70" stroke-width="5" stroke-linecap="round">
<path d="M600 150v26M630 150v26M660 150v26M690 150v26M720 150v26"/>
<path d="M600 252v26M630 252v26M660 252v26M690 252v26M720 252v26"/>
<path d="M600 354v26M630 354v26M660 354v26M690 354v26M720 354v26"/>
<path d="M600 456v26M630 456v26M660 456v26M690 456v26M720 456v26"/>
</g>
<g font-family="Onest, system-ui, Arial, sans-serif" font-weight="700" font-size="28">
<g><rect x="195" y="190" width="150" height="60" rx="30" fill="#fff"/><text x="270" y="229" text-anchor="middle" fill="#121a2b">файлы</text></g>
<g><rect x="215" y="300" width="150" height="60" rx="30" fill="#fff"/><text x="290" y="339" text-anchor="middle" fill="#121a2b">игра</text></g>
<g><rect x="855" y="250" width="150" height="60" rx="30" fill="#3556ff"/><text x="930" y="289" text-anchor="middle" fill="#fff">сайт</text></g>
</g>
<g stroke="#121a2b" stroke-width="3" stroke-linecap="round" opacity=".35" fill="none" stroke-dasharray="2 9">
<path d="M345 220 C370 220 385 238 400 250"/><path d="M365 330 C380 330 390 322 400 316"/><path d="M855 280 C835 280 820 278 800 275"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

+54
View File
@@ -0,0 +1,54 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Аман Ибраш: давай общаться</title>
<meta name="description" content="Тренировки, работа и фикс. Пиши, пообщаемся.">
<meta name="theme-color" content="#f4f6fb">
<meta property="og:type" content="website">
<meta property="og:locale" content="ru_RU">
<meta property="og:title" content="Аман Ибраш: давай общаться">
<meta property="og:description" content="Тренировки, работа и фикс. Пиши, пообщаемся.">
<meta property="og:image" content="https://example.com/og/home.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Аман Ибраш: давай общаться">
<meta name="twitter:description" content="Тренировки, работа и фикс. Пиши, пообщаемся.">
<meta name="twitter:image" content="https://example.com/og/home.png">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="preload" href="/fonts/onest-cyrillic-wght-normal.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/css/style.css">
<script src="/js/boot.js"></script>
</head>
<body data-hide>
<div class="blob blob--a" aria-hidden="true"></div>
<div class="blob blob--b" aria-hidden="true"></div>
<nav class="topnav" id="topnav" aria-label="Страницы"></nav>
<main class="page" id="page">
<section class="hero">
<div class="avatar" id="avatar" aria-hidden="true"><span id="initials">АИ</span></div>
<p class="hello">Привет <span class="wave" aria-hidden="true">👋</span></p>
<h1 id="name">Аман Ибраш</h1>
<p class="tagline" id="tagline">Админю серверы, качаюсь, кручу педали на фиксе и рисую здания. Скучать некогда.</p>
<ul class="facts" id="facts"></ul>
<ul class="tags" id="tags"></ul>
</section>
<section class="talk" aria-labelledby="h-talk">
<p class="status"><span class="dot" aria-hidden="true"></span><span id="status">на связи</span></p>
<h2 id="h-talk">Давай общаться</h2>
<p class="cta" id="cta">Хочешь пообщаться? Пиши, отвечу в течение пары дней.</p>
<ul class="links" id="links">
<li><a class="link link--mail" id="mail" href="mailto:hello@example.com"><span class="ic" aria-hidden="true">@</span><span class="lk">Почта</span><span class="lh">hello@example.com</span></a></li>
</ul>
</section>
</main>
<script src="/js/nav.js" defer></script>
<script src="/js/card.js" defer></script>
</body>
</html>
+10
View File
@@ -0,0 +1,10 @@
// Подключается в <head>: помечает «JS работает», сразу запрашивает config.json и даёт общий сигнал готовности
(function () {
var root = document.documentElement;
root.className += ' js';
window.siteReady = function () { root.classList.add('ready'); };
setTimeout(window.siteReady, 2000); // страховка: страница не останется скрытой
window.siteConfig = fetch('/config.json')
.then(function (r) { if (!r.ok) throw 0; return r.json(); })
.catch(function () { return null; });
})();
+52
View File
@@ -0,0 +1,52 @@
// Заполняет страницу из config.json
(function () {
var $ = function (id) { return document.getElementById(id); };
var make = function (tag, cls, text) { var n = document.createElement(tag); if (cls) n.className = cls; if (text) n.textContent = text; return n; };
var safe = function (u) { return /^https?:\/\//i.test(u) ? u : '#'; };
window.siteConfig.then(function (c) {
if (!c) return;
if (c.name) {
$('name').textContent = c.name;
document.title = c.name + ': давай общаться';
$('initials').textContent = c.name.split(/\s+/).map(function (w) { return w.charAt(0); }).join('').slice(0, 2).toUpperCase();
}
if (c.status) $('status').textContent = c.status;
if (c.tagline) {
// текст раскладывается на слова: каждое появляется по очереди (стили в css, .w)
var tg = $('tagline'); tg.textContent = '';
c.tagline.split(/\s+/).forEach(function (word, i, all) {
var w = make('span', 'w', word); w.style.setProperty('--i', i); tg.appendChild(w);
if (i < all.length - 1) tg.appendChild(document.createTextNode(' '));
});
}
(c.facts || []).forEach(function (f) {
var li = make('li'); li.appendChild(make('span', 'em', f.emoji || '')); li.appendChild(document.createTextNode(' ' + f.text));
$('facts').appendChild(li);
});
if (c.cta) $('cta').textContent = c.cta;
if (c.photo && /^\/[\w\-./]+$/.test(c.photo)) {
var img = document.createElement('img');
img.src = c.photo; img.alt = ''; img.width = 480; img.height = 480; img.fetchPriority = 'high';
$('avatar').textContent = ''; $('avatar').classList.add('has-photo'); $('avatar').appendChild(img);
}
(c.tags || []).forEach(function (t) {
var li = make('li');
li.appendChild(make('span', 'em', t.emoji || ''));
li.appendChild(document.createTextNode(' ' + t.text));
$('tags').appendChild(li);
});
var list = $('links'), mailLi = $('mail').parentNode;
(c.socials || []).forEach(function (s) {
var a = make('a', 'link');
a.href = safe(s.url); a.target = '_blank'; a.rel = 'me noopener';
a.appendChild(make('span', 'ic', (s.label || '?').charAt(0)));
a.appendChild(make('span', 'lk', s.label));
a.appendChild(make('span', 'lh', s.handle || ''));
var li = make('li'); li.appendChild(a);
list.insertBefore(li, mailLi);
});
if (c.email) { $('mail').href = 'mailto:' + c.email; $('mail').querySelector('.lh').textContent = c.email; }
}).then(window.siteReady);
})();
+20
View File
@@ -0,0 +1,20 @@
// Числа в карточках проекта «набегают» от нуля, когда появляются на экране. Без JS и при «уменьшить движение» остаются как есть.
(function () {
var nodes = document.querySelectorAll('[data-count]');
if (!nodes.length || !('IntersectionObserver' in window) || matchMedia('(prefers-reduced-motion: reduce)').matches) return;
var fmt = function (n, dec) { return n.toFixed(dec).replace('.', ','); };
var run = function (el) {
var raw = el.getAttribute('data-count'), end = parseFloat(raw), dec = (raw.split('.')[1] || '').length;
if (isNaN(end)) return;
var t0 = performance.now(), dur = 900;
(function step(now) {
var k = Math.min(1, (now - t0) / dur), e = 1 - Math.pow(1 - k, 3);
el.textContent = fmt(end * e, dec);
if (k < 1) requestAnimationFrame(step);
})(t0);
};
var io = new IntersectionObserver(function (items) {
items.forEach(function (it) { if (it.isIntersecting) { run(it.target); io.unobserve(it.target); } });
}, { threshold: 0.6 });
nodes.forEach(function (n) { io.observe(n); });
})();
+31
View File
@@ -0,0 +1,31 @@
// Верхнее меню из config.json: pages. На главной показывается, только если есть страницы; на остальных всегда.
(function () {
window.siteConfig.then(function (c) {
var nav = document.getElementById('topnav');
if (nav && c) {
var pages = (c.pages || []).filter(function (p) { return !p.draft; }); // черновики в меню не попадают
var norm = function (p) { return p.replace(/\/+$/, '') + '/'; };
var here = norm(location.pathname);
var home = here === '/';
if (pages.length || !home) {
var brand = document.createElement('a');
brand.className = 'brand'; brand.href = '/';
var parts = (c.name || 'Главная').split(' ');
brand.appendChild(document.createTextNode(parts[0]));
if (parts.length > 1) { var rest = document.createElement('span'); rest.className = 'brand-rest'; rest.textContent = ' ' + parts.slice(1).join(' '); brand.appendChild(rest); }
nav.appendChild(brand);
var ul = document.createElement('ul');
pages.forEach(function (p) {
if (!/^\/[\w\-./]*$/.test(p.url)) return; // только внутренние адреса
var a = document.createElement('a');
a.className = 'pill'; a.href = p.url; a.textContent = p.label;
var u = norm(p.url);
if (u === here || (u !== '/' && here.indexOf(u) === 0)) a.setAttribute('aria-current', 'page');
var li = document.createElement('li'); li.appendChild(a); ul.appendChild(li);
});
nav.appendChild(ul);
document.body.classList.add('has-nav');
}
}
}).then(window.siteReady);
})();
Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

+81
View File
@@ -0,0 +1,81 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Aman&#x27;s World: Аман Ибраш</title>
<meta name="description" content="Aman&#x27;s World: 3D-игра с паркуром и гонками, которая запускается прямо в браузере. Неоновый хаб, гонки Sector 3 Run и Ascend Only.">
<meta name="theme-color" content="#f4f6fb">
<meta property="og:type" content="website">
<meta property="og:locale" content="ru_RU">
<meta property="og:title" content="Aman&#x27;s World: Аман Ибраш">
<meta property="og:description" content="Aman&#x27;s World: 3D-игра с паркуром и гонками, которая запускается прямо в браузере. Неоновый хаб, гонки Sector 3 Run и Ascend Only.">
<meta property="og:image" content="https://example.com/og/projects-amans-world.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Aman&#x27;s World: Аман Ибраш">
<meta name="twitter:description" content="Aman&#x27;s World: 3D-игра с паркуром и гонками, которая запускается прямо в браузере. Неоновый хаб, гонки Sector 3 Run и Ascend Only.">
<meta name="twitter:image" content="https://example.com/og/projects-amans-world.jpg">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="preload" href="/fonts/onest-cyrillic-wght-normal.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/css/style.css">
<script src="/js/boot.js"></script>
</head>
<body class="doc has-nav">
<div class="blob blob--a" aria-hidden="true"></div>
<div class="blob blob--b" aria-hidden="true"></div>
<nav class="topnav" id="topnav" aria-label="Страницы"></nav>
<main class="page page--wide">
<p class="back"><a href="/projects/">← Проекты</a></p>
<header class="case-head">
<ul class="meta"><li>3D</li><li>в браузере</li><li>только на ПК</li><li>Godot 4</li></ul>
<h1>Aman&#x27;s World</h1>
<p class="lead">Паркур и гонки в неоновом городе. Запускается прямо в браузере.</p>
<div class="actions"><a class="btn btn--primary" href="https://grid.ibrash.duckdns.org/" target="_blank" rel="noopener">Играть</a><p class="note">Работает только на компьютере. Можно играть с геймпадом (Xbox).</p></div>
</header>
<div class="gallery gallery--one">
<figure class="shot shot--cover shot--lead">
<a href="/img/proj/game-ascend.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Ascend Only: старт трассы вверх, 13 чекпоинтов"><img src="/img/proj/game-ascend-md.webp" srcset="/img/proj/game-ascend-sm.webp 640w, /img/proj/game-ascend-md.webp 960w, /img/proj/game-ascend.webp 1600w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1600" height="900" alt="Ascend Only: старт трассы вверх, 13 чекпоинтов" fetchpriority="high"></a>
<figcaption>Ascend Only: старт трассы вверх, 13 чекпоинтов</figcaption>
</figure>
</div>
<ul class="case-stats"><li class="stat"><b data-count="5">5</b><span>порталов в хабе</span></li><li class="stat"><b data-count="8">8</b><span>чекпоинтов, Sector 3 Run</span></li><li class="stat"><b data-count="13">13</b><span>чекпоинтов, Ascend Only</span></li><li class="stat"><b data-count="40">40</b><span>МБ при первом запуске</span></li></ul>
<section class="case-body">
<p class="intro">Игра, в которую можно зайти по ссылке. Без установки и без регистрации.</p>
<h2>Неоновый хаб</h2><p>Ты начинаешь в хабе: зал с неоновыми колоннами, вращающейся скульптурой-атомом и порталами на карты. Над гоночными порталами висят таблицы рекордов. Перед входом вводишь ник до 16 символов.</p><h2>Паркур</h2><p>Движение собрано под паркур: бег, прыжок, двойной прыжок, рывок, скольжение, бег по стенам, прыжок от стены и подтягивание на уступы. На трассах лежат полосы-ускорители.</p><h2>Две гоночные трассы</h2><p>Sector 3 Run гонит по вечернему оранжевому городу, на трассе 8 чекпоинтов. Ascend Only ведёт всё выше по фиолетовому ночному городу, там 13 чекпоинтов. Перед стартом нажимаешь R, то есть «готов», а счётчик (0/1) показывает, сколько игроков готово. Время идёт, и побеждает самый быстрый.</p><h2>На чём играть</h2><p>Игра работает только на компьютере, на телефоне она не запустится. Управлять можно клавиатурой и мышью или геймпадом вроде Xbox.</p><h2>Песочница и Backrooms</h2><p>Ещё из хаба можно уйти в песочницу, где просто отрабатываешь движение, и на карту Backrooms.</p><h2>Под капотом</h2><p>Игру я сделал сам на движке Godot 4 и выложил на свой сервер. При первом запуске браузер загружает около 40 МБ, зато потом всё работает быстро.</p>
</section>
<section class="case-block" aria-label="Кадры из игры">
<h2 class="block-title">Кадры из игры</h2>
<div class="gallery">
<figure class="shot">
<a href="/img/proj/game-sector3.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Sector 3 Run: старт трассы, 8 чекпоинтов"><img src="/img/proj/game-sector3-md.webp" srcset="/img/proj/game-sector3-sm.webp 640w, /img/proj/game-sector3-md.webp 960w, /img/proj/game-sector3.webp 1600w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1600" height="900" alt="Sector 3 Run: старт трассы, 8 чекпоинтов" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>Sector 3 Run: старт трассы, 8 чекпоинтов</figcaption>
</figure>
<figure class="shot">
<a href="/img/proj/game-hub.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Хаб: порталы Sandbox, Backrooms, Race и Race 2"><img src="/img/proj/game-hub-md.webp" srcset="/img/proj/game-hub-sm.webp 640w, /img/proj/game-hub-md.webp 960w, /img/proj/game-hub.webp 1280w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1280" height="720" alt="Хаб: порталы Sandbox, Backrooms, Race и Race 2" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>Хаб: порталы Sandbox, Backrooms, Race и Race 2</figcaption>
</figure>
<figure class="shot shot--wide">
<a href="/img/proj/game-splash.webp" target="_blank" rel="noopener" aria-label="Открыть крупно: Заставка игры"><img src="/img/proj/game-splash-md.webp" srcset="/img/proj/game-splash-sm.webp 640w, /img/proj/game-splash-md.webp 960w, /img/proj/game-splash.webp 1280w" sizes="(min-width: 62rem) 62rem, calc(100vw - 2.2rem)" width="1280" height="720" alt="Заставка игры" loading="lazy" decoding="async" fetchpriority="low"></a>
<figcaption>Заставка игры</figcaption>
</figure>
</div>
</section>
<aside class="soon">
<p class="hello">Готов проверить?</p>
<p>Зайди, выбери портал и попробуй пробежать трассу. Перед гонкой не забудь нажать R.</p>
<div class="actions"><a class="btn btn--primary" href="https://grid.ibrash.duckdns.org/" target="_blank" rel="noopener">Играть в Aman's World</a></div>
</aside>
</main>
<script src="/js/nav.js" defer></script>
<script src="/js/count.js" defer></script>
</body>
</html>
+71
View File
@@ -0,0 +1,71 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Хоумлаб: Аман Ибраш</title>
<meta name="description" content="Мой домашний сервер и Fedora Linux: Nextcloud, моя игра и эксперименты, на которых я учусь DevOps.">
<meta name="theme-color" content="#f4f6fb">
<meta property="og:type" content="website">
<meta property="og:locale" content="ru_RU">
<meta property="og:title" content="Хоумлаб: Аман Ибраш">
<meta property="og:description" content="Мой домашний сервер и Fedora Linux: Nextcloud, моя игра и эксперименты, на которых я учусь DevOps.">
<meta property="og:image" content="https://example.com/og/projects-homelab.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Хоумлаб: Аман Ибраш">
<meta name="twitter:description" content="Мой домашний сервер и Fedora Linux: Nextcloud, моя игра и эксперименты, на которых я учусь DevOps.">
<meta name="twitter:image" content="https://example.com/og/projects-homelab.jpg">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="preload" href="/fonts/onest-cyrillic-wght-normal.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/css/style.css">
<script src="/js/boot.js"></script>
</head>
<body class="doc has-nav">
<div class="blob blob--a" aria-hidden="true"></div>
<div class="blob blob--b" aria-hidden="true"></div>
<nav class="topnav" id="topnav" aria-label="Страницы"></nav>
<main class="page page--wide">
<p class="back"><a href="/projects/">← Проекты</a></p>
<header class="case-head">
<ul class="meta"><li>дома</li><li>Linux</li><li>Fedora</li></ul>
<h1>Хоумлаб</h1>
<p class="lead">Мой домашний сервер и Linux, на котором я всё делаю.</p>
</header>
<div class="gallery gallery--one">
<figure class="shot shot--cover shot--lead">
<a href="/img/proj/homelab-cover.svg" target="_blank" rel="noopener" aria-label="Открыть иллюстрацию крупно"><img src="/img/proj/homelab-cover.svg" width="1200" height="630" alt="Иллюстрация: домашний сервер с тремя сервисами" fetchpriority="high"></a>
</figure>
</div>
<section class="case-body">
<p class="intro">Свой маленький интернет у меня дома.</p>
<h2>Что это</h2>
<p>Хоумлаб — это мой домашний сервер. Я работаю системным администратором и расту в сторону DevOps, поэтому держу дома место, где можно пробовать всё на настоящем железе.</p>
<p>Дома можно спокойно пробовать, ломать и чинить. Так я учусь автоматизации и всему, что окружает современный сервер.</p>
</section>
<section class="case-block" aria-label="Что живёт на сервере">
<h2 class="block-title">Что на нём живёт</h2>
<div class="tiles">
<div class="tile"><h3>Nextcloud</h3><p>Мои файлы и проекты лежат у меня, а не в чужом облаке.</p></div>
<a class="tile" href="/projects/amans-world/"><h3>Aman's World</h3><p>Моя браузерная игра запускается с этого сервера.</p><span class="more">Смотреть игру →</span></a>
<div class="tile"><h3>DuckDNS</h3><p>Бесплатные адреса, чтобы до домашнего сервера можно было достучаться снаружи.</p></div>
<div class="tile"><h3>Этот сайт</h3><p>Он тоже переезжает сюда. Выкладку хочу автоматизировать через CI.</p></div>
<div class="tile tile--more"><h3>И много чего ещё</h3><p>Список растёт: я постоянно что-то поднимаю и пробую.</p></div>
</div>
</section>
<section class="case-body">
<h2>Fedora Linux</h2>
<p>На своём компьютере я пользуюсь Fedora Linux. В ней я учусь, работаю и делаю свои проекты, в том числе этот сайт.</p>
</section>
</main>
<script src="/js/nav.js" defer></script>
<script src="/js/count.js" defer></script>
</body>
</html>
+67
View File
@@ -0,0 +1,67 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Проекты: Аман Ибраш</title>
<meta name="description" content="Мои проекты: Aman&#x27;s World, 3D-игра с паркуром и гонками, которая запускается прямо в браузере.">
<meta name="theme-color" content="#f4f6fb">
<meta property="og:type" content="website">
<meta property="og:locale" content="ru_RU">
<meta property="og:title" content="Проекты: Аман Ибраш">
<meta property="og:description" content="Мои проекты: Aman&#x27;s World, 3D-игра с паркуром и гонками, которая запускается прямо в браузере.">
<meta property="og:image" content="https://example.com/og/projects.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Проекты: Аман Ибраш">
<meta name="twitter:description" content="Мои проекты: Aman&#x27;s World, 3D-игра с паркуром и гонками, которая запускается прямо в браузере.">
<meta name="twitter:image" content="https://example.com/og/projects.jpg">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="preload" href="/fonts/onest-cyrillic-wght-normal.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/css/style.css">
<script src="/js/boot.js"></script>
</head>
<body class="doc has-nav">
<div class="blob blob--a" aria-hidden="true"></div>
<div class="blob blob--b" aria-hidden="true"></div>
<nav class="topnav" id="topnav" aria-label="Страницы"></nav>
<main class="page page--wide">
<header class="page-intro">
<p class="hello">Проекты</p>
<h1>Что я делаю</h1>
<p class="lead">Кроме учёбы и работы я собираю свои штуки. Выбери проект и загляни внутрь.</p>
</header>
<section class="works" aria-label="Проекты">
<a class="work work--lead" href="/projects/amans-world/">
<div class="pic"><img src="/img/proj/game-ascend-md.webp" srcset="/img/proj/game-ascend-sm.webp 640w, /img/proj/game-ascend-md.webp 960w, /img/proj/game-ascend.webp 1600w" sizes="(min-width: 62rem) 50vw, calc(100vw - 2.2rem)" width="1600" height="900" alt="Aman's World: старт трассы Ascend Only" fetchpriority="high"></div>
<div class="info">
<ul class="meta"><li>3D</li><li>в браузере</li><li>только на ПК</li><li>Godot 4</li></ul>
<h2>Aman's World</h2>
<p>Паркур и гонки в неоновом городе. Запускается прямо в браузере, ничего ставить не надо.</p>
<span class="more">Смотреть проект <span aria-hidden="true">→</span></span>
</div>
</a>
<a class="work work--lead" href="/projects/homelab/">
<div class="pic"><img src="/img/proj/homelab-cover.svg" width="1200" height="630" alt="Иллюстрация: домашний сервер с тремя сервисами" loading="lazy" decoding="async"></div>
<div class="info">
<ul class="meta"><li>дома</li><li>Linux</li><li>Fedora</li></ul>
<h2>Хоумлаб</h2>
<p>Мой домашний сервер: файлы, игра и эксперименты. И Linux, на котором я всё делаю.</p>
<span class="more">Смотреть проект <span aria-hidden="true">→</span></span>
</div>
</a>
</section>
<aside class="soon">
<p class="hello">Дальше</p>
<p>Тут появятся новые проекты, как только доделаю. Заглядывай.</p>
</aside>
</main>
<script src="/js/nav.js" defer></script>
<script src="/js/count.js" defer></script>
</body>
</html>
+4
View File
@@ -0,0 +1,4 @@
User-agent: *
Allow: /
Sitemap: https://example.com/sitemap.xml
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url><loc>https://example.com/</loc></url>
<url><loc>https://example.com/arch/</loc></url>
<url><loc>https://example.com/projects/</loc></url>
<url><loc>https://example.com/arch/quiet-courtyard/</loc></url>
<url><loc>https://example.com/arch/exhibition-pavilion/</loc></url>
<url><loc>https://example.com/arch/loft-complex/</loc></url>
<url><loc>https://example.com/projects/amans-world/</loc></url>
<url><loc>https://example.com/projects/homelab/</loc></url>
</urlset>
+40
View File
@@ -0,0 +1,40 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Тренировки: Аман Ибраш</title>
<meta name="description" content="Тут будет про тренировки: что делаю, как часто и во сколько встаю.">
<meta name="robots" content="noindex"><!-- черновик: удалите эту строку при публикации -->
<meta name="theme-color" content="#f4f6fb">
<meta property="og:type" content="website">
<meta property="og:locale" content="ru_RU">
<meta property="og:title" content="Тренировки: Аман Ибраш">
<meta property="og:description" content="Тут будет про тренировки: что делаю, как часто и во сколько встаю.">
<meta property="og:image" content="https://example.com/og/home.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="preload" href="/fonts/onest-cyrillic-wght-normal.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/css/style.css">
<script src="/js/boot.js"></script>
</head>
<body class="doc has-nav">
<div class="blob blob--a" aria-hidden="true"></div>
<div class="blob blob--b" aria-hidden="true"></div>
<nav class="topnav" id="topnav" aria-label="Страницы"></nav>
<main class="page page--doc">
<article class="doc-card">
<h1>Тренировки</h1>
<div class="prose">
<p>Тут будет про тренировки: что делаю, как часто и во сколько встаю.</p>
<p>Страница в работе, скоро заполню. А пока <a href="/">вернись на главную</a>.</p>
</div>
</article>
</main>
<script src="/js/nav.js" defer></script>
</body>
</html>
+40
View File
@@ -0,0 +1,40 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Работа: Аман Ибраш</title>
<meta name="description" content="Тут будет про работу: чем занимаюсь и куда расту.">
<meta name="robots" content="noindex"><!-- черновик: удалите эту строку при публикации -->
<meta name="theme-color" content="#f4f6fb">
<meta property="og:type" content="website">
<meta property="og:locale" content="ru_RU">
<meta property="og:title" content="Работа: Аман Ибраш">
<meta property="og:description" content="Тут будет про работу: чем занимаюсь и куда расту.">
<meta property="og:image" content="https://example.com/og/home.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="preload" href="/fonts/onest-cyrillic-wght-normal.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/css/style.css">
<script src="/js/boot.js"></script>
</head>
<body class="doc has-nav">
<div class="blob blob--a" aria-hidden="true"></div>
<div class="blob blob--b" aria-hidden="true"></div>
<nav class="topnav" id="topnav" aria-label="Страницы"></nav>
<main class="page page--doc">
<article class="doc-card">
<h1>Работа</h1>
<div class="prose">
<p>Тут будет про работу: чем занимаюсь и куда расту.</p>
<p>Страница в работе, скоро заполню. А пока <a href="/">вернись на главную</a>.</p>
</div>
</article>
</main>
<script src="/js/nav.js" defer></script>
</body>
</html>