Files
paseo/packages/website/src/styles.css
T
Mohamed BoudraandGitHub d781b68711 Polish release notes and in-app help (#2070)
* feat(ui): improve changelog and help navigation

Make release notes easier to scan and reach from the app. Also keep the homepage marquee within the layout viewport so it cannot create horizontal scrolling.

* fix(website): reject duplicate release anchors
2026-07-14 21:06:25 +02:00

750 lines
15 KiB
CSS

@import "tailwindcss";
* {
scrollbar-color: var(--color-scrollbar-handle) transparent;
scrollbar-width: thin;
}
*::-webkit-scrollbar {
width: 8px;
height: 8px;
}
*::-webkit-scrollbar-track {
background: transparent;
}
*::-webkit-scrollbar-thumb {
border: 2px solid transparent;
border-radius: 9999px;
background: var(--color-scrollbar-handle) content-box;
}
*::-webkit-scrollbar-button {
display: none;
width: 0;
height: 0;
}
@keyframes voice-bar {
0% {
transform: scaleY(1);
}
100% {
transform: scaleY(0.3);
}
}
@keyframes social-proof-scroll {
from {
transform: translateX(0);
}
to {
transform: translateX(-50%);
}
}
.social-proof-marquee {
margin-inline: calc(50% - 50cqw);
overflow-x: clip;
position: relative;
}
.landing-content {
container-type: inline-size;
}
.social-proof-marquee::before,
.social-proof-marquee::after {
content: "";
position: absolute;
top: 0;
bottom: 0;
width: max(4rem, 8vw);
z-index: 1;
pointer-events: none;
}
.social-proof-marquee::before {
left: 0;
background: linear-gradient(to right, var(--color-background), transparent);
}
.social-proof-marquee::after {
right: 0;
background: linear-gradient(to left, var(--color-background), transparent);
}
.social-proof-row {
display: flex;
width: 100%;
}
.social-proof-track {
display: flex;
width: max-content;
animation: social-proof-scroll 46s linear infinite;
will-change: transform;
}
.social-proof-track-reverse {
animation-direction: reverse;
animation-duration: 52s;
}
.social-proof-marquee:hover .social-proof-track {
animation-play-state: paused;
}
.social-proof-card-text {
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
}
@media (prefers-reduced-motion: reduce) {
.social-proof-track {
animation: none;
}
}
/* Title font - centralized for easy changes */
.font-title {
font-family: inherit;
}
/* Inline code styling - scoped to prose content */
.prose :not(pre) > code {
background-color: var(--color-muted);
color: var(--color-foreground);
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
font-size: 0.875em;
}
/* Changelog */
.changelog-release {
padding-bottom: 3rem;
}
.changelog-release + .changelog-release {
border-top: 1px solid var(--color-border);
padding-top: 3rem;
}
.changelog-release-date {
display: block;
margin-bottom: 0.625rem;
color: var(--color-muted-foreground);
font-size: 0.8125rem;
}
.changelog-release-heading {
position: relative;
scroll-margin-top: 1.5rem;
margin-bottom: 1.75rem;
}
.changelog-release-title {
color: var(--color-foreground);
font-size: 1.25rem;
font-weight: 500;
letter-spacing: -0.01em;
line-height: 1.4;
}
.changelog-release-title span {
color: var(--color-muted-foreground);
font-weight: 400;
}
.changelog-heading-anchor {
position: absolute;
top: 0;
right: 100%;
bottom: 0;
display: inline-flex;
align-items: center;
padding-right: 0.375rem;
color: color-mix(in srgb, var(--color-foreground) 40%, transparent);
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-weight: 400;
text-decoration: none;
opacity: 0;
transition: opacity 150ms ease;
}
.changelog-release-heading:hover .changelog-heading-anchor,
.changelog-heading-anchor:focus {
opacity: 1;
}
.changelog-heading-anchor:hover {
color: var(--color-foreground);
}
.changelog-release-notes {
color: color-mix(in srgb, var(--color-foreground) 76%, transparent);
font-size: 0.9375rem;
line-height: 1.7;
}
.changelog-release-notes h3 {
margin-top: 1.75rem;
margin-bottom: 0.625rem;
color: var(--color-muted-foreground);
font-size: 0.875rem;
font-weight: 500;
line-height: 1.4;
}
.changelog-release-notes h3:first-child {
margin-top: 0;
}
.changelog-release-notes p {
margin-block: 0.75rem;
}
.changelog-release-notes ul {
display: grid;
gap: 0.625rem;
margin-top: 0.75rem;
padding-left: 1.25rem;
list-style: disc;
}
.changelog-release-notes li::marker {
color: color-mix(in srgb, var(--color-primary) 65%, var(--color-muted-foreground));
}
.changelog-release-notes strong {
color: var(--color-foreground);
font-weight: 500;
}
.changelog-release-notes a {
color: var(--color-foreground);
text-decoration-color: color-mix(in srgb, var(--color-primary) 65%, transparent);
text-decoration-line: underline;
text-underline-offset: 3px;
}
.changelog-release-notes a:hover {
color: color-mix(in srgb, var(--color-foreground) 78%, var(--color-primary));
}
.changelog-release-notes code {
border-radius: 0.25rem;
background: var(--color-muted);
padding: 0.125rem 0.375rem;
color: var(--color-foreground);
font-size: 0.875em;
}
/* Docs page prose styles — mirrors the original docs/*.tsx components */
.docs-prose {
color: rgba(255, 255, 255, 0.6);
line-height: 1.625;
}
.docs-prose > :first-child {
margin-top: 0;
}
.docs-prose h1,
.docs-prose h2,
.docs-prose h3,
.docs-prose h4,
.docs-prose h5,
.docs-prose h6 {
position: relative;
scroll-margin-top: 1.5rem;
}
.docs-prose h1 {
color: var(--color-foreground);
font-size: 1.875rem;
line-height: 1.25;
font-weight: 500;
margin-top: 0;
margin-bottom: 2rem;
}
.docs-prose h2 {
color: var(--color-foreground);
font-size: 1.25rem;
line-height: 1.4;
font-weight: 500;
margin-top: 2rem;
margin-bottom: 1rem;
}
.docs-prose h3 {
color: var(--color-foreground);
font-size: 1.125rem;
line-height: 1.4;
font-weight: 500;
margin-top: 1.5rem;
margin-bottom: 0.75rem;
}
.docs-prose .heading-anchor {
position: absolute;
right: 100%;
top: 0;
bottom: 0;
display: inline-flex;
align-items: center;
padding-right: 0.375rem;
text-decoration: none;
color: rgba(255, 255, 255, 0.4);
opacity: 0;
transition: opacity 0.15s ease;
}
.docs-prose .heading-anchor:hover {
color: var(--color-foreground);
}
.docs-prose h1:hover .heading-anchor,
.docs-prose h2:hover .heading-anchor,
.docs-prose h3:hover .heading-anchor,
.docs-prose h4:hover .heading-anchor,
.docs-prose h5:hover .heading-anchor,
.docs-prose h6:hover .heading-anchor,
.docs-prose .heading-anchor:focus {
opacity: 1;
}
.docs-prose .heading-anchor-icon {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-weight: 400;
}
.docs-prose p {
margin-top: 1rem;
margin-bottom: 1rem;
}
.docs-prose a {
color: var(--color-foreground);
font-weight: 500;
text-decoration: underline;
text-decoration-thickness: 1px;
text-decoration-color: var(--color-primary);
text-underline-offset: 3px;
}
.docs-prose a:hover {
color: rgba(255, 255, 255, 0.8);
}
.docs-prose ul,
.docs-prose ol {
margin-top: 1rem;
margin-bottom: 1rem;
padding-left: 1.5rem;
}
.docs-prose ul {
list-style: disc;
}
.docs-prose ol {
list-style: decimal;
}
.docs-prose li {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
}
.docs-prose strong {
color: rgba(255, 255, 255, 0.8);
font-weight: 600;
}
.docs-prose blockquote {
background-color: color-mix(in srgb, var(--color-primary) 10%, transparent);
border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent);
border-radius: 0.5rem;
padding: 1rem;
margin-top: 1rem;
margin-bottom: 1rem;
color: rgba(255, 255, 255, 0.8);
}
.docs-prose blockquote > :first-child {
margin-top: 0;
}
.docs-prose blockquote > :last-child {
margin-bottom: 0;
}
.docs-prose table {
width: 100%;
border-collapse: collapse;
margin-top: 1rem;
margin-bottom: 1rem;
font-size: 0.875rem;
display: block;
overflow-x: auto;
}
.docs-prose th,
.docs-prose td {
border: 1px solid var(--color-border);
padding: 0.625rem 0.75rem;
text-align: left;
vertical-align: top;
}
.docs-prose th {
background-color: var(--color-muted);
color: var(--color-foreground);
font-weight: 600;
}
.docs-prose tbody tr:nth-child(even) {
background-color: rgba(255, 255, 255, 0.02);
}
.docs-prose pre {
background-color: var(--color-card) !important;
border: 1px solid var(--color-border);
border-radius: 0.5rem;
padding: 1rem;
overflow-x: auto;
margin-top: 1rem;
margin-bottom: 1rem;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
font-size: 0.875rem;
color: var(--color-foreground);
}
.docs-prose pre [data-line] {
display: inline-block;
min-width: 100%;
}
.docs-prose pre code {
background: transparent;
padding: 0;
border-radius: 0;
font-size: inherit;
}
.docs-prose :not(pre) > code {
background-color: var(--color-muted);
color: var(--color-foreground);
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
font-size: 0.875em;
}
.docs-prose hr {
border-color: var(--color-border);
margin-top: 2rem;
margin-bottom: 2rem;
}
.docs-source-footer {
border-top: 1px solid var(--color-border);
margin-top: 3rem;
padding-top: 1.25rem;
font-size: 0.875rem;
}
.docs-source-footer a {
color: rgba(255, 255, 255, 0.5);
font-weight: 500;
text-decoration: none;
}
.docs-source-footer a:hover {
color: var(--color-foreground);
}
/* Blog post prose styles — adapted from moboudra.com */
.blog-prose {
color: rgba(250, 250, 250, 0.82);
line-height: 1.8;
font-size: 1.125rem;
}
.blog-prose h1,
.blog-prose h2,
.blog-prose h3 {
color: var(--color-foreground);
font-weight: 600;
text-decoration: underline;
text-decoration-color: color-mix(in srgb, var(--color-primary) 50%, transparent);
text-decoration-thickness: 2px;
text-underline-offset: 4px;
}
.blog-prose h1,
.blog-prose h2 {
font-size: 1.5rem;
line-height: 1.3;
margin-top: 2.5rem;
margin-bottom: 0.75rem;
}
.blog-prose h3 {
font-size: 1.25rem;
line-height: 1.4;
margin-top: 2rem;
margin-bottom: 0.5rem;
}
.blog-prose p {
margin-top: 1rem;
margin-bottom: 1rem;
}
.blog-prose a {
color: var(--color-foreground);
text-decoration: underline;
text-underline-offset: 2px;
}
.blog-prose a:hover {
color: var(--color-primary);
}
.blog-prose ul,
.blog-prose ol {
margin-top: 1rem;
margin-bottom: 1rem;
padding-left: 1.5rem;
}
.blog-prose ul {
list-style: disc;
}
.blog-prose ol {
list-style: decimal;
}
.blog-prose li {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
}
.blog-prose blockquote {
border-left: 3px solid var(--color-border);
padding-left: 1rem;
color: rgba(250, 250, 250, 0.6);
margin-top: 1rem;
margin-bottom: 1rem;
}
.blog-prose pre {
background-color: var(--color-card);
border: 1px solid var(--color-border);
border-radius: 0.5rem;
padding: 1rem;
overflow-x: auto;
margin-top: 1rem;
margin-bottom: 1rem;
}
.blog-prose :not(pre) > code {
background-color: var(--color-muted);
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
font-size: 0.875em;
}
.blog-prose img {
max-width: 100%;
border-radius: 0.5rem;
margin-top: 1rem;
margin-bottom: 1rem;
}
.blog-prose hr {
border-color: var(--color-border);
margin-top: 2rem;
margin-bottom: 2rem;
}
@theme {
--color-background: #101615;
--color-foreground: #fafafa;
--color-muted: #1a1f1e;
--color-muted-foreground: #a8adac;
--color-card: #171d1c;
--color-border: #252b2a;
--color-scrollbar-handle: #717574;
--color-primary: #239956;
--color-primary-foreground: #ffffff;
--color-secondary: #252b2a;
--color-secondary-foreground: #fafafa;
/* Mockup palette (from app unistyles theme) */
--color-mock-surface0: #181b1a;
--color-mock-surface1: #1e2120;
--color-mock-surface2: #272a29;
--color-mock-surface3: #434645;
--color-mock-sidebar: #141716;
--color-mock-fg: #fafafa;
--color-mock-fg-muted: #a1a5a4;
--color-mock-border: #272a29;
--color-mock-border-accent: #313433;
--color-mock-accent: #20744a;
--color-mock-green: #22c55e;
--color-mock-green-400: #4ade80;
--color-mock-red: #f87171;
--color-mock-amber: #f59e0b;
--color-mock-blue: #3b82f6;
--color-mock-zinc500: #a1a5a4;
--color-mock-zinc600: #52525b;
--color-mock-diff-add: rgba(46, 160, 67, 0.15);
--color-mock-diff-remove: rgba(248, 81, 73, 0.1);
/* Syntax highlighting */
--color-syn-keyword: #ff7b72;
--color-syn-comment: #8b949e;
--color-syn-string: #a5d6ff;
--color-syn-number: #79c0ff;
--color-syn-function: #d2a8ff;
--color-syn-tag: #7ee787;
--color-syn-property: #79c0ff;
--color-syn-variable: #c9d1d9;
--color-syn-punctuation: #c9d1d9;
--color-syn-operator: #79c0ff;
--animate-flutter-left: flutter-left 0.6s ease-in-out infinite;
--animate-flutter-right: flutter-right 0.6s ease-in-out infinite;
--animate-float: float 8s ease-in-out infinite;
--animate-flutter-body: flutter-body 0.5s ease-in-out infinite;
--animate-synced-snake-dot: synced-snake-dot 950ms linear infinite;
}
/* Synced loader — 6-dot snake animation matching the real app.
Each dot runs this keyframe with a staggered delay so that at any moment
up to 4 dots are visible at decreasing opacity (head=1, trail=0.72/0.46/0.22).
steps(1,end) keeps each opacity level solid for its full 1/6-cycle slot. */
@keyframes synced-snake-dot {
0% {
opacity: 1;
animation-timing-function: steps(1, end);
}
16.667% {
opacity: 0.72;
animation-timing-function: steps(1, end);
}
33.333% {
opacity: 0.46;
animation-timing-function: steps(1, end);
}
50% {
opacity: 0.22;
animation-timing-function: steps(1, end);
}
66.667% {
opacity: 0;
animation-timing-function: steps(1, end);
}
83.333% {
opacity: 0;
animation-timing-function: steps(1, end);
}
}
@keyframes flutter-left {
0%,
100% {
transform: rotateY(0deg) rotateZ(0deg);
}
50% {
transform: rotateY(50deg) rotateZ(-5deg);
}
}
@keyframes flutter-right {
0%,
100% {
transform: rotateY(0deg) rotateZ(0deg);
}
50% {
transform: rotateY(-50deg) rotateZ(5deg);
}
}
@keyframes flutter-body {
0%,
100% {
transform: translateY(0) rotate(0deg);
}
50% {
transform: translateY(-2px) rotate(-3deg);
}
}
@keyframes float-1 {
0% {
transform: translate(0, 0) rotate(0deg);
}
20% {
transform: translate(12px, -18px) rotate(5deg);
}
40% {
transform: translate(-8px, -30px) rotate(-3deg);
}
60% {
transform: translate(-15px, -12px) rotate(2deg);
}
80% {
transform: translate(5px, 8px) rotate(-4deg);
}
100% {
transform: translate(0, 0) rotate(0deg);
}
}
@keyframes float-2 {
0% {
transform: translate(0, 0) rotate(0deg);
}
15% {
transform: translate(-10px, -12px) rotate(-4deg);
}
35% {
transform: translate(8px, -25px) rotate(3deg);
}
55% {
transform: translate(15px, -8px) rotate(-2deg);
}
75% {
transform: translate(-5px, 10px) rotate(5deg);
}
100% {
transform: translate(0, 0) rotate(0deg);
}
}
@keyframes float-3 {
0% {
transform: translate(0, 0) rotate(0deg);
}
25% {
transform: translate(18px, -10px) rotate(3deg);
}
50% {
transform: translate(5px, -35px) rotate(-5deg);
}
75% {
transform: translate(-12px, -15px) rotate(4deg);
}
100% {
transform: translate(0, 0) rotate(0deg);
}
}