Секция карточек
Компонент-секция с карточками услуг. Каждая карточка имеет уникальную визуализацию: tool badges, концентрические дуги, чеклист автоматизации, бар-чарт, shield с протоколами и анимированная SVG-книга.
Превью
Услуга
Интеграция анализа безопасности
Интегрируем автоматический анализ кода на уязвимости на каждом этапе разработки. Проверяем исходный код, тестируем работающее приложение и отслеживаем уязвимости в библиотеках — всё автоматически в CI/CD без участия команды.
Услуга
Проверка защищённости
Этично проверяем сервис или сервер на наличие уязвимостей: открытые точки входа, слабые конфигурации и всё, что может стать проблемой раньше, чем вы об этом узнаете.
Услуга
Автоматизация
Автоматизируем рутину — от простого bash-скрипта до сложных решений под индивидуальные требования.
Услуга
Разработка под заказ
Создаём сайты, лендинги и веб-системы под любой стек — React, Svelte, Next.js, Node.js и другие. Пишем чистый, поддерживаемый код и сдаём в срок.
Услуга
Настройка безопасного доступа
Настраиваем и интегрируем защищённый доступ к сервисам и серверам. Подбираем решение под задачу — mTLS, VPN, Zero Trust или другой подход. Доступ получают только те, кому вы это разрешили.
Открытые знания
Знания каждому!
Пишем понятные статьи и гайды по DevSecOps и не только. Рассказываем как настроить безопасность с нуля и сделать её частью культуры команды.
<script lang="ts">
// ─── Tool badges for card 1 ───────────────────────────────────────────────
const _securityTools = ["SCA", "SAST", "DAST", "LINT", "WAF", "IaC"];
// ─── Automation checklist items ───────────────────────────────────────────
const automationVisible = [
"ежедневный бэкап данных и логов",
"управление сетью и firewall-правилами",
"оптимизация работы git-репозиториев",
];
const automationHidden = [
"ротация ключей доступа",
"мониторинг состояния сервисов",
"автоочистка устаревших артефактов",
];
</script>
<section class="services-grid">
<style>
/* ── Grid layout ─────────────────────────────────────────────────── */
.services-grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto auto auto;
gap: 0.75rem;
width: 100%;
box-sizing: border-box;
}
/* Card 1 — top-left */
.card-security-analysis { grid-column: 1; grid-row: 1; }
/* Card 2 — top-right */
.card-pentest { grid-column: 2; grid-row: 1; }
/* Card 3 — full-width middle */
.card-automation { grid-column: 1 / -1; grid-row: 2; }
/* Card 4 — bottom-left */
.card-dev { grid-column: 1; grid-row: 3; }
/* Card 5 — bottom-right */
.card-access { grid-column: 2; grid-row: 3; }
/* Card 6 — full-width bottom (knowledge) */
.card-knowledge { grid-column: 1 / -1; grid-row: 4; }
@media (max-width: 600px) {
.services-grid {
grid-template-columns: 1fr;
}
.card-security-analysis,
.card-pentest,
.card-automation,
.card-dev,
.card-access,
.card-knowledge {
grid-column: 1;
grid-row: auto;
}
}
/* ── Shared card shell ────────────────────────────────────────────── */
.card-shell {
inset-shadow: var(--inset-shadow, inset 0 1px 0 rgba(255,255,255,0.06));
position: relative;
overflow: hidden;
border-radius: 0.5rem;
background: var(--background-inset);
padding: 0.375rem;
}
.card-inner {
position: relative;
border-radius: 0.375rem;
background: var(--background);
overflow: hidden;
display: flex;
flex-direction: column;
min-height: 18rem;
}
/* ── Visual areas ────────────────────────────────────────────────── */
.visual-area {
position: relative;
height: 9rem;
overflow: hidden;
flex-shrink: 0;
}
/* ── Card text ───────────────────────────────────────────────────── */
.card-body {
padding: 1rem 1.25rem 1.25rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
flex: 1;
}
.card-badge {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 0.6rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--foreground-muted, rgba(255,255,255,0.4));
margin-bottom: 0.25rem;
}
.card-title {
font-size: 1rem;
font-weight: 600;
line-height: 1.3;
color: var(--foreground);
margin: 0;
}
.card-desc {
font-size: 0.82rem;
line-height: 1.6;
color: var(--foreground-muted, rgba(255,255,255,0.55));
margin: 0;
flex: 1;
}
@media (min-width: 768px) {
.card-title { font-size: 1.125rem; }
.card-desc { font-size: 0.9rem; }
.card-badge { font-size: 0.65rem; }
}
.card-price {
display: flex;
align-items: baseline;
gap: 0.3em;
margin-top: 0.75rem;
}
.card-price-from {
font-family: ui-monospace, monospace;
font-size: 0.6rem;
font-weight: 500;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--foreground-muted, rgba(255,255,255,0.35));
}
.card-price-value {
font-size: 1rem;
font-weight: 600;
color: var(--foreground);
letter-spacing: -0.01em;
}
/* ═══════════════════════════════════════════════════════════════════
CARD 1 — Security Analysis Visual
Tool badges on horizontal lines (like the Seamless Integrations card)
═══════════════════════════════════════════════════════════════════ */
.sa-visual {
display: flex;
flex-direction: column;
justify-content: space-around;
padding: 1.1rem 0 0.5rem;
height: 100%;
gap: 0;
}
.sa-row {
position: relative;
display: flex;
align-items: center;
justify-content: center;
height: 2.1rem;
gap: 0.75rem;
}
/* horizontal connector line */
.sa-row::before {
content: '';
position: absolute;
inset: 0;
margin: auto 0;
height: 1px;
background: var(--border, rgba(255,255,255,0.1));
}
.sa-badge {
position: relative;
display: inline-flex;
align-items: center;
height: 1.75rem;
padding: 0 0.65rem;
border-radius: 999px;
background: var(--background);
border: 1px solid var(--border, rgba(255,255,255,0.12));
box-shadow: 0 2px 8px rgba(0,0,0,0.28);
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 0.65rem;
font-weight: 700;
letter-spacing: 0.06em;
color: var(--foreground-muted, rgba(255,255,255,0.55));
white-space: nowrap;
z-index: 2;
}
/* accent the first badge in each row */
.sa-badge-accent {
color: var(--accent, #e8834a);
border-color: color-mix(in srgb, var(--accent, #e8834a) 30%, transparent);
}
/* slight stagger while keeping badges in the visible center zone */
.sa-row:nth-child(1) { transform: translateX(-1.5rem); }
.sa-row:nth-child(2) { transform: translateX(1.5rem); }
.sa-row:nth-child(3) { transform: translateX(-0.75rem); }
/* ═══════════════════════════════════════════════════════════════════
CARD 2 — Pentest Visual (concentric arcs, like Real-time Sync)
═══════════════════════════════════════════════════════════════════ */
.pt-visual {
position: absolute;
inset: 0;
}
/* vertical centre line */
.pt-vline {
position: absolute;
left: 50%;
top: 0; bottom: 0;
width: 1px;
background: color-mix(in srgb, var(--foreground, #fff) 12%, transparent);
}
/* outer arc */
.pt-arc-outer {
position: absolute;
left: -3rem; right: -3rem;
top: 1.2rem;
aspect-ratio: 1;
border-radius: 50%;
border: 1px solid color-mix(in srgb, var(--foreground, #fff) 10%, transparent);
}
/* outer arc accent half */
.pt-arc-outer-accent {
position: absolute;
left: -3rem; right: -3rem;
top: 1.2rem;
aspect-ratio: 1;
border-radius: 50%;
border: 1px solid var(--accent, #e8834a);
/* show only right half */
-webkit-mask-image: linear-gradient(90deg, transparent 50%, black 50%);
mask-image: linear-gradient(90deg, transparent 50%, black 50%);
}
/* inner arc */
.pt-arc-inner {
position: absolute;
left: 0; right: 0;
top: 3.5rem;
aspect-ratio: 1;
border-radius: 50%;
border: 1px solid color-mix(in srgb, var(--foreground, #fff) 10%, transparent);
}
/* inner arc accent half — lime, like the original */
.pt-arc-inner-accent {
position: absolute;
left: 0; right: 0;
top: 3.5rem;
aspect-ratio: 1;
border-radius: 50%;
border: 1px solid #84cc16;
-webkit-mask-image: linear-gradient(90deg, black 50%, transparent 50%);
mask-image: linear-gradient(90deg, black 50%, transparent 50%);
}
/* ═══════════════════════════════════════════════════════════════════
CARD 3 — Automation (full-width checklist)
═══════════════════════════════════════════════════════════════════ */
.auto-visual {
display: flex;
flex-direction: column;
align-items: center;
padding: 1.25rem 1.5rem 0.5rem;
gap: 0.45rem;
height: 100%;
position: relative;
}
.auto-item {
display: flex;
align-items: center;
gap: 0.6rem;
width: 100%;
max-width: 32rem;
min-height: 2rem;
padding: 0.42rem 0.75rem;
border-radius: 999px;
border: 1px solid var(--border, rgba(255,255,255,0.1));
background: color-mix(in srgb, var(--background-inset) 70%, transparent);
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 0.7rem;
color: var(--foreground-muted, rgba(255,255,255,0.55));
overflow: hidden;
}
.auto-item span:last-child {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-width: 0;
}
.auto-check {
display: grid;
place-items: center;
flex: 0 0 1.1rem;
width: 1.1rem;
height: 1.1rem;
border-radius: 50%;
background: #2f6bff;
color: #fff;
font-size: 0.6rem;
font-weight: 800;
}
.auto-hidden {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.45rem;
width: 100%;
opacity: 0.42;
-webkit-mask-image: linear-gradient(180deg, black 0%, transparent 100%);
mask-image: linear-gradient(180deg, black 0%, transparent 100%);
}
.auto-item-muted .auto-check {
background: color-mix(in srgb, #2f6bff 35%, rgba(255,255,255,0.15));
}
/* full-width card gets a wider visual and shorter min-height */
.card-automation .card-inner {
min-height: 10rem;
flex-direction: row;
}
.card-automation .visual-area {
width: 52%;
height: auto;
flex-shrink: 0;
border-radius: 0 0 0 0.375rem;
}
.card-automation .card-body {
flex: 1;
justify-content: center;
}
@media (max-width: 600px) {
.card-automation .card-inner {
flex-direction: column;
}
.card-automation .visual-area {
width: 100%;
height: 9rem;
}
}
/* ═══════════════════════════════════════════════════════════════════
CARD 4 — Web Dev Visual (vertical bars, like Developer First)
═══════════════════════════════════════════════════════════════════ */
.dev-bars {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 0;
height: 100%;
padding: 1.25rem 1.25rem 0.5rem;
}
.dev-bar {
flex: 1;
background: color-mix(in srgb, var(--foreground, #fff) 12%, transparent);
border-radius: 2px 2px 0 0;
min-width: 3px;
max-width: 7px;
}
.dev-bar-accent {
background: var(--accent, #e8834a) !important;
}
/* ═══════════════════════════════════════════════════════════════════
CARD 5 — Secure Access Visual (shield, like Enterprise Ready)
═══════════════════════════════════════════════════════════════════ */
.access-shield {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}
.access-shield svg {
width: 7rem;
height: 7rem;
opacity: 0.18;
}
.access-shield-inner svg {
position: absolute;
width: 5rem;
height: 5rem;
opacity: 1;
}
/* lock icon overlay */
.access-chips {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
flex-wrap: wrap;
padding: 1rem;
z-index: 3;
}
.access-chip {
display: inline-flex;
align-items: center;
height: 1.6rem;
padding: 0 0.6rem;
border-radius: 999px;
border: 1px solid var(--border, rgba(255,255,255,0.1));
background: color-mix(in srgb, var(--background) 80%, transparent);
font-family: ui-monospace, monospace;
font-size: 0.62rem;
font-weight: 700;
letter-spacing: 0.05em;
color: var(--foreground-muted, rgba(255,255,255,0.5));
white-space: nowrap;
}
/* ═══════════════════════════════════════════════════════════════════
CARD 6 — Knowledge Visual (open book lines, like Real-time Sync)
═══════════════════════════════════════════════════════════════════ */
.knowledge-visual {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}
.knowledge-visual svg {
width: min(90%, 18rem);
height: auto;
opacity: 0.85;
}
</style>
<!-- ══════════════════════════════════════════════════════════════════════
CARD 1 — Интеграция анализа безопасности
══════════════════════════════════════════════════════════════════════ -->
<div class="card-shell card-security-analysis">
<div class="card-inner">
<div class="visual-area" style="height: 9.5rem;">
<div class="sa-visual" aria-hidden="true">
<!-- Row 1: SCA · SAST -->
<div class="sa-row">
<span class="sa-badge sa-badge-accent">SCA</span>
<span class="sa-badge">SAST</span>
</div>
<!-- Row 2: DAST · LINT (offset right) -->
<div class="sa-row">
<span class="sa-badge sa-badge-accent">DAST</span>
<span class="sa-badge">LINT</span>
</div>
<!-- Row 3: WAF · IaC -->
<div class="sa-row">
<span class="sa-badge">WAF</span>
<span class="sa-badge sa-badge-accent">IaC Scan</span>
</div>
</div>
</div>
<div class="card-body">
<p class="card-badge">Услуга</p>
<h3 class="card-title">Интеграция анализа безопасности</h3>
<p class="card-desc">
Интегрируем автоматический анализ кода на уязвимости на каждом этапе разработки.
Проверяем исходный код, тестируем работающее приложение и отслеживаем уязвимости
в библиотеках — всё автоматически в CI/CD без участия команды.
</p>
<div class="card-price">
<span class="card-price-from">от</span>
<span class="card-price-value">10 000 ₽</span>
</div>
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════════════
CARD 2 — Проверка защищённости
══════════════════════════════════════════════════════════════════════ -->
<div class="card-shell card-pentest">
<div class="card-inner">
<div class="visual-area" style="height: 9.5rem; overflow: hidden; position: relative;">
<div class="pt-visual" aria-hidden="true">
<div class="pt-vline"></div>
<div class="pt-arc-outer"></div>
<div class="pt-arc-outer-accent"></div>
<div class="pt-arc-inner"></div>
<div class="pt-arc-inner-accent"></div>
</div>
</div>
<div class="card-body">
<p class="card-badge">Услуга</p>
<h3 class="card-title">Проверка защищённости</h3>
<p class="card-desc">
Этично проверяем сервис или сервер на наличие уязвимостей: открытые точки входа,
слабые конфигурации и всё, что может стать проблемой раньше, чем вы об этом узнаете.
</p>
<div class="card-price">
<span class="card-price-from">от</span>
<span class="card-price-value">5 000 ₽</span>
</div>
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════════════
CARD 3 — Автоматизация (full-width)
══════════════════════════════════════════════════════════════════════ -->
<div class="card-shell card-automation">
<div class="card-inner">
<!-- Visual: checklist on the left side -->
<div class="visual-area">
<div class="auto-visual" aria-hidden="true">
{#each automationVisible as item, i (item)}
<div class="auto-item" class:auto-item-muted={i === 2}>
<span class="auto-check">✓</span>
<span>{item}</span>
</div>
{/each}
<div class="auto-hidden">
{#each automationHidden as item (item)}
<div class="auto-item auto-item-muted">
<span class="auto-check">✓</span>
<span>{item}</span>
</div>
{/each}
</div>
</div>
</div>
<!-- Text on the right -->
<div class="card-body">
<p class="card-badge">Услуга</p>
<h3 class="card-title">Автоматизация</h3>
<p class="card-desc">
Автоматизируем рутину — от простого bash-скрипта до сложных решений под
индивидуальные требования.
</p>
<div class="card-price">
<span class="card-price-from">от</span>
<span class="card-price-value">15 000 ₽</span>
</div>
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════════════
CARD 4 — Разработка под заказ
══════════════════════════════════════════════════════════════════════ -->
<div class="card-shell card-dev">
<div class="card-inner">
<div class="visual-area" style="height: 9.5rem;" aria-hidden="true">
<div class="dev-bars">
{#each Array(28) as _, i (i)}
{@const heights = [55,40,70,45,90,60,35,80,50,75,42,88,30,65,48,92,38,72,55,85,44,68,36,78,52,62,47,58]}
<div
class="dev-bar"
class:dev-bar-accent={[4,9,12,18,23,26].includes(i)}
style="height: {heights[i % heights.length]}%"
></div>
{/each}
</div>
</div>
<div class="card-body">
<p class="card-badge">Услуга</p>
<h3 class="card-title">Разработка под заказ</h3>
<p class="card-desc">
Создаём сайты, лендинги и веб-системы под любой стек — React, Svelte, Next.js,
Node.js и другие. Пишем чистый, поддерживаемый код и сдаём в срок.
</p>
<div class="card-price">
<span class="card-price-from">от</span>
<span class="card-price-value">20 000 ₽</span>
</div>
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════════════
CARD 5 — Настройка безопасного доступа
══════════════════════════════════════════════════════════════════════ -->
<div class="card-shell card-access">
<div class="card-inner">
<div class="visual-area" style="height: 9.5rem; position: relative;" aria-hidden="true">
<!-- Large faded shield -->
<div class="access-shield">
<svg viewBox="0 0 92 104" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M46 4L82 18V46C82 70 68 88 46 100C24 88 10 70 10 46V18L46 4Z"
stroke="currentColor"
stroke-width="1.5"
fill="none"
/>
</svg>
</div>
<!-- Chips for protocols -->
<div class="access-chips">
<span class="access-chip">mTLS</span>
<span class="access-chip">VPN</span>
<span class="access-chip">Zero Trust</span>
<span class="access-chip">SSH</span>
<span class="access-chip">OIDC</span>
</div>
</div>
<div class="card-body">
<p class="card-badge">Услуга</p>
<h3 class="card-title">Настройка безопасного доступа</h3>
<p class="card-desc">
Настраиваем и интегрируем защищённый доступ к сервисам и серверам. Подбираем
решение под задачу — mTLS, VPN, Zero Trust или другой подход. Доступ получают
только те, кому вы это разрешили.
</p>
<div class="card-price">
<span class="card-price-from">от</span>
<span class="card-price-value">10 000 ₽</span>
</div>
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════════════
CARD 6 — Знания каждому! (full-width)
══════════════════════════════════════════════════════════════════════ -->
<div class="card-shell card-knowledge">
<div class="card-inner" style="flex-direction: row; min-height: 10rem;">
<!-- Open book SVG visual -->
<div class="visual-area" style="width: 44%; height: auto; flex-shrink: 0;">
<div class="knowledge-visual" aria-hidden="true">
<svg viewBox="0 0 220 150" fill="none" xmlns="http://www.w3.org/2000/svg"
style="animation: bookFloat 6.8s ease-in-out infinite;">
<!-- left page -->
<path
d="M108 118C82 101 56 96 26 101V31C57 25 82 33 108 51Z"
fill="color-mix(in srgb, currentColor 8%, transparent)"
stroke="color-mix(in srgb, currentColor 20%, transparent)"
stroke-width="1.4"
/>
<!-- right page -->
<path
d="M112 118C138 101 164 96 194 101V31C163 25 138 33 112 51Z"
fill="color-mix(in srgb, currentColor 8%, transparent)"
stroke="color-mix(in srgb, currentColor 20%, transparent)"
stroke-width="1.4"
/>
<!-- spine -->
<path d="M110 51V122" stroke="color-mix(in srgb, currentColor 22%, transparent)" stroke-width="1.4" stroke-linecap="round"/>
<!-- left text lines -->
<path d="M43 51C62 49 80 53 96 63" stroke="color-mix(in srgb, currentColor 16%, transparent)" stroke-width="1.4" stroke-linecap="round" fill="none"/>
<path d="M43 70C63 68 80 72 96 82" stroke="color-mix(in srgb, currentColor 16%, transparent)" stroke-width="1.4" stroke-linecap="round" fill="none"/>
<path d="M43 89C63 87 80 91 96 101" stroke="color-mix(in srgb, currentColor 16%, transparent)" stroke-width="1.4" stroke-linecap="round" fill="none"/>
<!-- right text lines -->
<path d="M177 51C158 49 140 53 124 63" stroke="color-mix(in srgb, currentColor 16%, transparent)" stroke-width="1.4" stroke-linecap="round" fill="none"/>
<path d="M177 70C157 68 140 72 124 82" stroke="color-mix(in srgb, currentColor 16%, transparent)" stroke-width="1.4" stroke-linecap="round" fill="none"/>
<path d="M177 89C157 87 140 91 124 101" stroke="color-mix(in srgb, currentColor 16%, transparent)" stroke-width="1.4" stroke-linecap="round" fill="none"/>
<!-- shadow -->
<path d="M26 101C58 98 83 104 110 122C137 104 162 98 194 101"
stroke="color-mix(in srgb, currentColor 28%, transparent)" stroke-width="1.4" stroke-linecap="round" fill="none"/>
</svg>
</div>
</div>
<!-- Text -->
<div class="card-body" style="justify-content: center;">
<p class="card-badge">Открытые знания</p>
<h3 class="card-title">Знания каждому!</h3>
<p class="card-desc">
Пишем понятные статьи и гайды по DevSecOps и не только. Рассказываем как настроить
безопасность с нуля и сделать её частью культуры команды.
</p>
</div>
</div>
</div>
</section>
<style>
@keyframes bookFloat {
0%, 100% { transform: translateY(0) rotate(-1deg); }
50% { transform: translateY(-0.6rem) rotate(1deg); }
}
</style><script lang="ts">
// ─── Tool badges for card 1 ───────────────────────────────────────────────
const _securityTools = ["SCA", "SAST", "DAST", "LINT", "WAF", "IaC"];
// ─── Automation checklist items ───────────────────────────────────────────
const automationVisible = [
"ежедневный бэкап данных и логов",
"управление сетью и firewall-правилами",
"оптимизация работы git-репозиториев",
];
const automationHidden = [
"ротация ключей доступа",
"мониторинг состояния сервисов",
"автоочистка устаревших артефактов",
];
</script>
<section class="services-grid">
<style>
/* ── Grid layout ─────────────────────────────────────────────────── */
.services-grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto auto auto;
gap: 0.75rem;
width: 100%;
box-sizing: border-box;
}
/* Card 1 — top-left */
.card-security-analysis { grid-column: 1; grid-row: 1; }
/* Card 2 — top-right */
.card-pentest { grid-column: 2; grid-row: 1; }
/* Card 3 — full-width middle */
.card-automation { grid-column: 1 / -1; grid-row: 2; }
/* Card 4 — bottom-left */
.card-dev { grid-column: 1; grid-row: 3; }
/* Card 5 — bottom-right */
.card-access { grid-column: 2; grid-row: 3; }
/* Card 6 — full-width bottom (knowledge) */
.card-knowledge { grid-column: 1 / -1; grid-row: 4; }
@media (max-width: 600px) {
.services-grid {
grid-template-columns: 1fr;
}
.card-security-analysis,
.card-pentest,
.card-automation,
.card-dev,
.card-access,
.card-knowledge {
grid-column: 1;
grid-row: auto;
}
}
/* ── Shared card shell ────────────────────────────────────────────── */
.card-shell {
inset-shadow: var(--inset-shadow, inset 0 1px 0 rgba(255,255,255,0.06));
position: relative;
overflow: hidden;
border-radius: 0.5rem;
background: var(--background-inset);
padding: 0.375rem;
}
.card-inner {
position: relative;
border-radius: 0.375rem;
background: var(--background);
overflow: hidden;
display: flex;
flex-direction: column;
min-height: 18rem;
}
/* ── Visual areas ────────────────────────────────────────────────── */
.visual-area {
position: relative;
height: 9rem;
overflow: hidden;
flex-shrink: 0;
}
/* ── Card text ───────────────────────────────────────────────────── */
.card-body {
padding: 1rem 1.25rem 1.25rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
flex: 1;
}
.card-badge {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 0.6rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--foreground-muted, rgba(255,255,255,0.4));
margin-bottom: 0.25rem;
}
.card-title {
font-size: 1rem;
font-weight: 600;
line-height: 1.3;
color: var(--foreground);
margin: 0;
}
.card-desc {
font-size: 0.82rem;
line-height: 1.6;
color: var(--foreground-muted, rgba(255,255,255,0.55));
margin: 0;
flex: 1;
}
@media (min-width: 768px) {
.card-title { font-size: 1.125rem; }
.card-desc { font-size: 0.9rem; }
.card-badge { font-size: 0.65rem; }
}
.card-price {
display: flex;
align-items: baseline;
gap: 0.3em;
margin-top: 0.75rem;
}
.card-price-from {
font-family: ui-monospace, monospace;
font-size: 0.6rem;
font-weight: 500;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--foreground-muted, rgba(255,255,255,0.35));
}
.card-price-value {
font-size: 1rem;
font-weight: 600;
color: var(--foreground);
letter-spacing: -0.01em;
}
/* ═══════════════════════════════════════════════════════════════════
CARD 1 — Security Analysis Visual
Tool badges on horizontal lines (like the Seamless Integrations card)
═══════════════════════════════════════════════════════════════════ */
.sa-visual {
display: flex;
flex-direction: column;
justify-content: space-around;
padding: 1.1rem 0 0.5rem;
height: 100%;
gap: 0;
}
.sa-row {
position: relative;
display: flex;
align-items: center;
justify-content: center;
height: 2.1rem;
gap: 0.75rem;
}
/* horizontal connector line */
.sa-row::before {
content: '';
position: absolute;
inset: 0;
margin: auto 0;
height: 1px;
background: var(--border, rgba(255,255,255,0.1));
}
.sa-badge {
position: relative;
display: inline-flex;
align-items: center;
height: 1.75rem;
padding: 0 0.65rem;
border-radius: 999px;
background: var(--background);
border: 1px solid var(--border, rgba(255,255,255,0.12));
box-shadow: 0 2px 8px rgba(0,0,0,0.28);
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 0.65rem;
font-weight: 700;
letter-spacing: 0.06em;
color: var(--foreground-muted, rgba(255,255,255,0.55));
white-space: nowrap;
z-index: 2;
}
/* accent the first badge in each row */
.sa-badge-accent {
color: var(--accent, #e8834a);
border-color: color-mix(in srgb, var(--accent, #e8834a) 30%, transparent);
}
/* slight stagger while keeping badges in the visible center zone */
.sa-row:nth-child(1) { transform: translateX(-1.5rem); }
.sa-row:nth-child(2) { transform: translateX(1.5rem); }
.sa-row:nth-child(3) { transform: translateX(-0.75rem); }
/* ═══════════════════════════════════════════════════════════════════
CARD 2 — Pentest Visual (concentric arcs, like Real-time Sync)
═══════════════════════════════════════════════════════════════════ */
.pt-visual {
position: absolute;
inset: 0;
}
/* vertical centre line */
.pt-vline {
position: absolute;
left: 50%;
top: 0; bottom: 0;
width: 1px;
background: color-mix(in srgb, var(--foreground, #fff) 12%, transparent);
}
/* outer arc */
.pt-arc-outer {
position: absolute;
left: -3rem; right: -3rem;
top: 1.2rem;
aspect-ratio: 1;
border-radius: 50%;
border: 1px solid color-mix(in srgb, var(--foreground, #fff) 10%, transparent);
}
/* outer arc accent half */
.pt-arc-outer-accent {
position: absolute;
left: -3rem; right: -3rem;
top: 1.2rem;
aspect-ratio: 1;
border-radius: 50%;
border: 1px solid var(--accent, #e8834a);
/* show only right half */
-webkit-mask-image: linear-gradient(90deg, transparent 50%, black 50%);
mask-image: linear-gradient(90deg, transparent 50%, black 50%);
}
/* inner arc */
.pt-arc-inner {
position: absolute;
left: 0; right: 0;
top: 3.5rem;
aspect-ratio: 1;
border-radius: 50%;
border: 1px solid color-mix(in srgb, var(--foreground, #fff) 10%, transparent);
}
/* inner arc accent half — lime, like the original */
.pt-arc-inner-accent {
position: absolute;
left: 0; right: 0;
top: 3.5rem;
aspect-ratio: 1;
border-radius: 50%;
border: 1px solid #84cc16;
-webkit-mask-image: linear-gradient(90deg, black 50%, transparent 50%);
mask-image: linear-gradient(90deg, black 50%, transparent 50%);
}
/* ═══════════════════════════════════════════════════════════════════
CARD 3 — Automation (full-width checklist)
═══════════════════════════════════════════════════════════════════ */
.auto-visual {
display: flex;
flex-direction: column;
align-items: center;
padding: 1.25rem 1.5rem 0.5rem;
gap: 0.45rem;
height: 100%;
position: relative;
}
.auto-item {
display: flex;
align-items: center;
gap: 0.6rem;
width: 100%;
max-width: 32rem;
min-height: 2rem;
padding: 0.42rem 0.75rem;
border-radius: 999px;
border: 1px solid var(--border, rgba(255,255,255,0.1));
background: color-mix(in srgb, var(--background-inset) 70%, transparent);
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 0.7rem;
color: var(--foreground-muted, rgba(255,255,255,0.55));
overflow: hidden;
}
.auto-item span:last-child {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-width: 0;
}
.auto-check {
display: grid;
place-items: center;
flex: 0 0 1.1rem;
width: 1.1rem;
height: 1.1rem;
border-radius: 50%;
background: #2f6bff;
color: #fff;
font-size: 0.6rem;
font-weight: 800;
}
.auto-hidden {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.45rem;
width: 100%;
opacity: 0.42;
-webkit-mask-image: linear-gradient(180deg, black 0%, transparent 100%);
mask-image: linear-gradient(180deg, black 0%, transparent 100%);
}
.auto-item-muted .auto-check {
background: color-mix(in srgb, #2f6bff 35%, rgba(255,255,255,0.15));
}
/* full-width card gets a wider visual and shorter min-height */
.card-automation .card-inner {
min-height: 10rem;
flex-direction: row;
}
.card-automation .visual-area {
width: 52%;
height: auto;
flex-shrink: 0;
border-radius: 0 0 0 0.375rem;
}
.card-automation .card-body {
flex: 1;
justify-content: center;
}
@media (max-width: 600px) {
.card-automation .card-inner {
flex-direction: column;
}
.card-automation .visual-area {
width: 100%;
height: 9rem;
}
}
/* ═══════════════════════════════════════════════════════════════════
CARD 4 — Web Dev Visual (vertical bars, like Developer First)
═══════════════════════════════════════════════════════════════════ */
.dev-bars {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 0;
height: 100%;
padding: 1.25rem 1.25rem 0.5rem;
}
.dev-bar {
flex: 1;
background: color-mix(in srgb, var(--foreground, #fff) 12%, transparent);
border-radius: 2px 2px 0 0;
min-width: 3px;
max-width: 7px;
}
.dev-bar-accent {
background: var(--accent, #e8834a) !important;
}
/* ═══════════════════════════════════════════════════════════════════
CARD 5 — Secure Access Visual (shield, like Enterprise Ready)
═══════════════════════════════════════════════════════════════════ */
.access-shield {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}
.access-shield svg {
width: 7rem;
height: 7rem;
opacity: 0.18;
}
.access-shield-inner svg {
position: absolute;
width: 5rem;
height: 5rem;
opacity: 1;
}
/* lock icon overlay */
.access-chips {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
flex-wrap: wrap;
padding: 1rem;
z-index: 3;
}
.access-chip {
display: inline-flex;
align-items: center;
height: 1.6rem;
padding: 0 0.6rem;
border-radius: 999px;
border: 1px solid var(--border, rgba(255,255,255,0.1));
background: color-mix(in srgb, var(--background) 80%, transparent);
font-family: ui-monospace, monospace;
font-size: 0.62rem;
font-weight: 700;
letter-spacing: 0.05em;
color: var(--foreground-muted, rgba(255,255,255,0.5));
white-space: nowrap;
}
/* ═══════════════════════════════════════════════════════════════════
CARD 6 — Knowledge Visual (open book lines, like Real-time Sync)
═══════════════════════════════════════════════════════════════════ */
.knowledge-visual {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
}
.knowledge-visual svg {
width: min(90%, 18rem);
height: auto;
opacity: 0.85;
}
</style>
<!-- ══════════════════════════════════════════════════════════════════════
CARD 1 — Интеграция анализа безопасности
══════════════════════════════════════════════════════════════════════ -->
<div class="card-shell card-security-analysis">
<div class="card-inner">
<div class="visual-area" style="height: 9.5rem;">
<div class="sa-visual" aria-hidden="true">
<!-- Row 1: SCA · SAST -->
<div class="sa-row">
<span class="sa-badge sa-badge-accent">SCA</span>
<span class="sa-badge">SAST</span>
</div>
<!-- Row 2: DAST · LINT (offset right) -->
<div class="sa-row">
<span class="sa-badge sa-badge-accent">DAST</span>
<span class="sa-badge">LINT</span>
</div>
<!-- Row 3: WAF · IaC -->
<div class="sa-row">
<span class="sa-badge">WAF</span>
<span class="sa-badge sa-badge-accent">IaC Scan</span>
</div>
</div>
</div>
<div class="card-body">
<p class="card-badge">Услуга</p>
<h3 class="card-title">Интеграция анализа безопасности</h3>
<p class="card-desc">
Интегрируем автоматический анализ кода на уязвимости на каждом этапе разработки.
Проверяем исходный код, тестируем работающее приложение и отслеживаем уязвимости
в библиотеках — всё автоматически в CI/CD без участия команды.
</p>
<div class="card-price">
<span class="card-price-from">от</span>
<span class="card-price-value">10 000 ₽</span>
</div>
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════════════
CARD 2 — Проверка защищённости
══════════════════════════════════════════════════════════════════════ -->
<div class="card-shell card-pentest">
<div class="card-inner">
<div class="visual-area" style="height: 9.5rem; overflow: hidden; position: relative;">
<div class="pt-visual" aria-hidden="true">
<div class="pt-vline"></div>
<div class="pt-arc-outer"></div>
<div class="pt-arc-outer-accent"></div>
<div class="pt-arc-inner"></div>
<div class="pt-arc-inner-accent"></div>
</div>
</div>
<div class="card-body">
<p class="card-badge">Услуга</p>
<h3 class="card-title">Проверка защищённости</h3>
<p class="card-desc">
Этично проверяем сервис или сервер на наличие уязвимостей: открытые точки входа,
слабые конфигурации и всё, что может стать проблемой раньше, чем вы об этом узнаете.
</p>
<div class="card-price">
<span class="card-price-from">от</span>
<span class="card-price-value">5 000 ₽</span>
</div>
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════════════
CARD 3 — Автоматизация (full-width)
══════════════════════════════════════════════════════════════════════ -->
<div class="card-shell card-automation">
<div class="card-inner">
<!-- Visual: checklist on the left side -->
<div class="visual-area">
<div class="auto-visual" aria-hidden="true">
{#each automationVisible as item, i (item)}
<div class="auto-item" class:auto-item-muted={i === 2}>
<span class="auto-check">✓</span>
<span>{item}</span>
</div>
{/each}
<div class="auto-hidden">
{#each automationHidden as item (item)}
<div class="auto-item auto-item-muted">
<span class="auto-check">✓</span>
<span>{item}</span>
</div>
{/each}
</div>
</div>
</div>
<!-- Text on the right -->
<div class="card-body">
<p class="card-badge">Услуга</p>
<h3 class="card-title">Автоматизация</h3>
<p class="card-desc">
Автоматизируем рутину — от простого bash-скрипта до сложных решений под
индивидуальные требования.
</p>
<div class="card-price">
<span class="card-price-from">от</span>
<span class="card-price-value">15 000 ₽</span>
</div>
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════════════
CARD 4 — Разработка под заказ
══════════════════════════════════════════════════════════════════════ -->
<div class="card-shell card-dev">
<div class="card-inner">
<div class="visual-area" style="height: 9.5rem;" aria-hidden="true">
<div class="dev-bars">
{#each Array(28) as _, i (i)}
{@const heights = [55,40,70,45,90,60,35,80,50,75,42,88,30,65,48,92,38,72,55,85,44,68,36,78,52,62,47,58]}
<div
class="dev-bar"
class:dev-bar-accent={[4,9,12,18,23,26].includes(i)}
style="height: {heights[i % heights.length]}%"
></div>
{/each}
</div>
</div>
<div class="card-body">
<p class="card-badge">Услуга</p>
<h3 class="card-title">Разработка под заказ</h3>
<p class="card-desc">
Создаём сайты, лендинги и веб-системы под любой стек — React, Svelte, Next.js,
Node.js и другие. Пишем чистый, поддерживаемый код и сдаём в срок.
</p>
<div class="card-price">
<span class="card-price-from">от</span>
<span class="card-price-value">20 000 ₽</span>
</div>
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════════════
CARD 5 — Настройка безопасного доступа
══════════════════════════════════════════════════════════════════════ -->
<div class="card-shell card-access">
<div class="card-inner">
<div class="visual-area" style="height: 9.5rem; position: relative;" aria-hidden="true">
<!-- Large faded shield -->
<div class="access-shield">
<svg viewBox="0 0 92 104" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M46 4L82 18V46C82 70 68 88 46 100C24 88 10 70 10 46V18L46 4Z"
stroke="currentColor"
stroke-width="1.5"
fill="none"
/>
</svg>
</div>
<!-- Chips for protocols -->
<div class="access-chips">
<span class="access-chip">mTLS</span>
<span class="access-chip">VPN</span>
<span class="access-chip">Zero Trust</span>
<span class="access-chip">SSH</span>
<span class="access-chip">OIDC</span>
</div>
</div>
<div class="card-body">
<p class="card-badge">Услуга</p>
<h3 class="card-title">Настройка безопасного доступа</h3>
<p class="card-desc">
Настраиваем и интегрируем защищённый доступ к сервисам и серверам. Подбираем
решение под задачу — mTLS, VPN, Zero Trust или другой подход. Доступ получают
только те, кому вы это разрешили.
</p>
<div class="card-price">
<span class="card-price-from">от</span>
<span class="card-price-value">10 000 ₽</span>
</div>
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════════════════════════════
CARD 6 — Знания каждому! (full-width)
══════════════════════════════════════════════════════════════════════ -->
<div class="card-shell card-knowledge">
<div class="card-inner" style="flex-direction: row; min-height: 10rem;">
<!-- Open book SVG visual -->
<div class="visual-area" style="width: 44%; height: auto; flex-shrink: 0;">
<div class="knowledge-visual" aria-hidden="true">
<svg viewBox="0 0 220 150" fill="none" xmlns="http://www.w3.org/2000/svg"
style="animation: bookFloat 6.8s ease-in-out infinite;">
<!-- left page -->
<path
d="M108 118C82 101 56 96 26 101V31C57 25 82 33 108 51Z"
fill="color-mix(in srgb, currentColor 8%, transparent)"
stroke="color-mix(in srgb, currentColor 20%, transparent)"
stroke-width="1.4"
/>
<!-- right page -->
<path
d="M112 118C138 101 164 96 194 101V31C163 25 138 33 112 51Z"
fill="color-mix(in srgb, currentColor 8%, transparent)"
stroke="color-mix(in srgb, currentColor 20%, transparent)"
stroke-width="1.4"
/>
<!-- spine -->
<path d="M110 51V122" stroke="color-mix(in srgb, currentColor 22%, transparent)" stroke-width="1.4" stroke-linecap="round"/>
<!-- left text lines -->
<path d="M43 51C62 49 80 53 96 63" stroke="color-mix(in srgb, currentColor 16%, transparent)" stroke-width="1.4" stroke-linecap="round" fill="none"/>
<path d="M43 70C63 68 80 72 96 82" stroke="color-mix(in srgb, currentColor 16%, transparent)" stroke-width="1.4" stroke-linecap="round" fill="none"/>
<path d="M43 89C63 87 80 91 96 101" stroke="color-mix(in srgb, currentColor 16%, transparent)" stroke-width="1.4" stroke-linecap="round" fill="none"/>
<!-- right text lines -->
<path d="M177 51C158 49 140 53 124 63" stroke="color-mix(in srgb, currentColor 16%, transparent)" stroke-width="1.4" stroke-linecap="round" fill="none"/>
<path d="M177 70C157 68 140 72 124 82" stroke="color-mix(in srgb, currentColor 16%, transparent)" stroke-width="1.4" stroke-linecap="round" fill="none"/>
<path d="M177 89C157 87 140 91 124 101" stroke="color-mix(in srgb, currentColor 16%, transparent)" stroke-width="1.4" stroke-linecap="round" fill="none"/>
<!-- shadow -->
<path d="M26 101C58 98 83 104 110 122C137 104 162 98 194 101"
stroke="color-mix(in srgb, currentColor 28%, transparent)" stroke-width="1.4" stroke-linecap="round" fill="none"/>
</svg>
</div>
</div>
<!-- Text -->
<div class="card-body" style="justify-content: center;">
<p class="card-badge">Открытые знания</p>
<h3 class="card-title">Знания каждому!</h3>
<p class="card-desc">
Пишем понятные статьи и гайды по DevSecOps и не только. Рассказываем как настроить
безопасность с нуля и сделать её частью культуры команды.
</p>
</div>
</div>
</div>
</section>
<style>
@keyframes bookFloat {
0%, 100% { transform: translateY(0) rotate(-1deg); }
50% { transform: translateY(-0.6rem) rotate(1deg); }
}
</style>Карточки
| Карточка | Визуализация | Услуга |
|---|---|---|
| Security Analysis | Tool badges на линиях | SCA, SAST, DAST, LINT, WAF, IaC |
| Pentest | Концентрические дуги | Проверка защищённости |
| Automation | Чеклист с fade | Автоматизация процессов |
| Dev | Вертикальные бары | Разработка под заказ |
| Access | Shield + протокол chips | Настройка безопасного доступа |
| Knowledge | Анимированная книга | Открытые знания |
Особенности
- Адаптивная сетка: 2 колонки → 1 колонка на мобильных
- Карточки Automation и Knowledge — на всю ширину
- CSS-only анимация книги (
bookFloatkeyframes) - Поддержка тёмной/светлой темы через CSS-переменные
- Все визуализации — чистый HTML/CSS/SVG, без зависимостей
Использование
<script>
import CardSection from '$lib/components/ui/CardSection.svelte';
</script>
<CardSection /><script>
import CardSection from '$lib/components/ui/CardSection.svelte';
</script>
<CardSection />Кастомизация
Компонент не принимает пропсов — содержимое задано жёстко. Для изменений:
- Тексты и цены: заголовки, описания,
.card-price-value - Визуализации: CSS и SVG-разметка внутри компонента
- Списки: массивы
automationVisible,automationHidden
