la-rose/public/styles.css

4621 lines
93 KiB
CSS
Raw Permalink 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.

/* ============================================================================
La Rose — storefront styles
Design system lifted from the OpenPencil canvas (designs/design.fig):
palette, type scale, spacing, radii, shadows, components and states.
Mobile-first; the design is drawn at 390 and 1440.
========================================================================== */
:root {
/* Palette — Rose */
--rose-500: #d6336c;
--rose-600: #b22759;
--rose-700: #93214a;
--rose-100: #f7d9e4;
--rose-50: #fdf2f6;
/* Support colours */
--sage-500: #3f6f5b;
--sage-100: #e3ede7;
--gold-500: #c8a96a;
--gold-50: #f6efe0;
--ink-900: #1f1a1c;
--ink-600: #5c5457;
--ink-400: #8e8589;
--line-300: #d9d3d6;
--line-100: #eee9eb;
--surface: #ffffff;
--cream-100: #faf6f2;
--cream-200: #f1eae5;
--success: #2f9e63;
--warning: #e0a100;
--error: #d64545;
--disabled: #c9c2c5;
--whatsapp: #25d366;
--telegram: #2aabee;
--instagram: #e1306c;
--vk: #0077ff;
--free: #16a34a;
--footer-line: #3a2f33;
/* Type */
--font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;
--font-display: 'Playfair Display', Georgia, 'Times New Roman', serif;
/* Spacing / radii / shadow */
--r-sm: 4px;
--r-md: 8px;
--r-lg: 12px;
--r-xl: 16px;
--r-2xl: 24px;
--r-pill: 999px;
--shadow-sm: 0 2px 6px rgba(31, 26, 28, 0.1);
--shadow-md: 0 8px 24px rgba(31, 26, 28, 0.12);
--shadow-lg: 0 20px 48px rgba(31, 26, 28, 0.16);
--ease: cubic-bezier(0.4, 0, 0.2, 1);
--header-h: 60px;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
/* The `hidden` attribute must win over component display rules (e.g. the
lightbox uses `display: flex`, the menu panel `display: grid`), otherwise a
hidden overlay still renders and cannot be closed. */
[hidden] {
display: none !important;
}
html {
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
min-height: 100vh;
display: flex;
flex-direction: column;
background: var(--cream-100);
color: var(--ink-900);
font-family: var(--font-sans);
font-size: 15px;
line-height: 1.6;
-webkit-font-smoothing: antialiased;
overflow-x: hidden;
}
img {
max-width: 100%;
display: block;
}
a {
color: inherit;
text-decoration: none;
}
button {
font-family: inherit;
}
h1,
h2,
h3 {
font-family: var(--font-display);
font-weight: 700;
line-height: 1.2;
margin: 0;
}
p {
margin: 0;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
:focus-visible {
outline: 3px solid var(--rose-100);
outline-offset: 2px;
border-radius: 4px;
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
/* ---------- primitives ---------- */
.container {
width: 100%;
max-width: 1440px;
margin: 0 auto;
padding-inline: clamp(20px, 5.56vw, 80px);
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
border: 0;
}
.skip-link {
position: absolute;
left: 16px;
top: -60px;
z-index: 100;
padding: 10px 16px;
border-radius: var(--r-lg);
background: var(--ink-900);
color: #fff;
transition: top 0.15s var(--ease);
}
.skip-link:focus {
top: 12px;
}
.muted {
color: var(--ink-400);
}
.small {
font-size: 13px;
}
.overline {
font-size: 11px;
letter-spacing: 2px;
font-weight: 600;
text-transform: uppercase;
color: var(--rose-500);
}
.section-title {
font-size: 22px;
line-height: 1.2;
}
/* ---------- buttons ---------- */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 10px;
min-height: 52px;
padding: 0 24px;
border: 0;
border-radius: var(--r-lg);
font-size: 15px;
font-weight: 600;
line-height: 1.2;
cursor: pointer;
transition: background-color 0.18s var(--ease), color 0.18s var(--ease), border-color 0.18s var(--ease),
transform 0.18s var(--ease);
white-space: nowrap;
}
.btn:active {
transform: translateY(1px);
}
.btn--primary {
background: var(--rose-500);
color: #fff;
}
.btn--primary:hover {
background: var(--rose-600);
}
.btn--primary:active {
background: var(--rose-700);
}
.btn--dark {
background: var(--ink-900);
color: #fff;
}
.btn--dark:hover {
background: #000;
}
.btn--outline {
background: #fff;
border: 1.5px solid var(--rose-500);
color: var(--rose-500);
}
.btn--outline:hover {
background: var(--rose-50);
}
.btn--outline-dark {
background: #fff;
border: 1.5px solid var(--ink-900);
color: var(--ink-900);
}
.btn--outline-dark:hover {
background: var(--cream-100);
}
.btn--ghost {
background: #fff;
color: var(--ink-900);
border: 1px solid var(--line-300);
}
.btn--ghost:hover {
border-color: var(--ink-900);
}
.btn--sm {
min-height: 44px;
padding: 0 18px;
font-size: 14px;
}
.btn--lg {
min-height: 56px;
padding: 0 30px;
}
.btn--block {
width: 100%;
}
.btn[disabled],
.btn[aria-disabled='true'] {
background: var(--disabled);
color: var(--ink-400);
border-color: transparent;
cursor: not-allowed;
transform: none;
}
.btn--loading {
position: relative;
color: transparent;
}
.btn--loading::after {
content: '';
position: absolute;
width: 18px;
height: 18px;
border-radius: 50%;
border: 2px solid rgba(255, 255, 255, 0.45);
border-top-color: #fff;
animation: spin 0.7s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* ---------- pills ---------- */
.pill {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 5px 12px;
border-radius: 14px;
font-size: 12px;
font-weight: 600;
line-height: 1.2;
}
.pill--wa {
background: var(--whatsapp);
color: #fff;
}
.pill--tg {
background: var(--telegram);
color: #fff;
}
/* Instagram's brand colour is a gradient; fall back to --instagram where the
gradient is not painted. */
.pill--ig {
background: var(--instagram);
background: linear-gradient(135deg, #f9ce34 0%, #ee2a7b 55%, #6228d7 100%);
color: #fff;
}
.pill--vk {
background: var(--vk);
color: #fff;
}
.pill__ico {
font-size: 12px;
}
/* ---------- badges & chips ---------- */
.badge {
display: inline-flex;
align-items: center;
padding: 3px 8px;
border-radius: 6px;
font-size: 11px;
font-weight: 700;
line-height: 1.3;
letter-spacing: 0.02em;
text-transform: uppercase;
color: #fff;
background: var(--rose-500);
}
.badge--hit {
background: var(--rose-500);
}
.badge--new {
background: var(--success);
}
.badge--sale {
background: var(--warning);
}
.badge--discount {
background: var(--error);
}
.badge--out {
background: var(--cream-200);
color: var(--ink-400);
}
.chipset {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.chip {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 7px 14px;
border-radius: 14px;
border: 1px solid var(--line-300);
background: #fff;
color: var(--ink-900);
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.15s var(--ease);
}
.chip:hover {
border-color: var(--ink-400);
}
.chip--active {
background: var(--ink-900);
border-color: var(--ink-900);
color: #fff;
}
.chip--accent {
background: var(--rose-50);
border-color: var(--rose-100);
color: var(--rose-600);
}
/* ---------- forms ---------- */
.field {
display: flex;
flex-direction: column;
gap: 6px;
margin-bottom: 16px;
}
.field__label {
font-size: 13px;
font-weight: 600;
color: var(--ink-600);
}
.field__hint {
font-size: 12px;
color: var(--ink-400);
}
.input,
.select,
.textarea {
width: 100%;
min-height: 50px;
padding: 12px 16px;
border: 1px solid var(--line-300);
border-radius: var(--r-lg);
background: #fff;
color: var(--ink-900);
font-family: inherit;
font-size: 15px;
transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}
.textarea {
min-height: 96px;
resize: vertical;
}
.input::placeholder,
.textarea::placeholder {
color: var(--ink-400);
}
.input:focus,
.select:focus,
.textarea:focus {
outline: none;
border-color: var(--rose-500);
box-shadow: 0 0 0 1px var(--rose-500);
}
.select {
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%238E8589' stroke-width='1.6'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 16px center;
background-size: 12px;
padding-right: 40px;
}
.input--error,
.field--error .input {
border-color: var(--error);
background: var(--rose-50);
}
.field__error {
font-size: 12px;
color: var(--error);
}
.check {
display: flex;
align-items: center;
gap: 10px;
cursor: pointer;
font-size: 14px;
}
.check input {
width: 18px;
height: 18px;
accent-color: var(--rose-500);
flex: none;
}
.radio {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 14px 16px;
border: 1px solid var(--line-300);
border-radius: var(--r-lg);
background: #fff;
cursor: pointer;
transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}
.radio:hover {
border-color: var(--ink-400);
}
.radio input {
margin-top: 3px;
width: 20px;
height: 20px;
accent-color: var(--rose-500);
flex: none;
}
.radio:has(input:checked) {
border-color: var(--rose-500);
background: var(--rose-50);
}
.radio__text {
display: flex;
flex-direction: column;
gap: 2px;
}
.radio__title {
font-weight: 600;
font-size: 15px;
}
.radio__meta {
font-size: 13px;
color: var(--ink-400);
}
/* ---------- header ---------- */
.site-header {
position: sticky;
top: 0;
z-index: 30;
}
.topbar {
display: none;
background: var(--ink-900);
color: #cbbfc4;
font-size: 12px;
}
.topbar__inner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
min-height: 40px;
}
.topbar__note {
margin: 0;
}
.topbar__right {
display: flex;
align-items: center;
gap: 12px;
}
.topbar__pickup {
color: #cbbfc4;
}
.topbar .pill {
padding: 4px 10px;
border-radius: 12px;
font-size: 11px;
}
.topbar__phone {
color: #fff;
font-weight: 600;
}
.header {
background: rgba(255, 255, 255, 0.94);
border-bottom: 1px solid var(--line-100);
backdrop-filter: blur(10px);
}
.header__inner {
display: flex;
align-items: center;
gap: 16px;
min-height: var(--header-h);
}
.brand {
display: flex;
flex-direction: column;
line-height: 1.05;
flex: none;
}
/* The tagline under the wordmark: red HTML text (BRAND.tagline), deliberately
un-stretched — the letter-spaced caps it replaces read as squeezed. */
.brand__sub {
margin-top: 4px;
font-size: 10px;
letter-spacing: 0.2px;
font-weight: 600;
color: var(--rose-500);
}
.mainnav {
display: none;
}
.header__actions {
display: none;
}
.mobile-actions {
display: flex;
align-items: center;
gap: 6px;
margin-left: auto;
}
.iconbtn {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
border: 1px solid var(--line-300);
border-radius: var(--r-lg);
background: #fff;
color: var(--ink-900);
cursor: pointer;
transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}
.iconbtn:hover {
border-color: var(--ink-900);
}
.iconbtn svg {
width: 20px;
height: 20px;
}
.iconbtn--round {
border-radius: 50%;
width: 36px;
height: 36px;
border-color: transparent;
}
.cartbtn {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: 48px;
height: 36px;
border-radius: 18px;
background: var(--rose-500);
color: #fff;
}
.cartbtn svg {
width: 20px;
height: 20px;
}
.count {
position: absolute;
top: -6px;
right: -6px;
min-width: 18px;
height: 18px;
padding: 0 4px;
border-radius: 9px;
background: var(--ink-900);
color: #fff;
font-size: 11px;
font-weight: 700;
line-height: 18px;
text-align: center;
}
.cartbtn .count {
background: #fff;
color: var(--rose-500);
}
.mainnav__list {
display: flex;
align-items: center;
gap: 20px;
}
.mainnav__list a {
font-size: 13px;
font-weight: 500;
color: var(--ink-600);
white-space: nowrap;
transition: color 0.15s var(--ease);
}
.mainnav__list a:hover,
.mainnav__list a.is-active {
color: var(--rose-500);
font-weight: 600;
}
.mainnav__more-wrap {
position: relative;
}
.mainnav__more {
border: 0;
background: none;
font-size: 13px;
font-weight: 500;
color: var(--ink-600);
white-space: nowrap;
cursor: pointer;
padding: 4px;
}
.mainnav__more:hover {
color: var(--rose-500);
}
.menu-panel {
position: absolute;
top: calc(100% + 12px);
right: 0;
min-width: 260px;
/* The panel holds every category plus the info links, so cap it to the
viewport and let it scroll instead of running off the screen. */
max-height: calc(100vh - 140px);
overflow-y: auto;
overscroll-behavior: contain;
padding: 10px;
border: 1px solid var(--line-100);
border-radius: var(--r-xl);
background: #fff;
box-shadow: var(--shadow-md);
display: grid;
gap: 2px;
}
.menu-panel a {
display: block;
padding: 9px 12px;
border-radius: var(--r-md);
font-size: 14px;
color: var(--ink-600);
}
.menu-panel a:hover {
background: var(--cream-100);
color: var(--ink-900);
}
.menu-panel a.is-active {
color: var(--rose-500);
font-weight: 600;
}
/* The first info link opens a group under the category list (public/app.js →
renderNav/renderMobileMenu). */
.menu-panel a.menu-panel__sep {
margin-top: 6px;
padding-top: 13px;
border-top: 1px solid var(--line-100);
border-radius: 0;
font-weight: 600;
color: var(--ink-900);
}
.menu-panel a.menu-panel__sep:hover {
border-radius: var(--r-md);
}
/* The mobile menu already draws a hairline under every row, so the group only
needs extra breathing room. */
.mobile-menu a.menu-panel__sep {
margin-top: 10px;
font-weight: 600;
color: var(--ink-900);
}
.search {
position: relative;
display: flex;
align-items: center;
}
.search__ico {
position: absolute;
left: 14px;
width: 16px;
height: 16px;
color: var(--ink-400);
pointer-events: none;
}
.search input {
width: 196px;
height: 44px;
padding: 0 14px 0 38px;
border: 1px solid var(--line-300);
border-radius: var(--r-lg);
background: var(--cream-100);
font-family: inherit;
font-size: 14px;
color: var(--ink-900);
}
.search input:focus {
outline: none;
border-color: var(--rose-500);
background: #fff;
}
.mobile-search {
background: #fff;
border-bottom: 1px solid var(--line-100);
}
.mobile-search__inner {
display: flex;
gap: 8px;
padding-block: 10px;
}
.mobile-search__inner input {
flex: 1;
height: 36px;
padding: 0 14px;
border: 1px solid var(--line-300);
border-radius: var(--r-lg);
background: var(--cream-100);
font-family: inherit;
font-size: 14px;
}
.mobile-search__inner .btn {
min-height: 36px;
padding: 0 16px;
}
.mobile-menu {
background: #fff;
border-bottom: 1px solid var(--line-100);
padding: 8px 20px 16px;
max-height: calc(100vh - var(--header-h));
overflow-y: auto;
}
.mobile-menu a {
display: block;
padding: 12px 4px;
border-bottom: 1px solid var(--line-100);
font-size: 15px;
color: var(--ink-600);
}
.mobile-menu a.is-active {
color: var(--rose-500);
font-weight: 600;
}
/* ---------- bottom nav ---------- */
.bottomnav {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 40;
display: flex;
justify-content: space-around;
align-items: stretch;
height: 64px;
padding-bottom: env(safe-area-inset-bottom);
background: rgba(255, 255, 255, 0.96);
border-top: 1px solid var(--line-100);
backdrop-filter: blur(10px);
}
.bottomnav__item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
font-size: 10px;
color: var(--ink-400);
}
.bottomnav__item svg {
width: 20px;
height: 20px;
}
.bottomnav__item.is-active {
color: var(--rose-500);
font-weight: 600;
}
/* ---------- app main ---------- */
.app {
flex: 1;
width: 100%;
padding-bottom: 80px;
}
/* ---------- footer ---------- */
.site-footer {
background: var(--ink-900);
color: #cbbfc4;
font-size: 13px;
padding-top: 32px;
}
.footer__grid {
display: grid;
gap: 28px;
padding-bottom: 28px;
}
.footer__about {
margin: 10px 0 14px;
line-height: 1.6;
max-width: 40ch;
}
.footer__pills {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.footer__title {
font-family: var(--font-sans);
font-size: 13px;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: #fff;
margin-bottom: 12px;
}
.footer__list {
display: grid;
gap: 8px;
}
.footer__list a:hover {
color: #fff;
}
.footer__list--contacts li {
color: #cbbfc4;
}
.footer__bottom {
border-top: 1px solid var(--footer-line);
font-size: 12px;
color: var(--ink-400);
}
.footer__bottom-inner {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 8px;
padding-block: 16px;
}
/* ---------- hero ---------- */
.hero {
background: var(--cream-100);
padding-block: 24px;
}
.hero__grid {
display: grid;
gap: 24px;
}
.hero__text {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 14px;
}
.hero__title {
font-size: 30px;
line-height: 1.15;
}
.hero__lede {
color: var(--ink-600);
font-size: 15px;
max-width: 46ch;
}
.hero__actions {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.hero__perks {
display: flex;
flex-wrap: wrap;
gap: 12px;
font-size: 12px;
color: var(--ink-600);
}
.hero__perk {
display: inline-flex;
align-items: center;
gap: 6px;
}
.hero__dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--sage-500);
}
.hero__media {
position: relative;
border-radius: var(--r-2xl);
overflow: hidden;
aspect-ratio: 4 / 3;
background: var(--cream-200);
}
.hero__media img {
width: 100%;
height: 100%;
object-fit: cover;
}
.hero__card {
position: absolute;
left: 12px;
right: auto;
bottom: 12px;
/* Leave the bottom-right corner free for the slider dots. */
max-width: calc(100% - 96px);
padding: 12px 14px;
border-radius: var(--r-xl);
background: rgba(255, 255, 255, 0.96);
box-shadow: var(--shadow-md);
}
.hero__card-title {
font-family: var(--font-display);
font-size: 16px;
font-weight: 700;
}
.hero__card-note {
font-size: 12px;
color: var(--ink-400);
}
/* 10s timer: one bar along the bottom edge of the hero photo, filling while
the current shot is on screen. The JS drives the transform so pausing
(hover/focus, reduced motion) keeps the time left. */
.hero__timer {
position: absolute;
left: 0;
bottom: 0;
z-index: 3;
width: 100%;
height: 3px;
background: rgba(255, 255, 255, 0.9);
transform: scaleX(0);
transform-origin: left center;
pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
.hero__timer {
display: none;
}
}
/* Hero slider — the headline column never moves: only the photo track (the
bouquet shot with its price tag) slides. Slides change by the dots pinned to
the photo's bottom-right (the shared .slider__overlay), plus autoplay,
keyboard and swipe. */
.hero-slider {
display: grid;
gap: 24px;
}
@media (max-width: 1023px) {
/* The photo is narrow here, so keep the overlay to the bare dots and let the
price card shrink instead of running into them. */
.hero__overlay .slider__counter {
display: none;
}
}
@media (min-width: 1024px) {
.hero__card {
min-width: 300px;
}
}
@media (min-width: 768px) {
.hero-slider {
grid-template-columns: 0.95fr 1.05fr;
align-items: center;
gap: 40px;
}
}
/* ---------- trust ---------- */
.trust {
background: #fff;
}
.trust__grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
padding-block: 16px;
}
.trust__item {
display: flex;
align-items: center;
gap: 10px;
}
.trust__ico {
display: grid;
place-items: center;
width: 36px;
height: 36px;
border-radius: 10px;
background: var(--rose-50);
color: var(--rose-500);
flex: none;
font-size: 16px;
}
.trust__title {
font-size: 13px;
font-weight: 600;
}
.trust__note {
font-size: 11px;
color: var(--ink-400);
}
/* ---------- sections ---------- */
.section {
padding-block: 32px;
}
.section--cream {
background: var(--cream-100);
}
.section--white {
background: #fff;
}
.section__head {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 16px;
margin-bottom: 20px;
}
.section__heading {
display: flex;
flex-direction: column;
gap: 4px;
}
.section__link {
font-size: 13px;
font-weight: 600;
color: var(--rose-500);
white-space: nowrap;
}
.section__link:hover {
color: var(--rose-600);
}
/* ---------- category tiles ---------- */
.cats {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.cat {
display: flex;
flex-direction: column;
gap: 8px;
background: #fff;
border: 1px solid var(--line-100);
border-radius: var(--r-lg);
overflow: hidden;
transition: transform 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.cat:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.cat__media {
aspect-ratio: 16 / 10;
background: var(--cream-200);
}
.cat__media img {
width: 100%;
height: 100%;
object-fit: cover;
}
.cat__label {
padding: 0 12px 12px;
font-size: 13px;
font-weight: 600;
}
.cat--all {
justify-content: center;
align-items: center;
background: var(--ink-900);
color: #fff;
border-color: var(--ink-900);
min-height: 120px;
text-align: center;
padding: 16px;
}
.cat--all .cat__count {
font-family: var(--font-display);
font-size: 22px;
}
.cat--all .cat__cta {
font-size: 12px;
color: var(--rose-100);
}
/* ---------- product grid & card ---------- */
.grid-products {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.grid-products--list {
grid-template-columns: 1fr;
}
.spec-list {
margin: 0;
}
.pcard {
position: relative;
display: flex;
flex-direction: column;
background: #fff;
border: 1px solid var(--line-100);
border-radius: 14px;
overflow: hidden;
transition: transform 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.pcard:hover {
transform: translateY(-3px);
box-shadow: var(--shadow-md);
}
.pcard__media {
position: relative;
display: block;
aspect-ratio: 5 / 4;
background: var(--cream-200);
/* The photo track is wider than the card: keep the neighbouring shot out. */
overflow: hidden;
}
.pcard__media img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* Several shots per position: the dots flip through them in place. */
.pcard__mediawrap {
position: relative;
}
.pcard__dots {
position: absolute;
right: 8px;
bottom: 8px;
z-index: 2;
display: flex;
gap: 5px;
}
.pcard__dot {
width: 7px;
height: 7px;
padding: 0;
border: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.6);
box-shadow: 0 1px 3px rgba(31, 26, 28, 0.4);
cursor: pointer;
transition: transform 0.15s var(--ease), background-color 0.15s var(--ease);
}
.pcard__dot:hover {
background: rgba(255, 255, 255, 0.85);
}
.pcard__dot.is-active {
background: #fff;
transform: scale(1.25);
}
.pcard__badges {
position: absolute;
top: 8px;
left: 8px;
display: flex;
flex-wrap: wrap;
gap: 4px;
}
.pcard__body {
display: flex;
flex-direction: column;
gap: 5px;
padding: 10px;
flex: 1;
}
.pcard__title {
font-size: 13px;
font-weight: 600;
line-height: 1.35;
}
.pcard__meta {
font-size: 11px;
color: var(--ink-400);
}
.pcard__prices {
display: flex;
align-items: baseline;
gap: 8px;
flex-wrap: wrap;
margin-top: auto;
}
.price {
font-size: 15px;
font-weight: 700;
}
.price-old {
font-size: 12px;
color: var(--ink-400);
text-decoration: line-through;
}
.pcard__foot {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 0 10px 10px;
}
.pcard__add {
display: grid;
place-items: center;
width: 30px;
height: 30px;
border: 0;
border-radius: 50%;
background: var(--rose-500);
color: #fff;
font-size: 18px;
line-height: 1;
cursor: pointer;
transition: background-color 0.15s var(--ease);
}
.pcard__add:hover {
background: var(--rose-600);
}
/* ---------- small grid (dense catalog view) ---------- */
/* A fourth catalog view: the same product cards at roughly half the width and
height, packed tightly — many bouquets on one screen. On mobile the 2-column
grid becomes 4 columns and on desktop the 3-column grid becomes 6, so every
card is about 2× smaller; the column counts (4 → 4 → 6) always divide the
24-per-page size, so the dense view ends on a full row. */
.grid-products.grid-products--small {
grid-template-columns: repeat(4, 1fr);
gap: 6px;
}
.grid-products--small .pcard {
border-radius: 8px;
}
.grid-products--small .pcard:hover {
transform: translateY(-2px);
}
.grid-products--small .pcard__media {
aspect-ratio: 1 / 1;
}
.grid-products--small .pcard__badges {
top: 4px;
left: 4px;
gap: 2px;
}
.grid-products--small .badge {
padding: 1px 4px;
border-radius: 4px;
font-size: 8px;
}
.grid-products--small .pcard__body {
gap: 2px;
padding: 5px 6px;
}
.grid-products--small .pcard__title {
font-size: 12px;
line-height: 1.25;
/* Keep every tile the same height: long names clamp to two lines. */
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.grid-products--small .pcard__meta {
display: none;
}
.grid-products--small .pcard__prices {
gap: 4px;
}
.grid-products--small .price {
font-size: 13px;
}
.grid-products--small .price-old {
font-size: 11px;
}
.grid-products--small .pcard__dots {
right: 4px;
bottom: 4px;
gap: 3px;
}
.grid-products--small .pcard__dot {
width: 4px;
height: 4px;
}
/* The foot holds only the add button and collapses to nothing: the button is
lifted out of the flow into the photo's top-right corner. `.pcard` is the
positioned ancestor (the foot itself is static), so top/right land inside the
picture — badges keep the top-left, the dots the bottom-right. */
.grid-products--small .pcard__foot {
padding: 0;
gap: 0;
}
/* The full "♡ В избранное" label does not fit a tile this small; keep only the
add button — favourites stay available on the card's own page. */
.grid-products--small .pcard__foot .linkbtn {
display: none;
}
.grid-products--small .pcard__add {
position: absolute;
top: 4px;
right: 4px;
z-index: 3;
width: 24px;
height: 24px;
font-size: 15px;
box-shadow: 0 1px 4px rgba(31, 26, 28, 0.3);
}
/* ---------- delivery banner ---------- */
.banner {
background: var(--ink-900);
color: #fff;
border-radius: var(--r-2xl);
padding: 28px 24px;
display: grid;
gap: 20px;
}
.banner__title {
font-size: 26px;
margin-top: 6px;
}
.banner__text {
color: #cbbfc4;
font-size: 14px;
margin-top: 10px;
max-width: 52ch;
}
.banner__aside {
display: flex;
flex-direction: column;
gap: 8px;
align-items: flex-start;
}
.banner__note {
font-size: 12px;
color: #cbbfc4;
}
/* ---------- info cards ---------- */
.info-cards {
display: grid;
gap: 16px;
}
.info-card {
padding: 22px;
border-radius: var(--r-xl);
background: #fff;
border: 1px solid var(--line-100);
}
.info-card__ico {
display: grid;
place-items: center;
width: 44px;
height: 44px;
border-radius: var(--r-lg);
background: var(--sage-100);
color: var(--sage-500);
font-size: 20px;
margin-bottom: 12px;
}
.info-card h3 {
font-size: 18px;
margin-bottom: 8px;
}
.info-card p {
color: var(--ink-600);
font-size: 13px;
}
/* ---------- breadcrumbs ---------- */
.crumbs {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
font-size: 13px;
color: var(--ink-400);
padding-block: 14px;
}
.crumbs a:hover {
color: var(--rose-500);
}
.crumbs__sep {
color: var(--line-300);
}
.crumbs__current {
color: var(--ink-900);
}
/* ---------- catalog ---------- */
.page-head {
background: var(--cream-100);
padding-bottom: 20px;
}
.page-head h1 {
font-size: 28px;
}
.page-head__lede {
margin-top: 8px;
color: var(--ink-600);
font-size: 14px;
}
.page-head__note {
margin-top: 8px;
font-size: 12px;
color: var(--ink-400);
max-width: 60ch;
}
.catalog {
display: grid;
gap: 24px;
padding-block: 24px;
}
.filters {
background: var(--cream-100);
border: 1px solid var(--line-100);
border-radius: var(--r-xl);
padding: 20px;
}
.filters__head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
.filters__title {
font-size: 16px;
font-weight: 600;
}
.filters__reset {
border: 0;
background: none;
color: var(--rose-500);
font-size: 13px;
font-weight: 600;
cursor: pointer;
}
.filters__group {
padding-block: 16px;
border-top: 1px solid var(--line-100);
}
.filters__group:first-of-type {
border-top: 0;
padding-top: 0;
}
.filters__legend {
font-size: 13px;
font-weight: 600;
margin-bottom: 12px;
}
.filters__count {
color: var(--ink-400);
font-weight: 400;
}
.filters__list {
display: grid;
gap: 10px;
}
.filters__price-inputs {
display: flex;
align-items: center;
gap: 8px;
margin-top: 12px;
}
.filters__price-inputs input {
min-height: 36px;
padding: 6px 10px;
font-size: 14px;
}
.range {
position: relative;
height: 28px;
}
.range__track {
position: absolute;
top: 13px;
left: 0;
right: 0;
height: 2px;
background: var(--line-300);
}
.range__fill {
position: absolute;
top: 13px;
height: 2px;
background: var(--rose-500);
}
.range input[type='range'] {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 28px;
margin: 0;
background: none;
pointer-events: none;
appearance: none;
}
.range input[type='range']::-webkit-slider-thumb {
pointer-events: auto;
appearance: none;
width: 18px;
height: 18px;
border-radius: 50%;
background: var(--rose-500);
border: 3px solid #fff;
box-shadow: var(--shadow-sm);
cursor: pointer;
}
.range input[type='range']::-moz-range-thumb {
pointer-events: auto;
width: 18px;
height: 18px;
border: 3px solid #fff;
border-radius: 50%;
background: var(--rose-500);
cursor: pointer;
}
.filters__apply {
width: 100%;
margin-top: 8px;
}
.catalog__main {
min-width: 0;
}
.toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
margin-bottom: 16px;
}
.toolbar__count {
font-size: 13px;
color: var(--ink-400);
}
.toolbar__right {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
}
.toolbar .select {
min-height: 44px;
font-size: 13px;
padding-block: 8px;
}
.viewtoggle {
display: flex;
gap: 4px;
}
.viewtoggle button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 7px;
min-width: 44px;
height: 44px;
padding: 0 12px;
border: 1px solid var(--line-300);
border-radius: var(--r-lg);
background: #fff;
color: var(--ink-600);
font-size: 13px;
font-weight: 500;
cursor: pointer;
}
.viewtoggle button.is-active {
background: var(--cream-100);
color: var(--ink-900);
border-color: var(--ink-400);
font-weight: 600;
}
.viewtoggle svg {
width: 18px;
height: 18px;
flex: none;
}
.viewtoggle__label {
display: none;
white-space: nowrap;
}
@media (min-width: 640px) {
.viewtoggle__label {
display: inline;
}
}
.pagination {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 6px;
margin-top: 28px;
}
.pagination button {
min-width: 40px;
height: 40px;
padding: 0 10px;
border: 1px solid var(--line-300);
border-radius: 10px;
background: #fff;
color: var(--ink-900);
font-size: 14px;
font-weight: 500;
cursor: pointer;
}
.pagination button:hover:not(:disabled) {
border-color: var(--ink-900);
}
.pagination button.is-active {
background: var(--rose-500);
border-color: var(--rose-500);
color: #fff;
font-weight: 600;
}
.pagination button:disabled {
color: var(--line-300);
cursor: not-allowed;
}
.pagination__gap {
color: var(--ink-400);
padding: 0 4px;
}
/* ---------- states ---------- */
.state {
padding: 48px 0;
text-align: center;
color: var(--ink-400);
}
.state-card {
max-width: 420px;
margin: 40px auto;
padding: 32px;
border-radius: var(--r-xl);
background: #fff;
border: 1px solid var(--line-300);
text-align: center;
}
.state-card--error {
background: var(--rose-50);
border-color: var(--rose-100);
}
.state-card__ico {
display: grid;
place-items: center;
width: 72px;
height: 72px;
margin: 0 auto 16px;
border-radius: 50%;
background: var(--rose-100);
font-size: 28px;
}
.state-card--error .state-card__ico {
background: var(--error);
color: #fff;
}
.state-card h2 {
font-size: 18px;
margin-bottom: 8px;
}
.state-card p {
color: var(--ink-400);
font-size: 13px;
margin-bottom: 18px;
}
/* ---------- skeleton ---------- */
.skeleton {
background: var(--cream-200);
border-radius: var(--r-md);
position: relative;
overflow: hidden;
}
.skeleton::after {
content: '';
position: absolute;
inset: 0;
transform: translateX(-100%);
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.6), transparent);
animation: shimmer 1.4s infinite;
}
@keyframes shimmer {
100% {
transform: translateX(100%);
}
}
.skeleton--hero {
aspect-ratio: 4 / 3;
border-radius: var(--r-2xl);
margin-block: 24px;
}
.skeleton-card {
border: 1px solid var(--line-100);
border-radius: 14px;
overflow: hidden;
background: #fff;
}
.skeleton-card__media {
aspect-ratio: 5 / 4;
border-radius: 0;
}
.skeleton-card__body {
display: grid;
gap: 8px;
padding: 12px;
}
.skeleton--line {
height: 14px;
}
.skeleton--line-sm {
height: 11px;
width: 60%;
}
.skeleton--price {
height: 20px;
width: 45%;
}
/* ---------- product page ---------- */
.product {
display: grid;
gap: 24px;
padding-block: 8px 32px;
}
.gallery__main {
position: relative;
border: 1px solid var(--line-100);
border-radius: var(--r-xl);
overflow: hidden;
background: #fff;
aspect-ratio: 4 / 3;
cursor: zoom-in;
}
.gallery__main img {
width: 100%;
height: 100%;
object-fit: cover;
}
.gallery__badges {
position: absolute;
top: 12px;
left: 12px;
display: flex;
gap: 6px;
}
.gallery__counter {
position: absolute;
right: 12px;
bottom: 12px;
padding: 4px 10px;
border-radius: var(--r-pill);
background: rgba(255, 255, 255, 0.92);
font-size: 12px;
font-weight: 600;
}
.gallery__thumbs {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 10px;
}
.gallery__thumb {
position: relative;
width: 68px;
height: 52px;
padding: 0;
border: 2px solid transparent;
border-radius: 10px;
overflow: hidden;
background: var(--cream-200);
cursor: pointer;
}
.gallery__thumb img {
width: 100%;
height: 100%;
object-fit: cover;
}
.gallery__thumb.is-active {
border-color: var(--rose-500);
}
.gallery__thumb--more {
display: grid;
place-items: center;
font-size: 12px;
font-weight: 600;
color: var(--ink-600);
}
.product__info {
display: flex;
flex-direction: column;
gap: 14px;
}
.pdp-badges {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.pdp-title {
font-size: 24px;
line-height: 1.2;
}
.pdp-rating {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: var(--ink-400);
}
.stars {
color: var(--gold-500);
letter-spacing: 1px;
}
.pdp-price {
display: flex;
align-items: baseline;
gap: 10px;
flex-wrap: wrap;
}
.pdp-price .price {
font-size: 28px;
}
.pdp-price .price-old {
font-size: 15px;
}
.pdp-label {
font-size: 13px;
font-weight: 600;
color: var(--ink-600);
margin-bottom: 8px;
}
.variants {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.variant {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 108px;
padding: 10px 12px;
border: 2px solid var(--line-300);
border-radius: var(--r-lg);
background: #fff;
cursor: pointer;
text-align: left;
transition: all 0.15s var(--ease);
}
.variant:hover {
border-color: var(--ink-400);
}
.variant.is-active {
border-color: var(--rose-500);
background: var(--rose-50);
}
.variant__label {
font-size: 14px;
font-weight: 600;
}
.variant__price {
font-size: 12px;
color: var(--ink-600);
}
.variant.is-active .variant__price {
color: var(--rose-600);
}
.buyrow {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.buyrow .btn {
flex: 1;
}
.stockline {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
}
.stockline--in {
color: var(--success);
}
.stockline--out {
color: var(--error);
}
.delivery-card {
display: grid;
gap: 12px;
padding: 18px;
border-radius: var(--r-xl);
background: var(--cream-100);
}
.delivery-card__row {
display: flex;
gap: 12px;
align-items: flex-start;
font-size: 13px;
}
.delivery-card__ico {
display: grid;
place-items: center;
width: 36px;
height: 36px;
border-radius: 10px;
background: #fff;
color: var(--rose-500);
flex: none;
}
.delivery-card__title {
font-weight: 600;
}
.delivery-card__note {
color: var(--ink-600);
font-size: 12px;
}
.messengers {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.messengers .pill {
padding: 10px 18px;
border-radius: var(--r-2xl);
font-size: 13px;
}
/* ---------- stepper ---------- */
.stepper {
display: flex;
align-items: center;
gap: 4px;
height: 52px;
padding: 0 6px;
border: 1px solid var(--line-300);
border-radius: var(--r-lg);
background: #fff;
}
.stepper button {
display: grid;
place-items: center;
width: 36px;
height: 36px;
border: 0;
border-radius: 9px;
background: var(--cream-100);
font-size: 18px;
line-height: 1;
color: var(--ink-900);
cursor: pointer;
}
.stepper button:hover {
background: var(--cream-200);
}
.stepper button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.stepper__value {
min-width: 34px;
text-align: center;
font-size: 16px;
font-weight: 600;
}
/* ---------- tabs ---------- */
.tabs {
display: flex;
flex-wrap: wrap;
gap: 4px;
border-bottom: 1px solid var(--line-100);
margin-bottom: 20px;
}
.tab {
padding: 12px 14px;
border: 0;
border-bottom: 2px solid transparent;
background: none;
font-family: inherit;
font-size: 14px;
font-weight: 600;
color: var(--ink-400);
cursor: pointer;
}
.tab.is-active {
color: var(--ink-900);
border-bottom-color: var(--rose-500);
}
.tabpanel {
color: var(--ink-600);
font-size: 15px;
line-height: 1.7;
max-width: 72ch;
}
.spec-tables {
display: grid;
gap: 16px;
margin-top: 24px;
}
.spec {
display: grid;
grid-template-columns: 140px 1fr;
gap: 12px;
padding: 10px 0;
border-bottom: 1px dashed var(--line-300);
font-size: 14px;
}
.spec dt {
color: var(--ink-400);
}
.spec dd {
margin: 0;
}
.spec .ok {
color: var(--success);
font-weight: 600;
}
/* ---------- cart ---------- */
.cart-layout {
display: grid;
gap: 24px;
padding-block: 24px 40px;
}
.cart-lines {
display: grid;
gap: 12px;
}
.cart-line {
display: grid;
grid-template-columns: 84px 1fr;
gap: 14px;
padding: 14px;
border: 1px solid var(--line-100);
border-radius: var(--r-xl);
background: #fff;
}
.cart-line__media {
width: 84px;
height: 84px;
border-radius: var(--r-lg);
overflow: hidden;
background: var(--cream-200);
}
.cart-line__media img {
width: 100%;
height: 100%;
object-fit: cover;
}
.cart-line__body {
display: flex;
flex-direction: column;
gap: 8px;
min-width: 0;
}
.cart-line__top {
display: flex;
gap: 12px;
justify-content: space-between;
align-items: flex-start;
}
.cart-line__title {
font-size: 15px;
font-weight: 600;
}
.cart-line__meta {
font-size: 12px;
color: var(--ink-400);
}
.cart-line__bottom {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
margin-top: auto;
}
.linkbtn {
border: 0;
background: none;
padding: 0;
color: var(--ink-400);
font-size: 13px;
cursor: pointer;
text-decoration: underline;
}
.linkbtn:hover {
color: var(--error);
}
.summary {
align-self: start;
padding: 20px;
border: 1px solid var(--line-100);
border-radius: var(--r-xl);
background: #fff;
}
.summary__title {
font-size: 16px;
font-weight: 600;
margin-bottom: 16px;
}
.summary__row {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 12px;
font-size: 14px;
padding-block: 6px;
color: var(--ink-600);
}
.summary__row--total {
border-top: 1px solid var(--line-100);
margin-top: 10px;
padding-top: 14px;
font-size: 18px;
font-weight: 700;
color: var(--ink-900);
}
.summary__free {
color: var(--success);
font-weight: 600;
}
.progress {
margin: 14px 0;
}
.progress__note {
font-size: 12px;
margin-bottom: 8px;
color: var(--ink-600);
}
.progress__track {
height: 8px;
border-radius: 4px;
background: var(--cream-200);
overflow: hidden;
}
.progress__fill {
height: 100%;
border-radius: 4px;
background: var(--rose-500);
transition: width 0.25s var(--ease);
}
.progress--done .progress__fill {
background: var(--free);
}
.promo {
display: flex;
gap: 8px;
margin: 16px 0;
}
.promo input {
min-height: 44px;
}
.promo .btn {
min-height: 44px;
padding: 0 16px;
}
/* ---------- checkout ---------- */
.checkout {
display: grid;
gap: 24px;
padding-block: 24px 40px;
}
.checkout__main {
display: grid;
gap: 20px;
}
.card {
border: 1px solid var(--line-100);
border-radius: var(--r-xl);
background: #fff;
padding: 20px;
}
.card__title {
font-family: var(--font-sans);
font-size: 16px;
font-weight: 700;
margin-bottom: 16px;
display: flex;
align-items: center;
gap: 10px;
}
.card__step {
display: grid;
place-items: center;
width: 26px;
height: 26px;
border-radius: 50%;
background: var(--rose-500);
color: #fff;
font-size: 13px;
font-weight: 700;
flex: none;
}
.grid-2 {
display: grid;
gap: 0 16px;
}
/* ---------- success ---------- */
.success {
max-width: 760px;
margin: 32px auto 48px;
}
.success__badge {
display: grid;
place-items: center;
width: 64px;
height: 64px;
border-radius: 50%;
background: var(--sage-100);
color: var(--success);
font-size: 30px;
margin-bottom: 16px;
}
.success h1 {
font-size: 28px;
margin-bottom: 8px;
}
.success__order {
display: inline-block;
margin: 12px 0;
padding: 8px 14px;
border-radius: var(--r-lg);
background: var(--cream-100);
font-weight: 600;
}
.success__steps {
display: grid;
gap: 12px;
margin: 20px 0;
}
.success__step {
display: flex;
gap: 12px;
align-items: flex-start;
}
.success__num {
display: grid;
place-items: center;
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--rose-50);
color: var(--rose-500);
font-size: 13px;
font-weight: 700;
flex: none;
}
/* ---------- info pages ---------- */
/* A reading column of section cards plus a dark contact CTA. The body markup
(`## `/`### `/`- `/`> `, inline `**bold**` + `[label](href)`) is parsed in
public/app.js → renderPageBody(); routes stay 1:1 with the source (R10). */
.page-head {
padding-block: 18px 6px;
}
.page-hero {
display: grid;
gap: 10px;
max-width: 720px;
margin-top: 14px;
}
.page-hero h1 {
font-size: 28px;
}
.page-hero__lede {
color: var(--ink-600);
font-size: 15px;
line-height: 1.75;
}
.page-layout {
display: grid;
gap: 16px;
padding-block: 18px 56px;
}
/* All the section cards live in this one column so that on desktop the grid
has a single row: the CTA beside it then spans the real content height. */
.page-main {
display: grid;
gap: 16px;
}
.page-card {
padding: 20px;
border: 1px solid var(--line-100);
border-radius: var(--r-xl);
background: #fff;
}
.page-card__title {
font-size: 20px;
margin-bottom: 12px;
}
.page-card__subtitle {
font-family: var(--font-sans);
font-size: 15px;
font-weight: 700;
margin: 18px 0 10px;
}
.page-card > *:first-child {
margin-top: 0;
}
.page-card__text {
color: var(--ink-600);
font-size: 15px;
line-height: 1.75;
}
.page-card__text + .page-card__text {
margin-top: 10px;
}
.page-list {
display: grid;
gap: 8px;
margin: 10px 0;
}
.page-list li {
position: relative;
padding-left: 20px;
color: var(--ink-600);
font-size: 15px;
line-height: 1.7;
}
.page-list li::before {
content: '';
position: absolute;
left: 3px;
top: 0.66em;
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--rose-100);
}
.page-card a,
.page-list a,
.page-callout a {
color: var(--rose-600);
text-decoration: underline;
text-underline-offset: 2px;
}
.page-card a:hover,
.page-list a:hover,
.page-callout a:hover {
color: var(--rose-700);
}
.page-callout {
margin: 12px 0;
padding: 14px 16px;
border-left: 3px solid var(--rose-500);
border-radius: var(--r-md);
background: var(--rose-50);
color: var(--ink-600);
font-size: 14px;
line-height: 1.7;
}
.page-card > .page-callout:first-child {
margin-top: 0;
}
.page-card > .page-callout:last-child {
margin-bottom: 0;
}
/* embedded map (`!map <url>` line in a page body) */
.page-map {
margin: 14px 0;
border: 1px solid var(--line-100);
border-radius: var(--r-lg);
overflow: hidden;
background: var(--cream-100);
}
.page-map iframe {
display: block;
width: 100%;
height: 320px;
border: 0;
}
@media (min-width: 768px) {
.page-map iframe {
height: 400px;
}
}
/* contact CTA appended to every info page */
.page-cta {
display: grid;
gap: 18px;
padding: 24px;
border-radius: var(--r-xl);
background: var(--ink-900);
color: #fff;
}
.page-cta__title {
font-size: 22px;
}
.page-cta__note {
margin-top: 8px;
color: #cbbfc4;
font-size: 14px;
line-height: 1.7;
}
.page-cta__list {
display: grid;
gap: 6px;
margin-top: 16px;
font-size: 15px;
}
.page-cta__list a {
color: #fff;
text-decoration: underline;
text-underline-offset: 2px;
}
.page-cta__list a:hover {
color: var(--rose-100);
}
.page-cta__actions {
display: grid;
gap: 10px;
}
.page-cta .btn--ghost {
background: transparent;
color: #fff;
border-color: rgba(255, 255, 255, 0.4);
}
.page-cta .btn--ghost:hover {
border-color: #fff;
background: rgba(255, 255, 255, 0.08);
}
.faq {
display: grid;
gap: 10px;
margin-top: 20px;
}
.faq details {
border: 1px solid var(--line-100);
border-radius: var(--r-lg);
background: #fff;
padding: 14px 16px;
}
.faq summary {
font-weight: 600;
cursor: pointer;
}
.faq details p {
margin-top: 10px;
color: var(--ink-600);
font-size: 14px;
}
/* ---------- toast & lightbox ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 84px;
z-index: 60;
transform: translateX(-50%);
padding: 12px 20px;
border-radius: var(--r-lg);
background: var(--ink-900);
color: #fff;
font-size: 14px;
font-weight: 500;
box-shadow: var(--shadow-lg);
max-width: calc(100vw - 40px);
}
.lightbox {
position: fixed;
inset: 0;
z-index: 70;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 20px;
background: rgba(31, 26, 28, 0.92);
}
.lightbox__figure {
margin: 0;
max-width: min(1100px, 100%);
max-height: 100%;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
}
.lightbox__figure img {
max-width: 100%;
max-height: 78vh;
object-fit: contain;
border-radius: var(--r-lg);
}
.lightbox__cap {
color: #cbbfc4;
font-size: 13px;
}
.lightbox__close,
.lightbox__nav {
border: 0;
background: rgba(255, 255, 255, 0.12);
color: #fff;
cursor: pointer;
border-radius: 50%;
width: 44px;
height: 44px;
font-size: 22px;
flex: none;
}
.lightbox__close {
position: absolute;
top: 16px;
right: 16px;
}
.lightbox__close:hover,
.lightbox__nav:hover {
background: rgba(255, 255, 255, 0.24);
}
/* ============================================================================
Responsive — the design is drawn at 390 (mobile) and 1440 (desktop).
========================================================================== */
@media (max-width: 767px) {
.footer__bottom-inner {
flex-direction: column;
}
.site-footer {
padding-bottom: 72px;
}
}
@media (min-width: 768px) {
.grid-products--4 {
grid-template-columns: repeat(3, 1fr);
}
.header__inner {
min-height: 90px;
}
.brand__sub {
font-size: 11px;
}
.hero {
padding-block: 40px;
}
.hero__grid {
grid-template-columns: 0.95fr 1.05fr;
align-items: center;
gap: 40px;
}
.hero__title {
font-size: 40px;
}
.hero__lede {
font-size: 16px;
}
.hero__media {
aspect-ratio: 640 / 460;
}
.hero__card {
left: 20px;
right: auto;
bottom: 20px;
}
.trust__grid {
grid-template-columns: repeat(4, 1fr);
padding-block: 24px;
}
.trust__title {
font-size: 15px;
}
.trust__note {
font-size: 12px;
}
.section {
padding-block: 48px;
}
.section-title {
font-size: 32px;
}
.cats {
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
.grid-products {
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.grid-products.grid-products--small {
grid-template-columns: repeat(4, 1fr);
gap: 8px;
}
.pcard__body {
padding: 14px 16px;
}
.pcard__title {
font-size: 16px;
}
.price {
font-size: 20px;
}
.pcard__add {
width: 34px;
height: 34px;
}
.banner {
grid-template-columns: 1fr auto;
align-items: center;
padding: 40px 48px;
}
.banner__title {
font-size: 34px;
}
.banner__aside {
align-items: flex-end;
text-align: right;
}
.info-cards {
grid-template-columns: repeat(3, 1fr);
}
.page-head h1 {
font-size: 36px;
}
.page-hero__lede {
font-size: 16px;
}
/* Sections in the main column, the contact CTA pinned as a sticky sidebar. */
.page-layout {
grid-template-columns: minmax(0, 1fr) 340px;
align-items: start;
gap: 24px;
}
/* One grid item for the whole reading column: the single row is as tall as
the sections, so the sidebar sticks for the full scroll without faking a
60-row span (which used to inject ~55 empty rows of `gap` before the
footer). */
.page-main {
grid-column: 1;
gap: 24px;
}
.page-card {
padding: 28px 32px;
}
.page-cta {
grid-column: 2;
grid-row: 1;
align-self: start;
position: sticky;
top: 110px;
padding: 28px;
}
.catalog {
grid-template-columns: 300px minmax(0, 1fr);
gap: 32px;
padding-block: 40px;
}
.filters {
align-self: start;
position: sticky;
top: 110px;
}
.viewtoggle {
display: flex;
}
.pagination {
justify-content: flex-end;
}
.product {
grid-template-columns: 1.05fr 1fr;
gap: 40px;
padding-block: 16px 48px;
}
.gallery__main {
aspect-ratio: 620 / 520;
}
.gallery__thumb {
width: 92px;
height: 68px;
}
.pdp-title {
font-size: 32px;
}
.pdp-price .price {
font-size: 34px;
}
.spec-tables {
grid-template-columns: repeat(2, 1fr);
gap: 0 40px;
}
.product__info {
gap: 18px;
}
.cart-layout {
grid-template-columns: minmax(0, 1fr) 380px;
gap: 32px;
align-items: start;
}
.checkout {
grid-template-columns: minmax(0, 1fr) 380px;
gap: 32px;
align-items: start;
}
.summary {
position: sticky;
top: 110px;
}
.grid-2 {
grid-template-columns: 1fr 1fr;
}
.footer__grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 32px 40px;
padding-block: 40px 28px;
}
}
@media (min-width: 1024px) {
/* Five columns once there is room: brand · Каталог · Покупателям ·
Компания · Контакты. */
.footer__grid {
grid-template-columns: 1.4fr 1fr 1fr 1fr 1.2fr;
gap: 32px;
}
}
@media (min-width: 1200px) {
.topbar {
display: block;
}
.mobile-actions {
display: none;
}
.mainnav {
display: flex;
align-items: center;
gap: clamp(12px, 1.4vw, 20px);
margin-left: auto;
min-width: 0;
}
.mainnav__list {
flex-wrap: nowrap;
}
.header__actions {
display: flex;
align-items: center;
gap: 10px;
flex: none;
}
.mobile-search,
.mobile-menu {
display: none !important;
}
.bottomnav {
display: none;
}
.app {
padding-bottom: 0;
}
.hero__title {
font-size: 46px;
}
.cats {
grid-template-columns: repeat(6, 1fr);
}
.grid-products {
grid-template-columns: repeat(3, 1fr);
}
.grid-products--4 {
grid-template-columns: repeat(4, 1fr);
}
.grid-products.grid-products--small {
grid-template-columns: repeat(6, 1fr);
gap: 10px;
}
.cart-layout,
.checkout {
grid-template-columns: minmax(0, 1fr) 420px;
}
}
@media (min-width: 768px) and (max-width: 1199px) {
.cats {
grid-template-columns: repeat(4, 1fr);
}
.grid-products {
grid-template-columns: repeat(3, 1fr);
}
}
/* ============================================================================
Catalog slider — one bouquet per screen with a price tag (photo + name +
price) beside the large photo; the dots sit on the photo's bottom-right.
========================================================================== */
.slider {
position: relative;
}
.slider__viewport {
overflow: hidden;
}
.slider__track {
display: flex;
}
/* The other three sliders are the same machine: a flex track of full-width
slides, translated one slide at a time from app.js (paintTrack). */
.hero__media-track,
.pcard__track,
.gallery__track {
display: flex;
height: 100%;
}
.hero__media-slide,
.pcard__slide,
.gallery__slide {
position: relative;
flex: none;
width: 100%;
height: 100%;
}
.slider__slide {
flex: none;
width: 100%;
display: grid;
gap: 12px;
}
.slider__mediawrap {
position: relative;
}
/* Swipe surfaces: the hero photo, a product card's photo, the catalog-slider
photo and the PDP gallery. They are grabbable with the mouse, so the browser
must not start its own image/link drag or a text selection — otherwise the
gesture never reaches the pointer handlers and the slide does not change.
Vertical panning is still handed back to the page. */
.hero__media,
.pcard__mediawrap,
.slider__mediawrap,
.gallery__main,
.pcard__media,
.slider__media,
.hero__media img,
.pcard__media img,
.slider__media img,
.gallery__main img {
-webkit-user-drag: none;
user-select: none;
}
.hero__media,
.pcard__mediawrap,
.slider__mediawrap,
.gallery__main {
touch-action: pan-y;
}
.slider__media {
position: relative;
display: block;
aspect-ratio: 4 / 3;
border-radius: var(--r-xl);
overflow: hidden;
background: var(--cream-200);
}
.slider__media img {
width: 100%;
height: 100%;
object-fit: cover;
}
.slider__placeholder {
position: absolute;
inset: 0;
display: grid;
place-items: center;
font-size: 44px;
color: var(--rose-100);
}
.slider__tag {
display: grid;
gap: 6px;
align-content: start;
padding: 16px;
background: #fff;
border: 1px solid var(--line-100);
border-radius: var(--r-xl);
}
.slider__tag-thumb {
width: 60px;
height: 60px;
border-radius: var(--r-lg);
overflow: hidden;
background: var(--cream-200);
}
.slider__tag-thumb img {
width: 100%;
height: 100%;
object-fit: cover;
}
.slider__tag-name {
font-family: var(--font-display);
font-weight: 700;
font-size: 19px;
line-height: 1.25;
}
.slider__tag-name:hover {
color: var(--rose-500);
}
.slider__tag-meta {
font-size: 12px;
color: var(--ink-400);
}
.slider__tag-price {
display: flex;
align-items: baseline;
gap: 8px;
flex-wrap: wrap;
}
.slider__tag-price .price {
font-size: 24px;
}
.slider__tag-actions {
display: grid;
gap: 8px;
justify-items: start;
margin-top: 8px;
}
/* Overlay pinned to the bottom-right of the photo (hero + catalog slider). */
.slider__overlay {
position: absolute;
right: 12px;
bottom: 12px;
z-index: 2;
display: flex;
align-items: center;
gap: 10px;
}
.slider__dots {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.slider__overlay .slider__dots {
gap: 6px;
flex-wrap: nowrap;
}
/* On a photo the plain grey dots vanish, so use translucent white ones. */
.slider__overlay .slider__dot {
width: 10px;
height: 10px;
background: rgba(255, 255, 255, 0.6);
box-shadow: 0 1px 4px rgba(31, 26, 28, 0.35);
}
.slider__overlay .slider__dot:hover {
background: rgba(255, 255, 255, 0.85);
}
.slider__overlay .slider__dot.is-active {
background: #fff;
}
.slider__overlay .slider__counter {
color: #fff;
text-shadow: 0 1px 4px rgba(31, 26, 28, 0.55);
}
.slider__dot {
width: 9px;
height: 9px;
padding: 0;
border: 0;
border-radius: 50%;
background: var(--line-300);
cursor: pointer;
transition: transform 0.15s var(--ease), background-color 0.15s var(--ease);
}
.slider__dot:hover {
background: var(--ink-400);
}
.slider__dot.is-active {
background: var(--rose-500);
transform: scale(1.3);
}
.slider__counter {
font-size: 13px;
color: var(--ink-400);
}
@media (min-width: 768px) {
.slider__slide {
grid-template-columns: 1.15fr 0.85fr;
gap: 20px;
}
.slider__media {
aspect-ratio: 5 / 4;
}
.slider__tag {
padding: 24px;
}
.slider__tag-thumb {
width: 72px;
height: 72px;
}
}
/* ============================================================================
Catalog list view — one bouquet per row: photo, details, actions.
========================================================================== */
.grid-products--list {
grid-template-columns: 1fr;
gap: 10px;
}
.grid-products--list .pcard {
display: grid;
grid-template-columns: 148px minmax(0, 1fr) auto;
grid-template-areas: 'media body foot';
align-items: center;
gap: 0 18px;
padding-right: 18px;
}
.grid-products--list .pcard:hover {
transform: none;
}
.grid-products--list .pcard__mediawrap {
grid-area: media;
align-self: stretch;
}
.grid-products--list .pcard__media {
height: 100%;
min-height: 108px;
aspect-ratio: auto;
}
.grid-products--list .pcard__body {
grid-area: body;
padding: 14px 0;
}
.grid-products--list .pcard__title {
font-size: 17px;
}
.grid-products--list .pcard__meta {
font-size: 12px;
}
.grid-products--list .pcard__prices {
margin-top: 8px;
}
.grid-products--list .pcard__foot {
grid-area: foot;
padding: 0;
}
@media (max-width: 560px) {
.grid-products--list .pcard {
grid-template-columns: 104px minmax(0, 1fr);
grid-template-areas: 'media body' 'media foot';
gap: 0 14px;
padding: 10px;
}
.grid-products--list .pcard__body {
padding: 2px 0 8px;
}
.grid-products--list .pcard__foot {
justify-content: flex-start;
padding-bottom: 2px;
}
.grid-products--list .pcard__media {
min-height: 96px;
}
}
/* ============================================================================
Drag & swipe — Pointer gestures on the sliders, cards and product gallery.
========================================================================== */
#hero-slider,
#catalog-slider .slider__viewport,
.pcard__mediawrap,
#gallery-main {
touch-action: pan-y;
}
#hero-slider {
overflow: hidden;
}
.hero__media-track,
.slider__track,
.pcard__track,
.gallery__track {
transition: transform 0.35s var(--ease);
}
.hero__media-track.is-dragging,
.slider__track.is-dragging,
.pcard__track.is-dragging,
.gallery__track.is-dragging {
transition: none;
}
@media (prefers-reduced-motion: reduce) {
.hero__media-track,
.slider__track,
.pcard__track,
.gallery__track {
transition: none;
}
}
.pcard__media img,
.hero__media img,
.slider__media img,
#gallery-main img {
-webkit-user-drag: none;
}
/* ============================================================================
Reveal on scroll — sections and blocks fade in the first time they appear.
Uses the standalone `translate` property so it never fights a component's
own `transform` (e.g. the card hover lift).
========================================================================== */
@media (prefers-reduced-motion: no-preference) {
.reveal {
opacity: 0;
translate: 0 14px;
transition: opacity 0.5s var(--ease), translate 0.5s var(--ease);
transition-delay: var(--reveal-delay, 0ms);
}
.reveal.is-visible {
opacity: 1;
translate: 0 0;
}
}
/* ============================================================================
Brand lockup — the store wordmark (BRAND.logoSourceUrl, mirrored into
public/images/brand/logo_footer.png by scripts/fetch-logo.ts) with the red
tagline (BRAND.tagline) beneath it as HTML text.
The artwork is tightly cropped, so it is always sized on ONE axis (height)
with `width: auto` — give it a width and a height at once and it stretches.
It is dark with green/pink accents: it sits directly on the light header, and
on a white plate inside the dark footer so it stays legible.
========================================================================== */
.brand__logo {
display: block;
width: auto;
height: 32px;
max-width: 100%;
/* Belt and braces: keep the wordmark's own ratio if a box ever constrains it. */
object-fit: contain;
}
.footer__plate {
display: inline-flex;
flex-direction: column;
align-items: center;
gap: 4px;
padding: 10px 16px;
border-radius: var(--r-lg);
background: #fff;
}
.footer__logo {
display: block;
width: auto;
height: 34px;
object-fit: contain;
}
.footer__sub {
font-size: 10px;
letter-spacing: 0.2px;
font-weight: 600;
color: var(--rose-500);
}
@media (min-width: 768px) {
.brand__logo {
height: 42px;
}
}
/* ============================================================================
Motion & gradients — a decorative pass laid on top of the base design
system. It only adds gradients, hover/entrance motion and a few ambient
keyframes; the global `prefers-reduced-motion` rule plus the explicit reset
at the end switch the ambient movement off.
========================================================================== */
:root {
--grad-rose: linear-gradient(135deg, #ea5c8b 0%, #d6336c 48%, #93214a 100%);
--grad-rose-soft: linear-gradient(135deg, #fdf2f6 0%, #f7d9e4 55%, #f3c9d9 100%);
--grad-gold: linear-gradient(135deg, #ecd9a6 0%, #c8a96a 55%, #a9863f 100%);
--grad-sage: linear-gradient(135deg, #6aa88d 0%, #3f6f5b 100%);
--grad-dark: linear-gradient(135deg, #2c2428 0%, #1f1a1c 52%, #3d2230 100%);
--grad-hero: linear-gradient(158deg, #fffaf7 0%, #fdf2f6 46%, #f6e7ee 100%);
--grad-text: linear-gradient(100deg, #b22759 0%, #d6336c 46%, #c8a96a 100%);
--grad-shine: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, 0.55) 50%, transparent 70%);
}
@keyframes gradientShift {
0%,
100% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
}
@keyframes floatY {
0%,
100% {
transform: translate3d(0, 0, 0) scale(1);
}
50% {
transform: translate3d(0, -26px, 0) scale(1.06);
}
}
@keyframes floatX {
0%,
100% {
transform: translate3d(0, 0, 0);
}
50% {
transform: translate3d(24px, -14px, 0);
}
}
@keyframes sheen {
0% {
transform: translateX(-140%) skewX(-14deg);
}
60%,
100% {
transform: translateX(240%) skewX(-14deg);
}
}
@keyframes popIn {
0% {
transform: scale(0.4);
opacity: 0;
}
60% {
transform: scale(1.2);
}
100% {
transform: scale(1);
opacity: 1;
}
}
@keyframes dotPulse {
0%,
100% {
box-shadow: 0 0 0 0 rgba(214, 51, 108, 0.35);
}
70% {
box-shadow: 0 0 0 7px rgba(214, 51, 108, 0);
}
}
@keyframes toastIn {
from {
opacity: 0;
transform: translate(-50%, 14px);
}
to {
opacity: 1;
transform: translate(-50%, 0);
}
}
/* ---------- ambient hero & headings ---------- */
.hero {
position: relative;
isolation: isolate;
overflow: hidden;
background: var(--grad-hero);
}
.hero > .container {
position: relative;
z-index: 1;
}
.hero::before,
.hero::after {
content: '';
position: absolute;
z-index: 0;
border-radius: 50%;
pointer-events: none;
}
.hero::before {
top: -170px;
left: -120px;
width: 460px;
height: 460px;
background: radial-gradient(circle at 35% 35%, rgba(214, 51, 108, 0.22), transparent 68%);
animation: floatY 13s ease-in-out infinite;
}
.hero::after {
right: -150px;
bottom: -210px;
width: 540px;
height: 540px;
background: radial-gradient(circle at 55% 40%, rgba(200, 169, 106, 0.28), transparent 68%);
animation: floatX 17s ease-in-out infinite;
}
@supports (background-clip: text) or (-webkit-background-clip: text) {
.hero__title {
background: linear-gradient(112deg, #1f1a1c 0%, #1f1a1c 44%, #b22759 80%, #c8a96a 100%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
-webkit-text-fill-color: transparent;
}
.section-title {
background: linear-gradient(100deg, #1f1a1c 0%, #1f1a1c 58%, #b22759 100%);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
-webkit-text-fill-color: transparent;
}
.overline {
background: var(--grad-text);
background-size: 200% auto;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
-webkit-text-fill-color: transparent;
animation: gradientShift 6s ease-in-out infinite;
}
/* The home banner tints its overline gold inline — keep that intent. */
.overline[style] {
background: none;
-webkit-text-fill-color: currentColor;
}
}
/* ---------- buttons & pills ---------- */
.btn {
transition: background-color 0.2s var(--ease), color 0.2s var(--ease), border-color 0.2s var(--ease),
transform 0.2s var(--ease), box-shadow 0.25s var(--ease);
}
.btn:hover {
transform: translateY(-2px);
}
.btn:active {
transform: translateY(0);
}
.btn--primary {
position: relative;
overflow: hidden;
background-image: var(--grad-rose);
background-size: 180% 180%;
background-position: 0% 50%;
box-shadow: 0 6px 18px rgba(214, 51, 108, 0.28);
transition: background-position 0.5s var(--ease), transform 0.2s var(--ease), box-shadow 0.25s var(--ease);
}
.btn--primary:hover {
background: var(--grad-rose);
background-size: 180% 180%;
background-position: 100% 50%;
box-shadow: 0 10px 26px rgba(214, 51, 108, 0.38);
}
.btn--primary::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 45%;
background: var(--grad-shine);
transform: translateX(-140%) skewX(-14deg);
pointer-events: none;
}
.btn--primary:hover::before {
animation: sheen 0.8s var(--ease);
}
.btn--primary[disabled]:hover,
.btn--primary[aria-disabled='true']:hover {
background: var(--disabled);
}
.btn--dark {
background-image: var(--grad-dark);
box-shadow: 0 6px 18px rgba(31, 26, 28, 0.24);
}
.btn--outline,
.btn--outline-dark,
.btn--ghost {
transition: background-color 0.18s var(--ease), color 0.18s var(--ease), border-color 0.18s var(--ease),
transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.btn--outline:hover,
.btn--outline-dark:hover {
box-shadow: 0 8px 20px rgba(214, 51, 108, 0.18);
}
.btn[disabled],
.btn[aria-disabled='true'] {
box-shadow: none;
}
.pill {
transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease), filter 0.2s var(--ease);
}
.pill:hover {
transform: translateY(-1px);
filter: brightness(1.06);
box-shadow: var(--shadow-sm);
}
/* ---------- header chrome ---------- */
.topbar {
background: var(--grad-dark);
}
.header {
transition: box-shadow 0.3s var(--ease);
}
.site-header.is-scrolled .header {
box-shadow: 0 10px 30px rgba(31, 26, 28, 0.1);
}
.mainnav__list a {
position: relative;
}
.mainnav__list a::after {
content: '';
position: absolute;
left: 0;
right: 100%;
bottom: -5px;
height: 2px;
border-radius: 2px;
opacity: 0;
background: var(--grad-rose);
transition: right 0.28s var(--ease), opacity 0.2s var(--ease);
}
.mainnav__list a:hover::after,
.mainnav__list a.is-active::after {
right: 0;
opacity: 1;
}
.iconbtn {
transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease), transform 0.18s var(--ease),
box-shadow 0.18s var(--ease);
}
.iconbtn:hover {
transform: translateY(-1px);
box-shadow: var(--shadow-sm);
}
.iconbtn:active {
transform: translateY(0) scale(0.96);
}
.cartbtn {
background: var(--grad-rose);
box-shadow: 0 4px 14px rgba(214, 51, 108, 0.3);
transition: transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.cartbtn:hover {
transform: translateY(-1px) scale(1.04);
box-shadow: 0 8px 22px rgba(214, 51, 108, 0.4);
}
.count {
transition: transform 0.2s var(--ease);
}
.count--pop {
animation: popIn 0.42s var(--ease);
}
/* ---------- badges & chips ---------- */
.badge {
box-shadow: 0 2px 8px rgba(31, 26, 28, 0.14);
}
.badge--hit {
background: var(--grad-rose);
background-size: 170% 170%;
animation: gradientShift 7s ease-in-out infinite;
}
.badge--new {
background: var(--grad-sage);
}
.badge--sale {
background: var(--grad-gold);
color: #4a3a12;
}
.badge--discount {
background: linear-gradient(135deg, #e76a6a 0%, #c62b2b 100%);
}
.chip {
transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease), color 0.15s var(--ease),
transform 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.chip:hover {
transform: translateY(-1px);
box-shadow: var(--shadow-sm);
}
.chip--active {
background-image: var(--grad-dark);
border-color: transparent;
}
/* ---------- sections, tiles, cards ---------- */
.trust {
background: linear-gradient(180deg, #fff 0%, #fffafb 100%);
}
.trust__ico {
background: var(--grad-rose-soft);
transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.trust__item:hover .trust__ico {
transform: translateY(-2px) rotate(-4deg);
box-shadow: 0 8px 18px rgba(214, 51, 108, 0.22);
}
.cat {
transition: transform 0.22s var(--ease), box-shadow 0.25s var(--ease), border-color 0.25s var(--ease);
}
.cat:hover {
transform: translateY(-4px);
box-shadow: 0 16px 36px rgba(31, 26, 28, 0.14);
border-color: var(--rose-100);
}
.cat__media img {
transition: transform 0.6s var(--ease);
}
.cat--all {
position: relative;
overflow: hidden;
background: var(--grad-dark);
background-size: 200% 200%;
animation: gradientShift 9s ease-in-out infinite;
}
.cat--all::after {
content: '';
position: absolute;
top: -60px;
right: -40px;
width: 180px;
height: 180px;
border-radius: 50%;
background: radial-gradient(circle, rgba(214, 51, 108, 0.55), transparent 65%);
pointer-events: none;
animation: floatY 8s ease-in-out infinite;
}
.cat--all .cat__count,
.cat--all .cat__cta {
position: relative;
z-index: 1;
}
.cat--all .cat__count {
color: var(--gold-500);
}
@supports (background-clip: text) or (-webkit-background-clip: text) {
.cat--all .cat__count {
background: var(--grad-gold);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
-webkit-text-fill-color: transparent;
}
}
.pcard {
transition: transform 0.22s var(--ease), box-shadow 0.25s var(--ease), border-color 0.25s var(--ease);
}
.pcard:hover {
transform: translateY(-4px);
border-color: var(--rose-100);
box-shadow: 0 16px 40px rgba(214, 51, 108, 0.16);
}
.pcard__media img {
transition: transform 0.6s var(--ease);
}
.pcard__add {
background: var(--grad-rose);
box-shadow: 0 4px 12px rgba(214, 51, 108, 0.32);
transition: transform 0.22s var(--ease), box-shadow 0.22s var(--ease), background-color 0.15s var(--ease);
}
.pcard__add:hover {
transform: scale(1.14);
box-shadow: 0 6px 18px rgba(214, 51, 108, 0.45);
}
.pcard__add:active {
transform: scale(0.94);
}
.pcard__add:disabled {
background: var(--disabled);
color: var(--ink-400);
box-shadow: none;
cursor: not-allowed;
}
@media (hover: hover) {
.pcard:hover .pcard__media img,
.cat:hover .cat__media img {
transform: scale(1.055);
}
}
.info-card {
transition: transform 0.22s var(--ease), box-shadow 0.25s var(--ease), border-color 0.25s var(--ease);
}
.info-card:hover {
transform: translateY(-3px);
box-shadow: var(--shadow-md);
border-color: var(--line-300);
}
.info-card__ico {
background: var(--grad-sage);
color: #fff;
box-shadow: 0 8px 20px rgba(63, 111, 91, 0.26);
transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.info-card:hover .info-card__ico {
transform: translateY(-3px) scale(1.04);
}
.banner {
position: relative;
overflow: hidden;
background: var(--grad-dark);
background-size: 200% 200%;
animation: gradientShift 14s ease-in-out infinite;
box-shadow: 0 24px 60px rgba(31, 26, 28, 0.22);
}
.banner::before,
.banner::after {
content: '';
position: absolute;
border-radius: 50%;
pointer-events: none;
}
.banner::before {
top: -140px;
right: -60px;
width: 340px;
height: 340px;
background: radial-gradient(circle at 40% 40%, rgba(214, 51, 108, 0.5), transparent 68%);
animation: floatY 11s ease-in-out infinite;
}
.banner::after {
bottom: -160px;
left: -80px;
width: 320px;
height: 320px;
background: radial-gradient(circle at 50% 50%, rgba(200, 169, 106, 0.32), transparent 68%);
animation: floatX 15s ease-in-out infinite;
}
.banner > * {
position: relative;
z-index: 1;
}
.page-head {
background: linear-gradient(180deg, var(--cream-100) 0%, #fff 100%);
}
.page-cta {
position: relative;
overflow: hidden;
background: var(--grad-dark);
}
.page-cta::before {
content: '';
position: absolute;
top: -120px;
right: -60px;
width: 260px;
height: 260px;
border-radius: 50%;
background: radial-gradient(circle, rgba(214, 51, 108, 0.42), transparent 66%);
pointer-events: none;
animation: floatY 12s ease-in-out infinite;
}
.page-cta > * {
position: relative;
z-index: 1;
}
.progress__fill {
background: linear-gradient(90deg, #e64980 0%, #d6336c 60%, #93214a 100%);
}
.progress--done .progress__fill {
background: linear-gradient(90deg, #34c07a 0%, #16a34a 100%);
}
.range__fill {
background: var(--grad-rose);
}
.card__step {
background: var(--grad-rose);
box-shadow: 0 4px 10px rgba(214, 51, 108, 0.3);
}
.hero__dot {
animation: dotPulse 3.2s ease-out infinite;
}
/* ---------- footer ---------- */
.site-footer {
position: relative;
overflow: hidden;
background: var(--grad-dark);
background-size: 200% 200%;
animation: gradientShift 18s ease-in-out infinite;
}
.site-footer::before {
content: '';
position: absolute;
top: -190px;
left: 50%;
width: min(900px, 120%);
height: 380px;
border-radius: 50%;
transform: translateX(-50%);
background: radial-gradient(ellipse at center, rgba(214, 51, 108, 0.22), transparent 70%);
pointer-events: none;
}
.site-footer > * {
position: relative;
z-index: 1;
}
.footer__list a {
display: inline-block;
transition: color 0.18s var(--ease), transform 0.18s var(--ease);
}
.footer__list a:hover {
transform: translateX(3px);
}
/* ---------- toast, selection, scrollbar ---------- */
.toast--in {
animation: toastIn 0.35s var(--ease);
}
::selection {
background: rgba(214, 51, 108, 0.22);
color: var(--ink-900);
}
@media (min-width: 768px) {
html {
scrollbar-color: #e3c3d0 transparent;
}
::-webkit-scrollbar {
width: 12px;
height: 12px;
}
::-webkit-scrollbar-thumb {
border: 3px solid var(--cream-100);
border-radius: var(--r-pill);
background: linear-gradient(180deg, #f7d9e4 0%, #d9b8c6 100%);
}
::-webkit-scrollbar-thumb:hover {
background: var(--grad-rose);
}
::-webkit-scrollbar-track {
background: transparent;
}
}
/* A touch more life on the scroll-in reveals (the standalone `scale` property
never fights a component's own `transform`). */
@media (prefers-reduced-motion: no-preference) {
.reveal {
scale: 0.985;
transition: opacity 0.55s var(--ease), translate 0.55s var(--ease), scale 0.55s var(--ease);
transition-delay: var(--reveal-delay, 0ms);
}
.reveal.is-visible {
scale: 1;
}
}
@media (prefers-reduced-motion: reduce) {
.hero::before,
.hero::after,
.cat--all,
.cat--all::after,
.banner,
.banner::before,
.banner::after,
.page-cta::before,
.site-footer,
.badge--hit,
.hero__dot,
.overline {
animation: none !important;
}
.btn--primary::before {
display: none;
}
}
/* ============================================================================
Home variant B (A/B test) — the "flower field"
Rows of slit-tilted bouquet cells drift left / right (even rows left, odd
rows right). Hovering a row stops it; the cell under the pointer grows 20%
and reveals its bouquet card, so the grid reads as a living meadow.
========================================================================== */
.flowerfield {
/* x-gaps squeezed to a sixth (a third, then halved again) so the rows read as
a dense meadow with the blossoms almost touching. */
--ff-gap: calc(14px / 6);
/* Side tilt trimmed by 30% (26px → 18.2px): the corners are still clearly
slanted, just gentler. */
--ff-slant: 18.2px;
--ff-rowgap: 12px;
/* Hover glow + frame: the warm yellow the meadow lights up with. */
--ff-glow: #ffcb3d;
--ff-frame: 3px;
position: relative;
overflow: hidden;
/* Room above the first / below the last row for a hovered cell to grow. */
padding: 40px 0 46px;
background: var(--grad-hero);
}
.flowerfield__intro {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 10px 20px;
padding-block: 4px 26px;
}
.flowerfield__title {
font-size: clamp(24px, 4.2vw, 40px);
margin-top: 4px;
}
.flowerfield__rows {
display: flex;
flex-direction: column;
gap: var(--ff-rowgap);
}
/* No clip of its own: the field clips the drifting track at the viewport
edges, and a hovered cell is allowed to spill past its row (the meadow).
The row is positioned so a hovered one can lift above its neighbours: the
drifting track makes its own stacking context, so the cell's own z-index
cannot raise it over the next row. */
.ffrow {
position: relative;
z-index: 1;
overflow: visible;
}
.ffrow:hover,
.ffrow:focus-within {
z-index: 4;
}
.ffrow__track {
display: flex;
width: max-content;
will-change: transform;
}
/* Identical sets: translating the track by exactly one set (‑33.333% with three
sets) makes the loop seamless. `padding-right` keeps the junction gap the
same as the gaps inside a set. */
.ffrow__set {
display: flex;
gap: var(--ff-gap);
padding-right: var(--ff-gap);
}
.ffrow--left .ffrow__track {
animation: ffDriftLeft var(--ff-dur, 96s) linear infinite;
}
.ffrow--right .ffrow__track {
animation: ffDriftRight var(--ff-dur, 96s) linear infinite;
}
@keyframes ffDriftLeft {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(-33.3333%, 0, 0);
}
}
@keyframes ffDriftRight {
from {
transform: translate3d(-33.3333%, 0, 0);
}
to {
transform: translate3d(0, 0, 0);
}
}
/* The little wobble a hovered cell does as it grows: a couple of degrees one
way, then the other, then settles back to 0. The standalone `rotate` keeps it
from fighting the `scale()` in `transform`. */
@keyframes ffNudge {
0% {
rotate: 0deg;
}
35% {
rotate: 2.4deg;
}
70% {
rotate: -1.6deg;
}
100% {
rotate: 0deg;
}
}
/* The glow breathes: two yellow halos around the shape (plus a soft ink shadow
to keep the cell lifted) swell and settle while the bouquet is hovered. */
@keyframes ffGlow {
0%,
100% {
filter: drop-shadow(0 0 6px rgba(255, 203, 61, 0.55))
drop-shadow(0 0 18px rgba(255, 186, 45, 0.3)) drop-shadow(0 16px 26px rgba(31, 26, 28, 0.3));
}
50% {
filter: drop-shadow(0 0 15px rgba(255, 214, 92, 0.95))
drop-shadow(0 0 40px rgba(255, 186, 45, 0.6)) drop-shadow(0 20px 30px rgba(31, 26, 28, 0.38));
}
}
.ffcell {
position: relative;
z-index: 1;
display: block;
flex: 0 0 auto;
width: clamp(146px, 15.5vw, 222px);
height: clamp(196px, 20.5vw, 292px);
/* No clip here: the slanted shape moved to `.ffcell__clip` one level deeper,
so the golden frame (`::before`, inset outside the shape) is not cut off
and the glow — a `drop-shadow` — can spill past the cell like sunlight. */
transition: transform 0.34s var(--ease), filter 0.34s var(--ease);
}
/* The photo stack + card, cut to the parallelogram (bottom edge shifted left). */
.ffcell__clip {
position: absolute;
inset: 0;
display: block;
overflow: hidden;
background: var(--cream-200);
clip-path: polygon(
var(--ff-slant) 0,
100% 0,
calc(100% - var(--ff-slant)) 100%,
0 100%
);
}
/* The frame: a slightly larger copy of the same parallelogram sitting behind
the clipped photo, so its golden edge shows as a ~3px rim that follows the
slant. Invisible at rest, painted on hover / keyboard focus. */
.ffcell::before {
content: '';
position: absolute;
inset: calc(var(--ff-frame) * -1);
background: linear-gradient(150deg, #ffe79a 0%, var(--ff-glow) 45%, #f2a51d 100%);
clip-path: polygon(
var(--ff-slant) 0,
100% 0,
calc(100% - var(--ff-slant)) 100%,
0 100%
);
opacity: 0;
transition: opacity 0.28s var(--ease);
}
/* Every shot of the bouquet is stacked in the cell; only the active one is
opaque. Hovering cross-fades to the next after a few seconds. */
.ffcell__img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0;
transition: opacity 0.7s var(--ease);
}
.ffcell__img.is-active {
opacity: 1;
}
/* The bouquet card, revealed on hover / focus. */
.ffcell__info {
position: absolute;
/* The card rests on the bottom edge of the parallelogram, where the shape
spans 0 … (100% − slant). Matching that span keeps the gradient flush with
the photo on both sides; with a slant inset on the left it used to stop
short there and read as if the text had slid into the right edge. */
left: 0;
right: var(--ff-slant);
bottom: 0;
display: flex;
flex-direction: column;
gap: 1px;
padding: 40px 14px 14px;
color: #fff;
background: linear-gradient(
180deg,
rgba(31, 26, 28, 0) 0%,
rgba(31, 26, 28, 0.6) 45%,
rgba(31, 26, 28, 0.92) 100%
);
opacity: 0;
transform: translateY(14px);
transition: opacity 0.24s var(--ease), transform 0.3s var(--ease);
pointer-events: none;
}
.ffcell__name {
font-family: var(--font-display);
font-weight: 700;
font-size: 15px;
line-height: 1.25;
}
.ffcell__meta {
font-size: 12px;
color: rgba(255, 255, 255, 0.82);
}
.ffcell__price {
margin-top: 4px;
font-weight: 700;
color: #ffd9e7;
}
.ffcell__cta {
margin-top: 6px;
font-size: 12px;
font-weight: 600;
color: var(--gold-500);
}
/* A row stops while its bouquet is read; the cell under the pointer grows 20%,
wobbles, lights up with the yellow glow + frame and shows its card. Keyboard
focus behaves the same way. */
.ffrow:focus-within .ffrow__track {
animation-play-state: paused;
}
.ffcell:focus-visible {
z-index: 10;
transform: scale(1.2);
/* Fallback for engines that will not run the animation: the same glow, still. */
filter: drop-shadow(0 0 9px rgba(255, 203, 61, 0.7))
drop-shadow(0 0 26px rgba(255, 186, 45, 0.42)) drop-shadow(0 18px 28px rgba(31, 26, 28, 0.34));
animation: ffNudge 0.9s var(--ease), ffGlow 1.9s ease-in-out infinite;
}
.ffcell:focus-visible::before {
opacity: 1;
}
.ffcell:focus-visible .ffcell__info {
opacity: 1;
transform: none;
}
@media (hover: hover) {
.ffrow:hover .ffrow__track {
animation-play-state: paused;
}
.ffcell:hover {
z-index: 10;
transform: scale(1.2);
filter: drop-shadow(0 0 9px rgba(255, 203, 61, 0.7))
drop-shadow(0 0 26px rgba(255, 186, 45, 0.42)) drop-shadow(0 18px 28px rgba(31, 26, 28, 0.34));
animation: ffNudge 0.9s var(--ease), ffGlow 1.9s ease-in-out infinite;
}
.ffcell:hover::before {
opacity: 1;
}
.ffcell:hover .ffcell__info {
opacity: 1;
transform: none;
}
}
@media (prefers-reduced-motion: reduce) {
.ffrow__track {
animation: none !important;
}
/* Keep the yellow frame, drop the wobble and the pulsing glow. */
.ffcell {
animation: none !important;
}
}
/* ============================================================================
AI-агент «Анжелина» (Wiz4Chat widget) — a floating launcher that opens the
embedded chat upwards. It sits above the mobile bottom nav (z-index 40) but
below the toast (60) and the lightbox (70), so the overlays still win.
========================================================================== */
.agentwidget {
position: fixed;
right: 20px;
/* Clear the 64px bottom nav on phones and tablets. */
bottom: calc(64px + env(safe-area-inset-bottom) + 16px);
z-index: 50;
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 12px;
/* The empty space around the button and the panel must not swallow clicks. */
pointer-events: none;
}
.agentwidget > * {
pointer-events: auto;
}
.agentwidget__launch {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
height: 52px;
padding: 0 20px 0 16px;
border: 0;
border-radius: var(--r-pill);
background-image: var(--grad-rose);
background-size: 170% 170%;
color: #fff;
font-family: inherit;
font-size: 14px;
font-weight: 600;
cursor: pointer;
box-shadow: 0 10px 26px rgba(214, 51, 108, 0.38);
transition: transform 0.2s var(--ease), box-shadow 0.25s var(--ease);
animation: gradientShift 9s ease-in-out infinite;
}
.agentwidget__launch svg {
width: 22px;
height: 22px;
flex: none;
}
.agentwidget__launch:hover {
transform: translateY(-2px);
box-shadow: 0 14px 32px rgba(214, 51, 108, 0.46);
}
.agentwidget__launch:active {
transform: translateY(0) scale(0.97);
}
/* The panel takes the embed's 380×560 and shrinks to fit a small viewport. */
.agentwidget__panel {
position: relative;
width: min(380px, calc(100vw - 40px));
border-radius: 14px;
background: transparent;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.18);
animation: agentPanelIn 0.24s var(--ease);
}
.agentwidget__frame {
display: block;
width: 100%;
height: 560px;
max-height: calc(100vh - 200px);
max-height: calc(100dvh - 200px);
border: 0;
border-radius: 14px;
background: transparent;
color-scheme: normal;
}
.agentwidget__close {
position: absolute;
top: -10px;
right: -10px;
z-index: 1;
display: grid;
place-items: center;
width: 28px;
height: 28px;
padding: 0;
border: 0;
border-radius: 50%;
background: var(--ink-900);
color: #fff;
font-size: 13px;
line-height: 1;
cursor: pointer;
box-shadow: var(--shadow-md);
transition: transform 0.18s var(--ease), background-color 0.18s var(--ease);
}
.agentwidget__close:hover {
background: #000;
transform: scale(1.08);
}
@keyframes agentPanelIn {
from {
opacity: 0;
transform: translateY(10px) scale(0.98);
}
to {
opacity: 1;
transform: none;
}
}
/* From 1200px the bottom nav is gone, so the launcher drops to the corner and
the panel may use the freed height. */
@media (min-width: 1200px) {
.agentwidget {
right: 28px;
bottom: 28px;
}
.agentwidget__frame {
max-height: calc(100vh - 130px);
max-height: calc(100dvh - 130px);
}
}
/* On a narrow phone a pill would eat the corner: collapse it to the icon. */
@media (max-width: 480px) {
.agentwidget__launch {
width: 52px;
padding: 0;
}
.agentwidget__label {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}
}
/* ============================================================================
A/B home switcher — a small rose-tinted card that floats just under the
sticky header. It offers the two home variants as side-by-side tiles
(A = classic hero, B = the flower field) and stays on screen on both home
routes, so the visitor can flip back and forth; only an explicit close is
remembered in sessionStorage (public/app.js → initVariantPrompt), and the
card stays away until the tab closes.
z-index sits above the toast (60) but below the lightbox (70).
========================================================================== */
.variantprompt {
position: fixed;
/* The real value is measured in app.js (the header height varies with the
topbar breakpoint); this is only the pre-hydration fallback. */
top: 76px;
left: 50%;
z-index: 65;
display: flex;
align-items: center;
gap: 14px;
width: min(780px, calc(100vw - 24px));
padding: 13px 52px 13px 16px;
border: 1px solid rgba(255, 255, 255, 0.7);
border-radius: var(--r-2xl);
background: linear-gradient(
135deg,
rgba(255, 255, 255, 0.97) 0%,
rgba(253, 242, 246, 0.97) 58%,
rgba(247, 217, 228, 0.95) 100%
);
box-shadow: 0 18px 44px rgba(31, 26, 28, 0.18), 0 0 0 1px rgba(214, 51, 108, 0.06);
backdrop-filter: blur(14px);
/* Clip the top hairline (::before) to the card's 24px corners. A 3px-tall
pseudo-element cannot carry a 24px radius itself — the browser scales the
radii down to half the box height, leaving square ends that poke out past
the rounded silhouette — so the rounded clipping has to come from here. */
overflow: hidden;
transform: translateX(-50%);
animation: variantPromptIn 0.42s var(--ease) both;
}
/* A thin gradient hairline hugging the top edge. Its top rounding is inherited
from the parent's border-radius through the `overflow: hidden` above. */
.variantprompt::before {
content: '';
position: absolute;
inset: 0 0 auto 0;
height: 3px;
border-radius: var(--r-2xl) var(--r-2xl) 0 0;
background: var(--grad-rose);
opacity: 0.9;
}
.variantprompt__lead {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
}
.variantprompt__ico {
display: grid;
place-items: center;
flex: none;
width: 38px;
height: 38px;
border-radius: 50%;
font-size: 18px;
background: var(--grad-rose);
box-shadow: 0 6px 16px rgba(214, 51, 108, 0.32);
}
.variantprompt__text {
min-width: 0;
}
.variantprompt__title {
font-family: var(--font-display);
font-weight: 700;
font-size: 15px;
line-height: 1.2;
color: var(--ink-900);
}
.variantprompt__desc {
margin-top: 2px;
font-size: 12px;
line-height: 1.35;
color: var(--ink-400);
}
.variantprompt__options {
display: flex;
gap: 8px;
margin-left: auto;
}
/* One variant tile: a tiny CSS drawing of that home page + its name. */
.variantprompt__opt {
position: relative;
display: flex;
align-items: center;
gap: 10px;
flex: none;
padding: 7px 30px 7px 8px;
border: 1.5px solid var(--line-100);
border-radius: var(--r-xl);
background: #fff;
color: inherit;
cursor: pointer;
transition: border-color 0.2s var(--ease), background-color 0.2s var(--ease),
box-shadow 0.25s var(--ease), transform 0.2s var(--ease);
}
.variantprompt__opt:hover {
transform: translateY(-2px);
border-color: var(--rose-100);
box-shadow: 0 10px 22px rgba(214, 51, 108, 0.16);
}
.variantprompt__opt.is-active {
border-color: var(--rose-500);
background: var(--rose-50);
box-shadow: 0 8px 20px rgba(214, 51, 108, 0.18);
}
.variantprompt__opt-text {
display: flex;
flex-direction: column;
gap: 1px;
min-width: 0;
}
.variantprompt__opt-name {
font-size: 13px;
font-weight: 700;
line-height: 1.2;
}
.variantprompt__opt-note {
font-size: 11px;
line-height: 1.25;
color: var(--ink-400);
white-space: nowrap;
}
/* The tick only shows on the variant the visitor is looking at now. */
.variantprompt__check {
position: absolute;
top: 50%;
right: 9px;
display: grid;
place-items: center;
width: 17px;
height: 17px;
margin-top: -8.5px;
border-radius: 50%;
background: var(--rose-500);
color: #fff;
opacity: 0;
transform: scale(0.6);
transition: opacity 0.2s var(--ease), transform 0.24s var(--ease);
}
.variantprompt__check svg {
width: 11px;
height: 11px;
}
.variantprompt__opt.is-active .variantprompt__check {
opacity: 1;
transform: scale(1);
}
/* --- the two miniatures ------------------------------------------------- */
.variantprompt__thumb {
position: relative;
flex: none;
width: 46px;
height: 34px;
border-radius: 9px;
overflow: hidden;
background: var(--cream-200);
box-shadow: inset 0 0 0 1px rgba(31, 26, 28, 0.06);
}
/* A — hero photo with two text lines underneath. */
.variantprompt__thumb--a {
display: grid;
align-content: center;
gap: 3px;
padding: 4px;
}
.variantprompt__thumb-hero {
display: block;
height: 15px;
border-radius: 4px;
background: linear-gradient(135deg, #f7c9da 0%, #d6336c 100%);
}
.variantprompt__thumb-line {
display: block;
height: 3px;
border-radius: 2px;
background: var(--line-300);
}
.variantprompt__thumb-line--sm {
width: 62%;
}
/* B — three slanted "field" cells, like the drifting rows of bouquets. */
.variantprompt__thumb--b {
display: flex;
align-items: center;
gap: 3px;
padding: 4px;
background: linear-gradient(158deg, #fffaf7 0%, #f6e7ee 100%);
}
.variantprompt__petal {
flex: 1;
height: 22px;
border-radius: 3px;
background: linear-gradient(135deg, #f0a7c2 0%, #c8a96a 100%);
transform: skewX(-12deg);
}
/* --- close -------------------------------------------------------------- */
.variantprompt__close {
position: absolute;
top: 9px;
right: 9px;
display: grid;
place-items: center;
width: 30px;
height: 30px;
padding: 0;
border: 0;
border-radius: 50%;
background: transparent;
color: var(--ink-400);
cursor: pointer;
transition: background-color 0.18s var(--ease), color 0.18s var(--ease), transform 0.22s var(--ease);
}
.variantprompt__close:hover {
background: var(--ink-900);
color: #fff;
transform: rotate(90deg);
}
.variantprompt__close svg {
width: 16px;
height: 16px;
}
@keyframes variantPromptIn {
from {
opacity: 0;
transform: translate(-50%, -16px) scale(0.98);
}
to {
opacity: 1;
transform: translate(-50%, 0) scale(1);
}
}
/* Narrow screens: stack the copy over two full-width tiles. */
@media (max-width: 760px) {
.variantprompt {
flex-direction: column;
align-items: stretch;
gap: 10px;
padding: 14px 46px 14px 14px;
}
.variantprompt__options {
margin-left: 0;
}
.variantprompt__opt {
flex: 1;
}
}
@media (max-width: 380px) {
.variantprompt__desc {
display: none;
}
.variantprompt__opt-note {
white-space: normal;
}
}