/* Обвязка стенда. Сюда не пишем стили компонента — только рамки, сетки, подписи и подложки. Стили neu-card живут в public/css/main.css. */ .lab { max-width: 62rem; margin: 0 auto; padding: clamp(2rem, 5vw, 3.5rem) var(--space) 8rem; } .lab__head { margin-bottom: clamp(2.5rem, 6vw, 4rem); } .lab__h1 { margin: 0 0 0.5rem; font-family: var(--font-accent); font-size: clamp(1.8rem, 4vw, 2.5rem); font-weight: 700; line-height: 1.1; } .lab__sub { margin: 0 0 1.25rem; max-width: 42rem; color: var(--text-muted); line-height: 1.6; } .lab__nav { display: flex; flex-wrap: wrap; gap: 0.4rem 0.75rem; font-size: 0.85rem; } .lab__nav a { color: var(--accent-text); text-decoration: none; border-bottom: 1px solid transparent; } .lab__nav a:hover { border-bottom-color: currentColor; } .lab__sec { padding-top: clamp(2rem, 5vw, 3rem); margin-bottom: clamp(2rem, 5vw, 3rem); scroll-margin-top: 1.5rem; } .lab__h2 { margin: 0 0 0.5rem; font-family: var(--font-accent); font-size: clamp(1.25rem, 2.5vw, 1.6rem); font-weight: 700; line-height: 1.2; } .lab__h3 { margin: 2.5rem 0 0.5rem; font-family: var(--font-accent); font-size: 1rem; font-weight: 700; line-height: 1.2; color: var(--text); } .lab__note { margin: 0 0 1.5rem; max-width: 46rem; font-size: 0.9rem; line-height: 1.6; color: var(--text-muted); } .lab__caption { margin: 0.75rem 0 0; font-size: 0.78rem; line-height: 1.4; color: var(--text-muted); } .lab code { font-family: var(--font); font-size: 0.92em; padding: 0.1em 0.35em; border-radius: var(--radius-sm); background: color-mix(in srgb, var(--text) 8%, transparent); } .lab__row { display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: flex-start; } .lab__row--wrap .neu-card { flex: 0 0 auto; } /* ── Токены ─────────────────────────────────────────────────────── */ .lab__tokens { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 0.75rem; } .lab__token { margin: 0; padding: 0.9rem 1rem; border-radius: var(--radius-md); background: var(--bg-elevated); border: 1px solid var(--line); } .lab__token dt { font-size: 0.82rem; margin-bottom: 0.3rem; } .lab__token dt span { color: var(--text-muted); margin-left: 0.35rem; } .lab__token dd { margin: 0; font-size: 0.82rem; line-height: 1.5; color: var(--text-muted); } /* ── Фоны ───────────────────────────────────────────────────────── */ .lab__bg-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); gap: 1.5rem; } .lab__bg-cell { padding: 1.75rem; border-radius: var(--radius-md); border: 1px solid var(--line); } .lab__bg-cell[data-bg="page"] { background: var(--bg); } .lab__bg-cell[data-bg="elevated"] { background: var(--bg-elevated); } .lab__bg-cell[data-bg="surface"] { background: var(--surface); } .lab__bg-cell[data-bg="accent"] { background: var(--accent); color: var(--on-accent, var(--text)); } .lab__bg-cell[data-bg="accent"] .lab__caption { color: color-mix(in srgb, var(--on-accent, var(--text)) 78%, transparent); } .lab__bg-cell[data-bg="media"] { background-image: url("/assets/template-elements-demo/img-long.webp"); background-size: cover; background-position: center; color: #fff; } .lab__bg-cell[data-bg="media"] .lab__caption { color: rgba(255, 255, 255, 0.85); text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6); } .lab__bg-cell[data-bg="media"] .neu-card { background: var(--surface); color: var(--text); } /* ── Состояния ──────────────────────────────────────────────────── */ .lab__state { display: flex; flex-direction: column; } .lab__depth { gap: 1.25rem; } .lab__depth .neu-card { min-width: 150px; } /* ── Сетка ──────────────────────────────────────────────────────── */ .lab__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: 1rem; margin-bottom: 1.5rem; } .lab__grid--3 { grid-template-columns: repeat(3, 1fr); } .lab__grid--tight { gap: 0.5rem; } @media (max-width: 640px) { .lab__grid--3 { grid-template-columns: 1fr; } } /* ── Переключатель стенда ───────────────────────────────────────── */ .lab-switch { position: fixed; right: max(1rem, env(safe-area-inset-right, 0px)); bottom: max(1rem, env(safe-area-inset-bottom, 0px)); z-index: 200; display: flex; align-items: center; gap: 0.25rem; padding: 0.35rem; border-radius: 999px; background: var(--surface); border: 1px solid var(--line); box-shadow: 0 8px 24px hsla(0, 0%, 0%, 0.25); font-size: 0.78rem; } .lab-switch__btn { appearance: none; border: 0; padding: 0.35rem 0.7rem; border-radius: 999px; background: transparent; color: var(--text-muted); font: inherit; font-family: var(--font-accent); cursor: pointer; } .lab-switch__btn:hover { color: var(--text); background: color-mix(in srgb, var(--text) 8%, transparent); } .lab-switch__btn[aria-pressed="true"] { background: var(--accent); color: var(--on-accent, #fff); } .lab-switch__sep { width: 1px; height: 1.25rem; margin: 0 0.15rem; background: var(--line); } /* ── Карточка в карточке ────────────────────────────────────────── */ .lab__nest { margin-bottom: 1.5rem; } /* Внешняя карточка: увеличенные поля и минимум, чтобы вместить вложенные */ .neu-card--nest { --neu-pad: 1.75rem; --neu-min-w: 0; --neu-min-h: 0; gap: 1rem; justify-content: flex-start; } .neu-card__nest-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; } .neu-card__nest-row { display: flex; flex-wrap: wrap; gap: 1rem; } @media (max-width: 640px) { .neu-card__nest-grid { grid-template-columns: 1fr; } } /* ── Шейдер-карточка (прототип Paper Shaders) ───────────────────── */ /* canvas шейдера — фоновый слой ВНУТРИ карточки, под контентом. pointer-events:none — чтобы клик/hover доходили до самой карточки. */ .contact-card--shader { overflow: hidden; isolation: isolate; } .card-shader { position: absolute; inset: 0; z-index: 0; border-radius: inherit; overflow: hidden; pointer-events: none; /* нейтральный фон-запас: если WebGL не отрисовал, карточка выглядит как обычная neu-card (--neu-bg). Когда шейдер рисует — он перекрывает этот фон. */ background: var(--neu-bg); } /* ── neu-card + живой шейдер-слой под бликом ─────────────────────────────── Обычная неуморфная карточка (тени снаружи + блик) с анимированным шейдером ВНУТРИ, под бликом. Слои (снизу вверх): 0 — .card-shader (canvas шейдера) 1 — ::before (блик --neu-glow) И ::after (внутренний объём inset-теней) 2 — контент карточки Важно: box-shadow родителя рисуется НИЖЕ дочерних слоёв, поэтому шейдер (z:0) перекрыл бы внутренние тени. Чтобы объём был виден ПОВЕРХ шейдера, внешние тени (drop) оставляем на карточке, а внутренний объём (inset) выносим на ::after с z-index:1 — он рисуется поверх шейдера. */ .neu-card--shader { background: transparent; /* фон уходит, шейдер снизу */ isolation: isolate; /* только внешний объём (приподнятость) */ box-shadow: var(--neu-drop-1), var(--neu-drop-2), var(--neu-drop-3); } .neu-card--shader::before { content: ""; position: absolute; inset: 0; z-index: 1; /* поверх шейдера (z:0) */ border-radius: inherit; pointer-events: none; background: var(--neu-glow); /* блик из левого верхнего угла */ } .neu-card--shader::after { content: ""; position: absolute; inset: 0; z-index: 1; /* поверх шейдера, рядом с бликом */ border-radius: inherit; pointer-events: none; /* внутренний объём (выпуклость): белая кайма сверху-слева + тёмная снизу-справа */ box-shadow: var(--neu-in-light-1), var(--neu-in-light-2), var(--neu-in-dark-1), var(--neu-in-dark-2); } .neu-card--shader > *:not(.card-shader) { position: relative; z-index: 2; /* контент над бликом/объёмом и шейдером */ } .contact-card--shader .contact-card__icon, .contact-card--shader .contact-card__body, .contact-card--shader .contact-card__corner { position: relative; z-index: 1; } /* отдельная демо-карточка шейдера */ .shader-demo-card { position: relative; overflow: hidden; isolation: isolate; width: 100%; max-width: 360px; min-height: 220px; border-radius: var(--radius-card); background: var(--neu-bg); box-shadow: var(--neu-shadow); } .shader-demo-card--wide { max-width: 420px; min-height: 260px; } .shader-demo-card__label { position: absolute; left: 1rem; bottom: 0.85rem; z-index: 1; font-family: var(--font-accent); font-size: 0.95rem; font-weight: 600; color: #fff; text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55); pointer-events: none; }