Files
kvarta_project/apps/landing/src/app/globals.css
T
nunuchek d8d67c036f feat(landing): штамп, лента недели, состояния кнопки, липкая CTA
Оттиск штампа при загрузке и при успехе формы, заполнение ленты
недели по IntersectionObserver, мигающие точки при отправке.
Только CSS и transform/opacity; анимации включает скрипт в head,
поэтому без JS и при prefers-reduced-motion всё сразу в финале.
Липкая CTA на мобиле: «Заказать кофе», прячется у формы, при фокусе
в ней и при открытой клавиатуре. Ритм секций плотнее.
2026-10-17 16:56:52 +03:00

589 lines
13 KiB
CSS

@import 'tailwindcss';
/* Токены — DESIGN.md. Палитра Tailwind отключена: только цвета «Кварты». */
@theme {
--color-*: initial;
--color-cream: #f3ebdd;
--color-paper: #fbf7f0;
--color-kraft: #dcc7a1;
--color-roast: #1e120c;
--color-ink: #2a1810;
--color-muted: #5e4636;
--color-placeholder: #7a6352;
--color-rule-soft: #c9b595;
--color-cherry: #b3221b;
--color-cherry-deep: #8f1a14;
--color-cherry-on-dark: #e8604f;
--color-muted-on-dark: #bfa88a;
--color-ok: #2e5e3a;
--color-transparent: transparent;
--color-current: currentColor;
--radius-*: initial;
--radius-none: 0px;
--radius-hair: 2px;
--shadow-*: initial;
--text-display: clamp(2.75rem, 1.6rem + 5.2vw, 6rem);
--text-display--line-height: 0.92;
--text-display--letter-spacing: -0.035em;
--text-headline: clamp(2rem, 1.4rem + 2.8vw, 3.5rem);
--text-headline--line-height: 1;
--text-headline--letter-spacing: -0.03em;
--text-title: clamp(1.5rem, 1.3rem + 0.6vw, 1.875rem);
--text-title--line-height: 1.05;
--text-title--letter-spacing: -0.02em;
--text-lead: clamp(1.125rem, 1rem + 0.5vw, 1.375rem);
--text-lead--line-height: 1.45;
--text-body: 1.0625rem;
--text-body--line-height: 1.55;
--text-small: 0.875rem;
--text-small--line-height: 1.45;
--text-ui: 0.9375rem;
--text-ui--line-height: 1.3;
--text-tag: 0.75rem;
--text-tag--line-height: 1.3;
--text-tag--letter-spacing: 0.08em;
--text-price: clamp(1.375rem, 1.2rem + 0.8vw, 2rem);
--text-price--line-height: 1;
--text-price--letter-spacing: -0.02em;
--text-date: clamp(1.75rem, 1.2rem + 2.2vw, 3.25rem);
--text-date--line-height: 1;
--text-date--letter-spacing: -0.04em;
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
--ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
--ease-in-quart: cubic-bezier(0.5, 0, 0.75, 0);
--container-page: 1280px;
}
@theme inline {
--font-sans: var(--font-golos), system-ui, sans-serif;
--font-mono: var(--font-martian), ui-monospace, monospace;
}
@layer base {
html {
background: var(--color-cream);
color: var(--color-ink);
scroll-padding-top: 16px;
-webkit-text-size-adjust: 100%;
}
body {
font-family: var(--font-sans);
font-size: var(--text-body);
line-height: 1.55;
background: var(--color-cream);
-webkit-tap-highlight-color: transparent;
font-synthesis: none;
}
::selection {
background: var(--color-cherry);
color: var(--color-paper);
}
:focus-visible {
outline: 2px solid var(--color-ink);
outline-offset: 3px;
}
.on-dark :focus-visible {
outline-color: var(--color-cream);
}
input,
textarea {
caret-color: var(--color-cherry);
}
a {
text-decoration-thickness: 1px;
text-underline-offset: 3px;
}
h1,
h2,
h3 {
text-wrap: balance;
}
p {
text-wrap: pretty;
}
}
@layer components {
/* моно-шрифт: ширина через wdth-ось Martian Mono */
.mono {
font-family: var(--font-mono);
font-variant-numeric: tabular-nums;
}
.mono-narrow {
font-family: var(--font-mono);
font-stretch: 87.5%;
font-variation-settings: 'wdth' 87.5;
}
.tag {
font-family: var(--font-mono);
font-size: var(--text-tag);
line-height: 1.3;
letter-spacing: 0.08em;
font-weight: 500;
text-transform: uppercase;
}
.page-x {
padding-inline: 20px;
}
@media (min-width: 1024px) {
.page-x {
padding-inline: 48px;
}
}
.container-page {
margin-inline: auto;
max-width: var(--container-page);
}
.section-y {
padding-block: 48px;
}
@media (min-width: 1024px) {
.section-y {
padding-block: 80px;
}
}
/* Кнопки */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 10px;
min-height: 52px;
padding: 0 24px;
font-family: var(--font-sans);
font-size: 1rem;
font-weight: 700;
line-height: 1.2;
text-align: center;
border-radius: 0;
cursor: pointer;
user-select: none;
transition:
background-color 120ms ease-out,
color 120ms ease-out,
border-color 120ms ease-out,
transform 60ms linear;
}
.btn:active:not(:disabled) {
transform: translateY(1px);
}
.btn-primary {
background: var(--color-cherry);
color: var(--color-paper);
}
.btn-primary:active:not(:disabled) {
background: var(--color-cherry-deep);
}
.btn-secondary {
background: transparent;
color: var(--color-ink);
box-shadow: inset 0 0 0 1.5px var(--color-ink);
padding: 0 20px;
}
.btn-on-dark {
background: transparent;
color: var(--color-cream);
box-shadow: inset 0 0 0 1.5px var(--color-cream);
padding: 0 20px;
}
@media (hover: hover) {
.btn-primary:hover:not(:disabled) {
background: var(--color-cherry-deep);
}
.btn-secondary:hover:not(:disabled) {
background: var(--color-ink);
color: var(--color-cream);
}
.btn-on-dark:hover:not(:disabled) {
background: var(--color-cream);
color: var(--color-roast);
}
}
.btn:disabled:not([aria-busy]) {
background: var(--color-rule-soft);
color: var(--color-ink);
box-shadow: none;
cursor: not-allowed;
}
.btn[aria-busy='true'] {
cursor: progress;
}
.busy-dots {
display: inline-flex;
gap: 4px;
}
.busy-dots i {
width: 4px;
height: 4px;
background: currentColor;
}
/* Поля формы */
.field-label {
font-size: var(--text-ui);
font-weight: 600;
line-height: 1.3;
}
.field {
display: block;
width: 100%;
min-height: 52px;
padding: 12px 14px;
background: var(--color-paper);
color: var(--color-ink);
font-size: 1.0625rem;
line-height: 1.45;
border: 1.5px solid var(--color-muted);
border-radius: 0;
transition: border-color 120ms ease-out;
}
.field::placeholder {
color: var(--color-placeholder);
opacity: 1;
}
.field:focus {
border-color: var(--color-ink);
box-shadow: inset 0 0 0 0.5px var(--color-ink);
}
.field:focus-visible {
outline-offset: 2px;
}
.field[data-invalid] {
border-color: var(--color-cherry);
box-shadow: inset 0 0 0 0.5px var(--color-cherry);
}
textarea.field {
min-height: 112px;
resize: vertical;
}
.field-error {
display: flex;
gap: 6px;
align-items: flex-start;
font-size: var(--text-small);
font-weight: 500;
line-height: 1.45;
color: var(--color-cherry-deep);
}
.talon {
position: relative;
display: flex;
align-items: center;
gap: 10px;
min-height: 48px;
padding: 0 16px;
font-size: var(--text-ui);
font-weight: 600;
box-shadow: inset 0 0 0 1.5px var(--color-muted);
cursor: pointer;
transition:
background-color 120ms ease-out,
color 120ms ease-out;
}
.talon::before {
content: '';
width: 10px;
height: 10px;
flex: none;
box-shadow: inset 0 0 0 1.5px currentColor;
}
.talon[data-checked] {
background: var(--color-ink);
color: var(--color-cream);
box-shadow: inset 0 0 0 1.5px var(--color-ink);
}
.talon[data-checked]::before {
background: var(--color-cherry);
box-shadow: none;
}
.talon:has(:focus-visible) {
outline: 2px solid var(--color-ink);
outline-offset: 2px;
}
[data-invalid] .talon:not([data-checked]) {
box-shadow: inset 0 0 0 2px var(--color-cherry);
}
@media (hover: hover) {
.talon:not([data-checked]):hover {
background: var(--color-cream);
}
}
/* Этикетка: лента-наклейка, срезанная краем */
.ribbon {
position: absolute;
top: 34px;
right: -62px;
width: 220px;
padding: 6px 0;
background: var(--color-cherry);
color: var(--color-paper);
text-align: center;
transform: rotate(45deg);
pointer-events: none;
}
.perforation {
background-image: linear-gradient(to right, var(--color-ink) 0 6px, transparent 6px 10px);
background-size: 10px 1px;
background-repeat: repeat-x;
height: 1px;
}
}
/* Штамп */
@layer components {
.stamp {
display: inline-block;
transform: rotate(var(--stamp-rotate, -6deg));
opacity: 0.92;
}
.stamp-text {
font-family: var(--font-mono);
font-weight: 700;
font-stretch: 112.5%;
font-variation-settings: 'wdth' 112.5;
letter-spacing: 0.04em;
}
}
/* Лента недели: 390 — столбиком, ≥1024 — строкой */
@layer components {
.week-days {
display: grid;
grid-template-columns: minmax(0, 1fr) 128px;
column-gap: 12px;
}
.week-day {
grid-column: 1;
display: grid;
grid-template-columns: 64px minmax(0, 1fr);
column-gap: 12px;
align-items: center;
min-height: 60px;
padding-block: 10px;
position: relative;
}
.week-head {
display: flex;
flex-direction: column;
gap: 2px;
}
.week-letter {
font-size: 0.875rem;
font-weight: 800;
letter-spacing: 0.04em;
line-height: 1;
}
.week-date {
font-size: var(--text-date);
font-weight: 700;
line-height: 1;
letter-spacing: -0.04em;
}
.week-rule {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 1px;
background: var(--color-ink);
transform-origin: left;
}
.week-mark {
position: absolute;
left: 0;
width: 64px;
bottom: -1px;
height: 4px;
background: var(--color-cherry);
transform-origin: left;
}
.week-note {
display: flex;
flex-direction: column;
gap: 2px;
}
.week-bracket {
grid-column: 2;
grid-row: 5 / 8;
display: flex;
gap: 10px;
padding-block: 12px;
}
.week-bracket-line {
flex: none;
width: 8px;
border: 2px solid var(--color-cherry);
border-left: 0;
transform-origin: top;
}
.week-bracket-note {
display: flex;
flex-direction: column;
gap: 4px;
align-self: center;
}
@media (min-width: 1024px) {
.week-days {
grid-template-columns: repeat(7, minmax(0, 1fr));
column-gap: 0;
}
.week-day {
grid-column: auto;
display: flex;
flex-direction: column;
align-items: stretch;
padding: 0;
min-height: 0;
}
.week-head {
position: relative;
gap: 10px;
padding: 0 16px 20px;
border-left: 1px solid var(--color-rule-soft);
}
.week-day:first-child .week-head {
border-left: 0;
padding-left: 0;
}
.week-letter {
font-size: 1rem;
}
.week-mark {
left: 16px;
right: 16px;
width: auto;
}
.week-note {
padding: 16px 16px 0;
}
.week-bracket {
grid-column: 5 / 8;
grid-row: 2;
flex-direction: column;
gap: 12px;
padding: 28px 16px 0;
}
.week-bracket-line {
width: auto;
height: 10px;
border: 2px solid var(--color-cherry);
border-top: 0;
transform-origin: left;
}
.week-bracket-note {
align-self: auto;
}
}
}
/* Моушн (DESIGN.md → «Моушн»). Без JS и при reduced-motion — сразу финальное состояние. */
@keyframes stamp-in {
from {
opacity: 0;
transform: rotate(calc(var(--stamp-rotate, -6deg) - 3deg)) scale(1.18);
}
to {
opacity: 0.92;
transform: rotate(var(--stamp-rotate, -6deg)) scale(1);
}
}
@keyframes busy-dot {
0%,
100% {
opacity: 0.3;
}
33% {
opacity: 1;
}
}
@keyframes fade-in {
from {
opacity: 0;
}
}
@media (prefers-reduced-motion: no-preference) {
[data-motion] .stamp[data-stamp='load'] {
animation: stamp-in 380ms var(--ease-out-expo) 250ms both;
}
.stamp[data-stamp='event'] {
animation: stamp-in 380ms var(--ease-out-expo) 80ms both;
}
.busy-dots i {
animation: busy-dot 480ms steps(1) infinite;
}
.busy-dots i:nth-child(2) {
animation-delay: 160ms;
}
.busy-dots i:nth-child(3) {
animation-delay: 320ms;
}
[data-lead-notice] > * {
animation: fade-in 160ms ease-out;
}
/* лента недели */
[data-motion] .week .week-rule {
transition: transform 600ms var(--ease-out-quart);
}
[data-motion] .week .week-mark {
transition: transform 320ms var(--ease-out-quart) 300ms;
}
[data-motion] .week .week-note {
transition:
opacity 320ms var(--ease-out-quart) 300ms,
transform 320ms var(--ease-out-quart) 300ms;
}
[data-motion] .week .week-day:nth-child(5) .week-mark,
[data-motion] .week .week-day:nth-child(5) .week-note {
transition-delay: 480ms;
}
[data-motion] .week .week-bracket-line {
transition: transform 500ms var(--ease-out-quart) 680ms;
}
[data-motion] .week .week-bracket-note {
transition: opacity 240ms ease-out 1000ms;
}
[data-motion] .week:not([data-inview]) .week-rule,
[data-motion] .week:not([data-inview]) .week-mark {
transform: scaleX(0);
}
[data-motion] .week:not([data-inview]) .week-note {
opacity: 0;
transform: translateY(6px);
}
[data-motion] .week:not([data-inview]) .week-bracket-line {
transform: scaleY(0);
}
[data-motion] .week:not([data-inview]) .week-bracket-note {
opacity: 0;
}
@media (min-width: 1024px) {
[data-motion] .week:not([data-inview]) .week-bracket-line {
transform: scaleX(0);
}
}
/* липкая CTA */
.sticky-cta {
transition: transform 180ms var(--ease-in-quart);
}
.sticky-cta[data-visible] {
transition: transform 240ms var(--ease-out-quart);
}
}
.sticky-cta:not([data-visible]) {
transform: translateY(100%);
visibility: hidden;
transition-property: transform, visibility;
}