Files
site-portfolio/public/en/cases/template-elements-demo/index.html
T
root a0dda98b83 i18n: build-time ru/en localization + EN homepage & cookie-policy
- build-pages.mjs: per-locale page/partial overrides (*.en.html), i18n token
  resolution with ru fallback, <html lang> + assetPrefix per locale
- UI dictionaries src/i18n/{ru,en}.json; lang-switch partial
- headers/footer/partials converted to {{i18n:…}} tokens
- root-absolute static asset refs so /en/ subpath loads css/js/vendor
- EN content: homepage (index.en.html + partials) and cookie-policy.en.html
  (cookie-policy body translated via apinex.bond /v1/tools/translator)
2026-09-15 22:27:51 +02:00

1153 lines
74 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en" data-theme="dark" data-radius="medium" data-font="merriweather">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta name="description" content="Демо-страница кейса со всеми разработанными элементами: карточки ссылок и медиа-блоки." />
<title>Демо элементов кейса — template</title>
<script>
(function () {
var FONT_CSS = {
merriweather: "/assets/fonts/merriweather.css",
geologica: "/assets/fonts/geologica.css",
mono: "/assets/fonts/mono.css",
};
try {
var t = JSON.parse(localStorage.getItem("siteThemeV1") || "{}");
var d = document.documentElement;
var m = t.mode;
if (m !== "light" && m !== "dark" && m !== "system") m = "system";
var eff =
m === "system"
? window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light"
: m;
d.dataset.theme = eff;
var h = typeof t.h === "number" ? t.h : typeof t.hue === "number" ? t.hue : null;
var s = typeof t.s === "number" ? t.s : typeof t.sat === "number" ? t.sat : null;
var l = typeof t.l === "number" ? t.l : typeof t.light === "number" ? t.light : null;
if (h !== null) d.style.setProperty("--theme-h", String(h));
if (s !== null) d.style.setProperty("--theme-s", String(s));
if (l !== null) {
var L = Number(l);
if (Number.isFinite(L)) d.style.setProperty("--theme-l", String(Math.min(70, Math.max(20, L))));
}
var hVal = h !== null ? h : 210;
var sVal = s !== null ? s : 90;
var lVal = l !== null ? Math.min(70, Math.max(20, Number(l))) : 40;
var H = (((hVal % 360) + 360) % 360) / 360;
var S = Math.min(100, Math.max(0, sVal)) / 100;
var Lv = Math.min(100, Math.max(0, lVal)) / 100;
var r, g, b;
if (S === 0) { r = g = b = Lv; }
else {
var q = Lv < 0.5 ? Lv * (1 + S) : Lv + S - Lv * S;
var p = 2 * Lv - q;
var hue2rgb = function(p, q, t) {
if (t < 0) t += 1; if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
r = hue2rgb(p, q, H + 1/3);
g = hue2rgb(p, q, H);
b = hue2rgb(p, q, H - 1/3);
}
var lum = 0.2126 * r + 0.7152 * g + 0.0722 * b;
d.style.setProperty("--on-accent", lum > 0.58 ? "hsl(220 14% 12%)" : "hsl(0 0% 98%)");
var rad = t.radius;
if (rad === "soft" || rad === "medium" || rad === "strong") {
d.dataset.radius = rad;
} else {
d.dataset.radius = "medium";
}
var f = t.font;
if (f === "onest") f = "geologica";
if (f === "anonymous") f = "mono";
if (f !== "merriweather" && f !== "mono" && f !== "geologica") f = "merriweather";
d.dataset.font = f;
var mb = t.meshBg;
if (mb === "off") {
d.dataset.meshBg = "off";
} else {
d.dataset.meshBg = "on";
}
var href = FONT_CSS[f];
if (href && !document.querySelector('link[data-theme-font="' + f + '"]')) {
var link = document.createElement("link");
link.rel = "stylesheet";
link.href = href;
link.setAttribute("data-theme-font", f);
document.head.appendChild(link);
}
} catch (e) {}
})();
</script>
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon/favicon-16x16.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicon/apple-touch-icon.png" />
<link rel="manifest" href="/assets/favicon/site.webmanifest" />
<link rel="preload" href="/assets/fonts/merriweather.css" as="style" />
<link rel="preload" href="/css/main.css" as="style" />
<link rel="preload" href="/js/skill-connectors.js" as="script" />
<link rel="modulepreload" href="/js/main.js" />
<link rel="stylesheet" href="/css/main.css" />
<script src="/js/skill-connectors.js" defer></script>
<script type="module" src="/js/main.js"></script>
<link rel="stylesheet" href="/vendor/plyr/plyr.css" />
<style>
.case-article {
max-width: 48rem;
margin: 0 auto;
}
.case-article h2 {
margin: 2rem 0 0.75rem;
font-size: clamp(1.15rem, 2vw, 1.35rem);
font-weight: 700;
color: var(--text);
}
.case-article h3 {
font-size: 1.05rem;
font-weight: 600;
color: var(--text);
}
.case-article .section__prose {
margin-bottom: 0.75rem;
color: var(--text);
}
.case-article a:not(.btn) {
color: var(--accent);
}
</style>
<script>
(function () {
try {
var t = JSON.parse(localStorage.getItem("siteThemeV1") || "{}");
var d = document.documentElement;
var m = t.mode;
if (m !== "light" && m !== "dark" && m !== "system") m = "system";
var eff =
m === "system"
? window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light"
: m;
d.dataset.theme = eff;
var h = typeof t.h === "number" ? t.h : typeof t.hue === "number" ? t.hue : null;
var s = typeof t.s === "number" ? t.s : typeof t.sat === "number" ? t.sat : null;
var l = typeof t.l === "number" ? t.l : typeof t.light === "number" ? t.light : null;
if (h !== null) d.style.setProperty("--theme-h", String(h));
if (s !== null) d.style.setProperty("--theme-s", String(s));
if (l !== null) {
var L = Number(l);
if (Number.isFinite(L)) d.style.setProperty("--theme-l", String(Math.min(70, Math.max(20, L))));
}
var rad = t.radius;
if (rad === "soft" || rad === "medium" || rad === "strong") {
d.dataset.radius = rad;
} else {
d.dataset.radius = "medium";
}
var f = t.font;
if (f === "onest") f = "geologica";
if (f === "anonymous") f = "mono";
if (f === "merriweather" || f === "mono" || f === "geologica") {
d.dataset.font = f;
} else {
d.dataset.font = "merriweather";
}
var mb = t.meshBg;
if (mb === "off") {
d.dataset.meshBg = "off";
} else {
d.dataset.meshBg = "on";
}
} catch (e) {}
})();
</script>
</head>
<body>
<a class="skip-link" href="#main">Skip to main content</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../../" aria-label="Home">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Page sections">
<a href="../../../">Home</a>
</nav>
<nav class="lang-switch" aria-label="Choose language" data-lang-switch>
<a class="lang-switch__btn" data-lang="ru" href="/">RU</a>
<a class="lang-switch__btn" data-lang="en" href="/en/">EN</a>
</nav>
<script>
(function () {
var p = location.pathname.replace(/^\/+/, "");
var isEn = p.indexOf("en/") === 0;
var base = isEn ? p.slice(3) : p;
var links = document.querySelectorAll("[data-lang-switch] [data-lang]");
for (var i = 0; i < links.length; i++) {
var b = links[i];
var l = b.getAttribute("data-lang");
b.setAttribute("href", (l === "en" ? "/en/" : "/") + base);
if ((l === "en") === isEn) b.setAttribute("aria-current", "true");
}
})();
</script>
</div>
</div>
</header>
<div class="fab-stack" aria-label="Быстрые действия">
<div class="theme-panel-fab-wrap">
<button type="button" class="fab fab--secondary glass-neutral" data-theme-panel-btn aria-expanded="false" aria-controls="theme-panel" aria-label="Настройки стиля">
<span class="theme-panel-fab__icon theme-panel-fab__icon--open-hide" aria-hidden="true"></span>
<svg class="theme-panel-fab__icon theme-panel-fab__icon--close" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path d="M6 6L18 18M18 6L6 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
</svg>
</button>
<div id="theme-panel" class="theme-picker__panel glass-neutral" role="dialog" aria-label="Тема и оформление" hidden data-theme-panel>
<div class="theme-picker__stack">
<section class="theme-picker__section" aria-labelledby="theme-accent-title">
<h3 id="theme-accent-title" class="theme-picker__section-title">Акцентный цвет</h3>
<div class="colorpicker" data-colorpicker>
<div class="colorpicker__plane-box">
<canvas class="colorpicker__plane" width="320" height="180" data-sl-canvas aria-label="Насыщенность и светлость акцента"></canvas>
<div class="colorpicker__knob" data-sl-knob></div>
</div>
<div class="colorpicker__hue-wrap">
<label class="colorpicker__hue-sr" for="theme-hue-slider">Оттенок акцента</label>
<input id="theme-hue-slider" class="colorpicker__hue" type="range" min="0" max="360" value="210" data-hue-slider aria-valuemin="0" aria-valuemax="360" />
</div>
</div>
</section>
<section class="theme-picker__section" aria-labelledby="theme-mode-title">
<h3 id="theme-mode-title" class="theme-picker__section-title">Тема</h3>
<div class="radius-seg theme-mode-seg" role="radiogroup" aria-labelledby="theme-mode-title">
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-theme-mode="system" aria-label="Как в системе"><span class="radius-seg__viz" aria-hidden="true"><span class="theme-mode-seg__ico theme-mode-seg__ico--system"></span></span></button>
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-theme-mode="light" aria-label="Светлая тема"><span class="radius-seg__viz" aria-hidden="true"><span class="theme-mode-seg__ico theme-mode-seg__ico--light"></span></span></button>
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-theme-mode="dark" aria-label="Тёмная тема"><span class="radius-seg__viz" aria-hidden="true"><span class="theme-mode-seg__ico theme-mode-seg__ico--dark"></span></span></button>
</div>
</section>
<section class="theme-picker__section" aria-labelledby="theme-radius-title">
<h3 id="theme-radius-title" class="theme-picker__section-title">Скругление углов</h3>
<div class="radius-seg" role="radiogroup" aria-labelledby="theme-radius-title">
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-radius-option="soft" aria-label="Слабое скругление"><span class="radius-seg__viz" aria-hidden="true"><span class="radius-seg__arc radius-seg__arc--soft"></span></span></button>
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-radius-option="medium" aria-label="Среднее скругление"><span class="radius-seg__viz" aria-hidden="true"><span class="radius-seg__arc radius-seg__arc--medium"></span></span></button>
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-radius-option="strong" aria-label="Сильное скругление"><span class="radius-seg__viz" aria-hidden="true"><span class="radius-seg__arc radius-seg__arc--strong"></span></span></button>
</div>
</section>
<section class="theme-picker__section" aria-labelledby="theme-typography-title">
<h3 id="theme-typography-title" class="theme-picker__section-title">Типографика</h3>
<div class="radius-seg" role="radiogroup" aria-labelledby="theme-typography-title">
<button type="button" class="radius-seg__btn theme-font-seg__btn" role="radio" aria-checked="false" data-font-option="geologica" aria-label="Sans"><span class="theme-font-seg__label">Sans</span></button>
<button type="button" class="radius-seg__btn theme-font-seg__btn" role="radio" aria-checked="false" data-font-option="merriweather" aria-label="Sans Serif"><span class="theme-font-seg__label">Sans Serif</span></button>
<button type="button" class="radius-seg__btn theme-font-seg__btn" role="radio" aria-checked="false" data-font-option="mono" aria-label="Mono"><span class="theme-font-seg__label">Mono</span></button>
</div>
</section>
<section class="theme-picker__section" aria-labelledby="theme-mesh-bg-title">
<h3 id="theme-mesh-bg-title" class="theme-picker__section-title">Фон страницы</h3>
<div class="radius-seg radius-seg--two" role="radiogroup" aria-labelledby="theme-mesh-bg-title">
<button type="button" class="radius-seg__btn theme-mesh-bg-seg__btn" role="radio" aria-checked="false" data-mesh-bg-option="on" aria-label="Показать фоновый градиент"><span class="theme-mesh-bg-seg__label">Вкл</span></button>
<button type="button" class="radius-seg__btn theme-mesh-bg-seg__btn" role="radio" aria-checked="false" data-mesh-bg-option="off" aria-label="Скрыть фоновый градиент"><span class="theme-mesh-bg-seg__label">Выкл</span></button>
</div>
</section>
</div>
</div>
</div>
<a class="fab fab--primary" href="../../../#contact" aria-label="Связаться">
<span class="fab-primary__ico" aria-hidden="true"></span>
</a>
</div>
<div class="content-edit-fab-stack" aria-label="Правки контента" data-content-edit-ui>
<button
type="button"
class="fab fab--secondary glass-neutral content-edit-fab"
data-content-edit-mode-toggle
hidden
aria-pressed="false"
aria-label="Режим правок контента"
title="Режим правок"
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M4 20h4l10.5-10.5a2.12 2.12 0 0 0 0-3L16.5 4.5a2.12 2.12 0 0 0-3 0L3 15v5z"
stroke="currentColor"
stroke-width="1.75"
stroke-linejoin="round"
/>
</svg>
<span class="content-edit-fab__badge" hidden aria-hidden="true">0</span>
</button>
</div>
<main id="main" class="section section--tight">
<div class="section__inner case-article">
<p class="hero__eyebrow">Демо · template</p>
<h1 class="case-page__h1">Пример кейса: демо элементов</h1>
<p class="case-page__sub">Рыба-текст и блоки для быстрой сборки лонгрида</p>
<p class="section__prose case-page__code">Медиа для демо лежат в <code>public/assets/</code> (сборка страниц их не копирует). См. <code>public/assets/README.md</code>.</p>
<h2>Контекст</h2>
<p class="section__prose">
Этот раздел показывает пример рыбы для вступления. Здесь можно коротко описать продукт, аудиторию и ограничения проекта.
Текст нейтральный: цель — быстро набросать структуру и проверить визуальный ритм страницы.
</p>
<h2>Задача</h2>
<p class="section__prose">
Нужно собрать демонстрационный лонгрид с основными UI-элементами: карточками ссылок, медиа-блоками и примерами оформления контента.
Дополнительно важно проверить, как блоки ведут себя на узких и широких экранах.
</p>
<h2>Решение</h2>
<p class="section__prose">Ниже собраны готовые примеры, которые можно копировать в реальные кейсы.</p>
<h3>Карточки ссылок</h3>
<div class="case-links-grid">
<a class="case-link-card" href="https://www.examples.com/" target="_blank" rel="noopener noreferrer">
<span class="case-link-card__media" aria-hidden="true">
<img src="../../../assets/template-elements-demo/wallpaper-1.jpg" alt="" loading="lazy" decoding="async" />
</span>
<span class="case-link-card__body">
<span class="case-link-card__title">Источник с превью</span>
<span class="case-link-card__meta">Короткая подпись: что пользователь увидит по ссылке</span>
<span class="case-link-card__url">www.examples.com</span>
</span>
</a>
<a class="case-link-card case-link-card--favicon" href="https://www.examples.com/docs" target="_blank" rel="noopener noreferrer">
<span class="case-link-card__media" aria-hidden="true">
<img src="https://www.google.com/s2/favicons?domain=www.examples.com&sz=128" alt="" decoding="async" />
</span>
<span class="case-link-card__body">
<span class="case-link-card__title">Источник с favicon</span>
<span class="case-link-card__meta">Вариант для более легких ссылок без скриншота</span>
<span class="case-link-card__url">www.examples.com/docs</span>
</span>
</a>
</div>
<h3>Картинка: 50% от оригинала (без превью)</h3>
<figure class="case-media case-media--natural">
<img src="../../../assets/template-elements-demo/hello.gif" alt="Демо GIF в натуральном размере" loading="lazy" decoding="async" />
<figcaption>Изображение в уменьшенном натуральном размере, по центру.</figcaption>
</figure>
<h3>Картинка: по ширине контента (с превью)</h3>
<figure class="case-media case-media--content">
<img src="../../../assets/template-elements-demo/wallpaper-1.jpg" alt="Демо изображения по ширине контента" loading="lazy" decoding="async" data-image-viewer />
<figcaption>Изображение по ширине контента. Клик открывает viewer.</figcaption>
</figure>
<h3>Картинка: чуть шире контента (с превью)</h3>
<figure class="case-media case-media--wide">
<img src="../../../assets/template-elements-demo/wallpaper-1.jpg" alt="Демо изображения шире контента" loading="lazy" decoding="async" data-image-viewer />
<figcaption>Изображение немного выходит за пределы контентной колонки.</figcaption>
</figure>
<h3>Длинный скрин: свёрнутая высота и кнопка внутри превью</h3>
<p class="section__prose">
Блок <code>data-case-tall-media</code>: ширина задаётся атрибутом <code>data-case-tall-width="wide"</code> (как «широкая» картинка) или <code>content</code> (по колонке). В свёрнутом виде видна верхняя часть кадра, внизу превью — плотный «туман». Кнопка «Развернуть» / «Свернуть» с иконкой-шевроном поверх нижней части кадра, внутри рамки; после раскрытия туман скрывается, после сворачивания страница прокручивается к превью. Высоту превью — на <code>.case-media-tall__clip</code> через <code>--case-tall-max</code> (по умолчанию <code>min(70vh, 32rem)</code>).
</p>
<figure class="case-media" data-case-tall-media data-case-tall-width="wide">
<div class="case-media-tall" data-case-tall-root>
<div class="case-media-tall__clip" id="template-demo-tall-clip" data-case-tall-clip>
<img
src="../../../assets/template-elements-demo/img-long.webp"
alt="Демо: длинный вертикальный скрин интерфейса"
width="1200"
loading="lazy"
decoding="async"
data-image-viewer
/>
<div class="case-media-tall__fog" aria-hidden="true"></div>
</div>
<div class="case-media-tall__actions">
<button
type="button"
class="case-media-tall__btn btn btn--ghost btn--flat"
data-case-tall-toggle
aria-expanded="false"
aria-controls="template-demo-tall-clip"
>
<span class="case-media-tall__btn-chev" aria-hidden="true"></span>
<span data-case-tall-label-more>Развернуть</span>
<span data-case-tall-label-less hidden>Свернуть</span>
</button>
</div>
</div>
<figcaption>Длинное изображение <code>img-long.webp</code> (исходник PNG рядом в <code>public/assets/template-elements-demo/</code>).</figcaption>
</figure>
<h3>Галерея: сетка по ширине контента</h3>
<p class="section__prose">
Колонок на широком экране задаётся на <code>figure</code>: атрибут <code>style="--case-gallery-cols: 3"</code>. Ниже порогов сетка схлопывается до двух и одной колонки. Клик по миниатюре открывает общий viewer кейса.
</p>
<figure class="case-media case-media-gallery" style="--case-gallery-cols: 3">
<div class="case-media-gallery__grid">
<div class="case-media-gallery__item">
<img src="../../../assets/template-elements-demo/small-image-1.webp" alt="Демо миниатюра 1" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="../../../assets/template-elements-demo/small-image-2.webp" alt="Демо миниатюра 2" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="../../../assets/template-elements-demo/small-image-3.webp" alt="Демо миниатюра 3" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="../../../assets/template-elements-demo/small-image-4.webp" alt="Демо миниатюра 4" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="../../../assets/template-elements-demo/small-image-5.webp" alt="Демо миниатюра 5" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="../../../assets/template-elements-demo/small-image-6.webp" alt="Демо миниатюра 6" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="../../../assets/template-elements-demo/small-image-7.webp" alt="Демо миниатюра 7" loading="lazy" decoding="async" data-image-viewer />
</div>
</div>
<figcaption>Сетка в колонке статьи; на этом примере три колонки на десктопе.</figcaption>
</figure>
<h3>Галерея: сетка на ширину страницы с боковыми отступами</h3>
<p class="section__prose">
Класс <code>case-media-gallery--wide</code> — та же логика выхода за колонку, что у одиночного <code>case-media--wide</code>. Здесь четыре колонки на широком экране (<code>--case-gallery-cols: 4</code>).
</p>
<figure class="case-media case-media-gallery case-media-gallery--wide" style="--case-gallery-cols: 4">
<div class="case-media-gallery__grid">
<div class="case-media-gallery__item">
<img src="../../../assets/template-elements-demo/small-image-1.webp" alt="Wide-сетка, кадр 1" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="../../../assets/template-elements-demo/small-image-2.webp" alt="Wide-сетка, кадр 2" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="../../../assets/template-elements-demo/small-image-3.webp" alt="Wide-сетка, кадр 3" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="../../../assets/template-elements-demo/small-image-4.webp" alt="Wide-сетка, кадр 4" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="../../../assets/template-elements-demo/small-image-5.webp" alt="Wide-сетка, кадр 5" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="../../../assets/template-elements-demo/small-image-6.webp" alt="Wide-сетка, кадр 6" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="../../../assets/template-elements-demo/small-image-7.webp" alt="Wide-сетка, кадр 7" loading="lazy" decoding="async" data-image-viewer />
</div>
</div>
<figcaption>Ширина как у wide-картинки; на узком экране wide-обёртка схлопывается в 100% ширины колонки (см. медиазапросы).</figcaption>
</figure>
<h3>Слайдер: одна картинка, стрелки и точки</h3>
<p class="section__prose">
Блок <code>.case-media-slider</code> показывает слайды по одному: навигация стрелками «пред/след»,
пагинация точками (активная — акцентным цветом). Поддерживается клавиатура (←/→, Home/End на точках),
тач/мышь-свайп и ленивая подгрузка соседних кадров через <code>data-src</code>. Клик по активному
кадру открывает общий viewer кейса.
</p>
<figure class="case-media case-media-slider" data-case-media-slider>
<div class="case-media-slider__viewport" data-slider-viewport>
<div class="case-media-slider__track" data-slider-track>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-demo-1.webp" alt="Слайдер, кадр 1" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-demo-2.webp" alt="Слайдер, кадр 2" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-demo-3.webp" alt="Слайдер, кадр 3" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-demo-4.webp" alt="Слайдер, кадр 4" loading="lazy" decoding="async" data-image-viewer />
</div>
</div>
<div class="case-media-slider__nav-group">
<button type="button" class="case-media-slider__nav case-media-slider__nav--prev" data-slider-prev aria-label="Предыдущее изображение">
<span class="case-media-slider__nav-ico case-media-slider__nav-ico--left icon-press" aria-hidden="true"></span>
</button>
<button type="button" class="case-media-slider__nav case-media-slider__nav--next" data-slider-next aria-label="Следующее изображение">
<span class="case-media-slider__nav-ico case-media-slider__nav-ico--right icon-press" aria-hidden="true"></span>
</button>
</div>
</div>
<div class="case-media-slider__dots" data-slider-dots role="tablist" aria-label="Выбор изображения">
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 1"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 2"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 3"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 4"></button>
</div>
</figure>
<p class="section__prose">
Тот же слайдер, но с модификатором <code>case-media--wide</code> — выходит за колонку
контента, как одиночные широкие картинки. Кнопки пред/след и точки ведут себя так же.
</p>
<figure class="case-media case-media-slider case-media--wide" data-case-media-slider>
<div class="case-media-slider__viewport" data-slider-viewport>
<div class="case-media-slider__track" data-slider-track>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-wide-1.webp" alt="Слайдер wide, кадр 1" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-wide-2.webp" alt="Слайдер wide, кадр 2" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-wide-3.webp" alt="Слайдер wide, кадр 3" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-wide-4.webp" alt="Слайдер wide, кадр 4" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-wide-5.webp" alt="Слайдер wide, кадр 5" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-wide-6.webp" alt="Слайдер wide, кадр 6" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-wide-7.webp" alt="Слайдер wide, кадр 7" loading="lazy" decoding="async" data-image-viewer />
</div>
</div>
<div class="case-media-slider__nav-group">
<button type="button" class="case-media-slider__nav case-media-slider__nav--prev" data-slider-prev aria-label="Предыдущее изображение">
<span class="case-media-slider__nav-ico case-media-slider__nav-ico--left icon-press" aria-hidden="true"></span>
</button>
<button type="button" class="case-media-slider__nav case-media-slider__nav--next" data-slider-next aria-label="Следующее изображение">
<span class="case-media-slider__nav-ico case-media-slider__nav-ico--right icon-press" aria-hidden="true"></span>
</button>
</div>
</div>
<div class="case-media-slider__dots" data-slider-dots role="tablist" aria-label="Выбор изображения">
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 1"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 2"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 3"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 4"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 5"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 6"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 7"></button>
</div>
</figure>
<p class="section__prose">
Слайдер с горизонтальными (широкими) кадрами одного размера — все картинки
<code>1024×800</code>.
</p>
<figure class="case-media case-media-slider case-media--natural" data-case-media-slider style="--slider-natural-w: 1024px">
<div class="case-media-slider__viewport" data-slider-viewport>
<div class="case-media-slider__track" data-slider-track>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-wide-1.webp" alt="Широкий слайдер, кадр 1" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-wide-2.webp" alt="Широкий слайдер, кадр 2" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-wide-3.webp" alt="Широкий слайдер, кадр 3" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-wide-4.webp" alt="Широкий слайдер, кадр 4" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-wide-5.webp" alt="Широкий слайдер, кадр 5" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-wide-6.webp" alt="Широкий слайдер, кадр 6" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-wide-7.webp" alt="Широкий слайдер, кадр 7" loading="lazy" decoding="async" data-image-viewer />
</div>
</div>
<div class="case-media-slider__nav-group">
<button type="button" class="case-media-slider__nav case-media-slider__nav--prev" data-slider-prev aria-label="Предыдущее изображение">
<span class="case-media-slider__nav-ico case-media-slider__nav-ico--left icon-press" aria-hidden="true"></span>
</button>
<button type="button" class="case-media-slider__nav case-media-slider__nav--next" data-slider-next aria-label="Следующее изображение">
<span class="case-media-slider__nav-ico case-media-slider__nav-ico--right icon-press" aria-hidden="true"></span>
</button>
</div>
</div>
<div class="case-media-slider__dots" data-slider-dots role="tablist" aria-label="Выбор изображения">
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 1"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 2"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 3"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 4"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 5"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 6"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 7"></button>
</div>
</figure>
<p class="section__prose">
Тот же слайдер, но с вертикальными кадрами одного размера — все картинки
<code>600×800</code>.
</p>
<figure class="case-media case-media-slider case-media--natural" data-case-media-slider style="--slider-natural-w: 600px">
<div class="case-media-slider__viewport" data-slider-viewport>
<div class="case-media-slider__track" data-slider-track>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-portrait-1.webp" alt="Вертикальный слайдер, кадр 1" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-portrait-2.webp" alt="Вертикальный слайдер, кадр 2" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-portrait-3.webp" alt="Вертикальный слайдер, кадр 3" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-portrait-4.webp" alt="Вертикальный слайдер, кадр 4" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-portrait-5.webp" alt="Вертикальный слайдер, кадр 5" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-portrait-6.webp" alt="Вертикальный слайдер, кадр 6" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-portrait-7.webp" alt="Вертикальный слайдер, кадр 7" loading="lazy" decoding="async" data-image-viewer />
</div>
</div>
<div class="case-media-slider__nav-group">
<button type="button" class="case-media-slider__nav case-media-slider__nav--prev" data-slider-prev aria-label="Предыдущее изображение">
<span class="case-media-slider__nav-ico case-media-slider__nav-ico--left icon-press" aria-hidden="true"></span>
</button>
<button type="button" class="case-media-slider__nav case-media-slider__nav--next" data-slider-next aria-label="Следующее изображение">
<span class="case-media-slider__nav-ico case-media-slider__nav-ico--right icon-press" aria-hidden="true"></span>
</button>
</div>
</div>
<div class="case-media-slider__dots" data-slider-dots role="tablist" aria-label="Выбор изображения">
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 1"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 2"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 3"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 4"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 5"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 6"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 7"></button>
</div>
</figure>
<p class="section__prose">
Отдельный пример: переключатель режима анимации смены кадров —
<code>slide</code> (сдвиг), <code>fade</code> (кроссфейд) и <code>none</code> (без перехода).
Режим задаётся атрибутом <code>data-slider-anim</code> на фигуре.
</p>
<figure class="case-media case-media-slider" data-case-media-slider data-slider-anim="fade">
<div class="case-media-slider__anim-switch" data-slider-anim-switch role="group" aria-label="Режим анимации слайдера">
<button type="button" data-mode="slide" aria-pressed="false">Слайд</button>
<button type="button" data-mode="fade" aria-pressed="true">Fade</button>
<button type="button" data-mode="none" aria-pressed="false">None</button>
</div>
<div class="case-media-slider__viewport" data-slider-viewport>
<div class="case-media-slider__track" data-slider-track>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-demo-1.webp" alt="Пример анимации, кадр 1" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-demo-2.webp" alt="Пример анимации, кадр 2" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-demo-3.webp" alt="Пример анимации, кадр 3" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="../../../assets/template-elements-demo/slider-demo-4.webp" alt="Пример анимации, кадр 4" loading="lazy" decoding="async" data-image-viewer />
</div>
</div>
<div class="case-media-slider__nav-group">
<button type="button" class="case-media-slider__nav case-media-slider__nav--prev" data-slider-prev aria-label="Предыдущее изображение">
<span class="case-media-slider__nav-ico case-media-slider__nav-ico--left icon-press" aria-hidden="true"></span>
</button>
<button type="button" class="case-media-slider__nav case-media-slider__nav--next" data-slider-next aria-label="Следующее изображение">
<span class="case-media-slider__nav-ico case-media-slider__nav-ico--right icon-press" aria-hidden="true"></span>
</button>
</div>
</div>
<div class="case-media-slider__dots" data-slider-dots role="tablist" aria-label="Выбор изображения">
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 1"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 2"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 3"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 4"></button>
</div>
</figure>
<h3>Callout: важный абзац с эмоджи</h3>
<aside class="case-callout" data-callout>
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">📌</span>
<div class="case-callout__content">
<p>Это пример акцентного callout-блока. Эмоджи вынесен влево и пульсирует, чтобы визуально усилить важную мысль.</p>
</div>
</aside>
<h3>Видео: карточка с тенью и фиксированными малыми углами</h3>
<figure class="case-media" style="margin: 0.85rem 0 1.2rem">
<div class="case-video-shell">
<video controls preload="metadata" playsinline poster="../../../assets/template-elements-demo/video-1.webp" data-case-video-player style="display: block; width: 100%; height: auto">
<source src="../../../assets/template-elements-demo/video-1.webm" type="video/webm" />
<source src="../../../assets/template-elements-demo/video-1.mp4" type="video/mp4" />
Ваш браузер не поддерживает видео.
</video>
</div>
<figcaption>Пример видео-карточки в стиле кейса.</figcaption>
</figure>
<h2>Результат</h2>
<p class="section__prose">
Шаблон готов для копирования в новый кейс: остаётся заменить рыбу на фактический текст, подставить реальные ссылки и медиа проекта.
</p>
</div>
</main>
<section id="projects" class="section section--surface" data-reveal>
<div class="section__inner">
<h2 class="section__title">Portfolio</h2>
<ol class="mini-projects-grid" data-mini-projects-list>
<li class="mini-projects-grid__item" data-mp-cells="2" data-related-slug="ai-platform-primo-rpa">
<a class="mp-card mp-card--link mp-card--stack" href="../ai-platform-primo-rpa/" aria-label="AI platform — open case">
<div class="mp-card__media" aria-hidden="true">
<img
class="mp-card__image"
src="../../../assets/ai-platform-primo-rpa/cover.webp"
alt=""
width="400"
height="225"
loading="lazy"
decoding="async"
/>
</div>
<div class="mp-card__body">
<h3 class="mp-card__title">Primo AI Server</h3>
<ul class="mp-card__tags" aria-label="Project type">
<li class="mp-card__tag">UX/UI</li>
<li class="mp-card__tag">Web App</li>
</ul>
<p class="mp-card__desc">Interface for training and using AI models in business processes: data work, automation scenarios, and Smart OCR.</p>
</div>
</a>
</li>
<li class="mini-projects-grid__item" data-mp-cells="2" data-related-slug="lunacy">
<a class="mp-card mp-card--link mp-card--stack" href="../lunacy/" aria-label="Graphics editor Lunacy — open case">
<div class="mp-card__media" aria-hidden="true">
<img
class="mp-card__image"
src="../../../assets/lunacy/cover.webp"
alt=""
width="400"
height="225"
loading="lazy"
decoding="async"
/>
</div>
<div class="mp-card__body">
<h3 class="mp-card__title">Lunacy</h3>
<ul class="mp-card__tags" aria-label="Project type">
<li class="mp-card__tag">UX/UI</li>
<li class="mp-card__tag">Desktop App</li>
</ul>
<p class="mp-card__desc">Work on the Lunacy interface at Icons8: user flows, complex prototypes, improved functionality and interface logic.</p>
</div>
</a>
</li>
<li class="mini-projects-grid__item" data-mp-cells="2" data-related-slug="manu-game-maker" hidden>
<a class="mp-card mp-card--link mp-card--stack" href="../manu-game-maker/" aria-label="MANU game engine — open case">
<div class="mp-card__media" aria-hidden="true">
<img
class="mp-card__image"
src="../../../assets/manu-game-maker/cover.webp"
alt=""
width="400"
height="225"
loading="lazy"
decoding="async"
/>
</div>
<div class="mp-card__body">
<h3 class="mp-card__title">MANU game engine</h3>
<ul class="mp-card__tags" aria-label="Project type">
<li class="mp-card__tag">Product Design</li>
<li class="mp-card__tag">Desktop App</li>
</ul>
<p class="mp-card__desc">Redesign and evolution of the game engine interface: a new working concept, refreshed visual system, and hundreds of complex user scenarios worked through.</p>
</div>
</a>
</li>
<li class="mini-projects-grid__item" data-mp-cells="2" data-related-slug="mobile-clinic-app" hidden>
<a class="mp-card mp-card--link mp-card--stack" href="../mobile-clinic-app/" aria-label="Mobile app for a clinic network — open case">
<div class="mp-card__media" aria-hidden="true">
<img
class="mp-card__image"
src="../../../assets/mobile-clinic-app/cover.webp"
alt=""
width="400"
height="225"
loading="lazy"
decoding="async"
/>
</div>
<div class="mp-card__body">
<h3 class="mp-card__title">Mobile app for a clinic network</h3>
<ul class="mp-card__tags" aria-label="Project type">
<li class="mp-card__tag">UX/UI</li>
<li class="mp-card__tag">Mobile App</li>
</ul>
<p class="mp-card__desc">Design of a mobile app for booking doctors and managing medical services. Focus on a simple user path, clear navigation, and quick access to the right actions.</p>
</div>
</a>
</li>
<li class="mini-projects-grid__item" data-mp-cells="2" data-related-slug="orc-automation-panel">
<a class="mp-card mp-card--link mp-card--stack" href="../orc-automation-panel/" aria-label="Web panel for automation orchestration — open case">
<div class="mp-card__media" aria-hidden="true">
<img
class="mp-card__image"
src="../../../assets/orc-primo-rpa/cover.webp"
alt=""
width="400"
height="225"
loading="lazy"
decoding="async"
/>
</div>
<div class="mp-card__body">
<h3 class="mp-card__title">Primo Orc</h3>
<ul class="mp-card__tags" aria-label="Project type">
<li class="mp-card__tag">Mentoring &amp; coaching</li>
</ul>
<p class="mp-card__desc">Primo RPA orchestrator web console: projects, launch and control of RPA bots. Redesign of key screens for production without halting releases.</p>
</div>
</a>
</li>
<li class="mini-projects-grid__item" data-mp-cells="2" data-related-slug="task-distribution-concept" hidden>
<a class="mp-card mp-card--link mp-card--stack" href="../task-distribution-concept/" aria-label="Task distribution service concept — open case">
<div class="mp-card__media" aria-hidden="true">
<img
class="mp-card__image"
src="../../../assets/task-distribution-concept/cover.webp"
alt=""
width="400"
height="225"
loading="lazy"
decoding="async"
/>
</div>
<div class="mp-card__body">
<h3 class="mp-card__title">Task distribution service concept</h3>
<ul class="mp-card__tags" aria-label="Project type">
<li class="mp-card__tag">UX/UI</li>
<li class="mp-card__tag">Analytics</li>
</ul>
<p class="mp-card__desc">A product concept for a service to set, distribute and track tasks, with emphasis on process transparency and comfortable teamwork.</p>
</div>
</a>
</li>
<li class="mini-projects-grid__item" data-mp-cells="2" data-related-slug="task-tracker" hidden>
<a class="mp-card mp-card--link mp-card--stack" href="../task-tracker/" aria-label="Task tracker for a back-office system — open case">
<div class="mp-card__media" aria-hidden="true">
<img
class="mp-card__image"
src="../../../assets/task-tracker/cover.webp"
alt=""
width="400"
height="225"
loading="lazy"
decoding="async"
/>
</div>
<div class="mp-card__body">
<h3 class="mp-card__title">Task tracker for a back-office system</h3>
<ul class="mp-card__tags" aria-label="Project type">
<li class="mp-card__tag">Product Design</li>
<li class="mp-card__tag">Web App</li>
</ul>
<p class="mp-card__desc">Interface for planning and distributing tasks in the operations department: shared pool, personal ToDo, per-assignee overview; tabs, filters, board / list / table views, drag &amp; drop.</p>
</div>
</a>
</li>
</ol>
</div>
</section>
<section hidden class="section section--surface" aria-hidden="true">
<div class="section__inner">
<div class="projects__heading">
<h2 class="section__title projects__title">Portfolio</h2>
<div class="projects__controls" aria-label="Portfolio card navigation">
<button type="button" class="projects__nav-btn" data-projects-prev aria-label="Scroll left" aria-controls="projects-viewport">
<span class="projects__nav-ico projects__nav-ico--left" aria-hidden="true"></span>
</button>
<button type="button" class="projects__nav-btn" data-projects-next aria-label="Scroll right" aria-controls="projects-viewport">
<span class="projects__nav-ico projects__nav-ico--right" aria-hidden="true"></span>
</button>
</div>
</div>
<div class="projects-carousel">
<div id="projects-viewport" class="projects-carousel__viewport" data-projects-viewport>
<div class="projects-carousel__track">
<div class="projects-carousel__spacer" aria-hidden="true"></div>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../orc-automation-panel/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Web panel for automation orchestration</h3>
<p class="portfolio-card__summary">
Primo RPA orchestrator web console: projects, launch and control of RPA bots. Redesign of key screens for production without halting releases.
</p>
<ul class="portfolio-card__tags" aria-label="Key tags">
<li class="portfolio-card__tag">UX/UI</li>
<li class="portfolio-card__tag">Web App</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../../assets/orc-primo-rpa/cover.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../ai-platform-primo-rpa/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Platform for working with AI</h3>
<p class="portfolio-card__summary">
Interface for training and using AI models in business processes: data work, automation scenarios, and Smart OCR.
</p>
<ul class="portfolio-card__tags" aria-label="Key tags">
<li class="portfolio-card__tag">UX/UI</li>
<li class="portfolio-card__tag">Web App</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../../assets/ai-platform-primo-rpa/cover.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../task-tracker/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Task tracker for a back-office system</h3>
<p class="portfolio-card__summary">
Interface for planning and distributing tasks in the operations department: shared pool, personal ToDo, per-assignee overview; tabs, filters, board / list / table views, drag &amp; drop.
</p>
<ul class="portfolio-card__tags" aria-label="Key tags">
<li class="portfolio-card__tag">Product Design</li>
<li class="portfolio-card__tag">Web App</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../../assets/task-tracker/cover.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../manu-game-maker/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">MANU game engine</h3>
<p class="portfolio-card__summary">
Redesign and evolution of the game engine interface: a new working concept, refreshed visual system, and hundreds of complex user scenarios worked through.
</p>
<ul class="portfolio-card__tags" aria-label="Key tags">
<li class="portfolio-card__tag">Product Design</li>
<li class="portfolio-card__tag">Desktop App</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../../assets/manu-game-maker/cover.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../lunacy/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Graphics editor Lunacy</h3>
<p class="portfolio-card__summary">
Work on the Lunacy interface at Icons8: user flows, complex prototypes, improved functionality and interface logic.
</p>
<ul class="portfolio-card__tags" aria-label="Key tags">
<li class="portfolio-card__tag">UX/UI</li>
<li class="portfolio-card__tag">Desktop App</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../../assets/lunacy/cover.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../mobile-clinic-app/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Mobile app for a clinic network</h3>
<p class="portfolio-card__summary">
Design of a mobile app for booking doctors and managing medical services. Focus on a simple user path, clear navigation, and quick access to the right actions.
</p>
<ul class="portfolio-card__tags" aria-label="Key tags">
<li class="portfolio-card__tag">UX/UI</li>
<li class="portfolio-card__tag">Mobile App</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../../assets/mobile-clinic-app/cover.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../task-distribution-concept/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Task distribution service concept</h3>
<p class="portfolio-card__summary">
A product concept for a service to set, distribute and track tasks, with emphasis on process transparency and comfortable teamwork.
</p>
<ul class="portfolio-card__tags" aria-label="Key tags">
<li class="portfolio-card__tag">UX/UI</li>
<li class="portfolio-card__tag">Analytics</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../../assets/task-distribution-concept/cover.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../obsidian-plugin-columns-view/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Columns view — plugin for Obsidian</h3>
<p class="portfolio-card__summary">
Interface for multi-column note work: convenient navigation, filtering and column-view settings right inside the Obsidian editor.
</p>
<ul class="portfolio-card__tags" aria-label="Key tags">
<li class="portfolio-card__tag">UX/UI</li>
<li class="portfolio-card__tag">Plugin</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../../assets/obsidian-plugin-columns-view/filter use.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<div class="projects-carousel__spacer" aria-hidden="true"></div>
</div>
</div>
<button
type="button"
class="projects-carousel__edge-hit projects-carousel__edge-hit--left"
data-projects-edge-prev
aria-label="Scroll portfolio left"
></button>
<button
type="button"
class="projects-carousel__edge-hit projects-carousel__edge-hit--right"
data-projects-edge-next
aria-label="Scroll portfolio right"
></button>
</div>
</div>
</section>
<section id="contact" class="section section--surface section--footerish" data-reveal>
<div class="section__inner">
<h2 class="section__title">Contact</h2>
<ul class="contact-grid">
<li><a class="contact-card contact-card--link contact-card--brand-tg" href="https://t.me/mamadaevv" rel="noopener noreferrer"><span class="contact-card__corner" aria-hidden="true"></span><span class="contact-card__icon" aria-hidden="true"><img src="../../../assets/shared/icons/tg.svg" alt="" width="24" height="24" loading="eager" decoding="async" /></span><span class="contact-card__body"><span class="contact-card__name">Telegram</span><span class="contact-card__hint">I'll reply today</span></span></a></li>
<li><a class="contact-card contact-card--link contact-card--brand-vk" href="https://vk.com/mamadaevv" rel="noopener noreferrer"><span class="contact-card__corner" aria-hidden="true"></span><span class="contact-card__icon" aria-hidden="true"><img src="../../../assets/shared/icons/vk.svg" alt="" width="24" height="24" loading="eager" decoding="async" /></span><span class="contact-card__body"><span class="contact-card__name">VK</span><span class="contact-card__hint">Stable connection</span></span></a></li>
<li><a class="contact-card contact-card--link contact-card--brand-ya" href="https://yandex.ru/chat/p/727e71fa-89b5-44a8-90a5-851021631a1c?utm_source=invite" rel="noopener noreferrer"><span class="contact-card__corner" aria-hidden="true"></span><span class="contact-card__icon" aria-hidden="true"><img src="../../../assets/shared/icons/yandex_telemost.svg" alt="" width="24" height="24" loading="eager" decoding="async" /></span><span class="contact-card__body"><span class="contact-card__name">Yandex</span><span class="contact-card__hint">Yes, you can reach me here too</span></span></a></li>
<li><button type="button" class="contact-card contact-card--action contact-card--brand-email" data-contact-copy data-email-b64="bmlrQG1hbWFkYWV2di5zaXRl" data-hint-default="Copy address" aria-label="Copy email address to clipboard"><span class="contact-card__corner contact-card__corner--copy" aria-hidden="true"></span><span class="contact-card__icon contact-card__icon--accent" aria-hidden="true"></span><span class="contact-card__body"><span class="contact-card__name">Email</span><span class="contact-card__hint" data-contact-copy-hint>Copy address</span></span></button></li>
</ul>
</div>
</section>
<footer class="footer">
<div class="footer__inner">
<span class="footer__chunk footer__chunk--date">© 2015–2026<span class="footer__sep" aria-hidden="true"> · </span></span>
<span class="footer__chunk footer__chunk--main">Website design and development — Nikolay Mamadaev</span>
<span class="footer__chunk footer__chunk--meta footer__attr"><span class="footer__sep" aria-hidden="true"> · </span><a href="../../../cases/design-system/">Design System</a><span class="footer__sep" aria-hidden="true"> · </span><a href="../../../cookie-policy/">Cookie policy</a></span>
</div>
</footer>
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
<p class="cookie-notice__text">
This site uses cookies for a comfortable experience. Read more in
<a href="../../../cookie-policy/" data-cookie-policy-link>cookie policy</a>.
</p>
<button type="button" class="btn btn--secondary btn--flat cookie-notice__accept" data-cookie-accept>
<span>Accept</span>
<span class="cookie-notice__accept-icon" aria-hidden="true">
<img src="../../../assets/shared/icons/сookie.svg" alt="" width="20" height="20" loading="eager" decoding="async" />
</span>
</button>
</aside>
<div id="nav-more-menu-floating" class="nav-more__floating" hidden data-nav-more-menu-floating aria-hidden="true"></div>
</body>
</html>