generated from wiz4apps/templates.OnlineShop
4621 lines
93 KiB
CSS
4621 lines
93 KiB
CSS
/* ============================================================================
|
||
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;
|
||
}
|
||
}
|
||
|