Add subscription validation and first-run onboarding reveal
All checks were successful
Build and Deploy Gateway / build-and-push (push) Successful in 16s
Build and Deploy Gateway / deploy (push) Successful in 1s

This commit is contained in:
2026-07-11 14:13:39 +03:00
parent 84efbe7450
commit 0a1aa8aed3
5 changed files with 205 additions and 29 deletions

View File

@@ -92,15 +92,43 @@ p {
.harbor-brand {
position: fixed;
top: 24px;
left: 28px;
display: flex;
align-items: center;
gap: 9px;
top: 50%;
left: 50%;
z-index: 2;
color: var(--harbor-word);
font-size: 13px;
letter-spacing: -0.035em;
transform: translate(-50%, calc(-50% - 25vh)) scale(3);
transform-origin: center;
transition: transform 1800ms cubic-bezier(0.16, 1, 0.3, 1);
user-select: none;
pointer-events: none;
}
.client-shell.is-first-run .harbor-brand {
transform: translate(-50%, calc(-50% - 72px)) scale(1.35);
}
.harbor-brand-content {
display: flex;
align-items: center;
gap: 9px;
}
.client-shell.is-intro .harbor-brand-content {
animation: harbor-first-run 1200ms cubic-bezier(0.16, 1, 0.3, 1);
}
.client-shell.is-intro .client-form {
animation: harbor-first-run-form 650ms 720ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes harbor-first-run {
from { transform: translateY(53px) scale(1.59); }
}
@keyframes harbor-first-run-form {
from { opacity: 0; filter: blur(8px); }
}
.harbor-brand svg {
@@ -113,6 +141,14 @@ p {
stroke-linejoin: round;
}
.harbor-brand .harbor-anchor-left {
stroke: var(--harbor-connect);
}
.harbor-brand .harbor-anchor-right {
stroke: var(--harbor-gateway);
}
.harbor-brand strong {
font-weight: 800;
}
@@ -726,7 +762,13 @@ p {
display: grid;
gap: 36px;
transform: translateX(0);
transition: left 850ms cubic-bezier(0.16, 1, 0.3, 1), transform 850ms cubic-bezier(0.16, 1, 0.3, 1), width 850ms cubic-bezier(0.16, 1, 0.3, 1);
transition: left 850ms cubic-bezier(0.16, 1, 0.3, 1), transform 850ms cubic-bezier(0.16, 1, 0.3, 1), width 850ms cubic-bezier(0.16, 1, 0.3, 1), opacity 650ms cubic-bezier(0.16, 1, 0.3, 1), filter 650ms cubic-bezier(0.16, 1, 0.3, 1);
}
.client-form.is-waiting {
opacity: 0;
filter: blur(10px);
pointer-events: none;
}
.client-subscription {
@@ -842,6 +884,12 @@ p {
opacity: 0.72;
filter: blur(0.5px);
box-shadow: 0 0 8px var(--client-accent), 0 0 18px var(--client-accent-soft);
transition: background 500ms ease, box-shadow 500ms ease;
}
.client-subscription-edit.is-invalid::after {
background: oklch(0.68 0.15 28);
box-shadow: 0 0 8px oklch(0.68 0.15 28 / 0.72), 0 0 18px oklch(0.68 0.15 28 / 0.24);
}
.client-subscription.is-timing-out .client-subscription-edit::after {
@@ -911,7 +959,7 @@ p {
pointer-events: none;
}
.client-subscription-edit button {
.client-subscription-submit {
position: absolute;
top: 4px;
right: 0;
@@ -923,6 +971,32 @@ p {
color: var(--client-accent);
font-size: 19px;
font-weight: 700;
cursor: pointer;
transition: color 250ms ease, filter 500ms ease, opacity 250ms ease, transform 300ms cubic-bezier(0.16, 1, 0.3, 1);
}
.client-subscription-submit:hover:not(:disabled),
.client-subscription-submit:focus-visible {
filter: drop-shadow(0 0 5px var(--client-accent)) drop-shadow(0 0 14px var(--client-accent));
transform: scale(1.14);
}
.client-subscription-submit:disabled {
cursor: default;
}
.client-subscription-edit.is-checking .client-subscription-submit {
color: var(--client-muted);
animation: client-validation-pulse 900ms ease-in-out infinite alternate;
}
.client-subscription-edit.is-invalid .client-subscription-submit {
color: oklch(0.68 0.15 28);
opacity: 0.9;
}
@keyframes client-validation-pulse {
to { opacity: 0.35; }
}
.client-subscription-heading {
@@ -1374,10 +1448,7 @@ p {
}
.harbor-brand {
position: absolute;
top: -4px;
left: 50%;
transform: translateX(-50%);
transform: translate(-50%, calc(-50% - 28vh)) scale(2.15);
}
.client-instructions-toggle {
@@ -1437,12 +1508,22 @@ p {
.client-instruction-summary > i::after,
.client-subscription-edit,
.client-subscription-edit::after,
.client-subscription-submit,
.client-subscription-summary,
.client-subscription-summary strong {
transition: none;
animation: none;
}
.harbor-brand {
transition: none;
animation: none;
}
.harbor-brand-content {
animation: none;
}
.client-state-copy h2,
.client-state-detail > * {
animation: none;