Files
paseo/packages/website/src/styles.css
Mohamed Boudra f53c770a71 [codex] add batch close rpc for workspace tabs (#165)
* style: add subtle teal tint to dark mode surfaces

Replace neutral gray surfaces with a teal-tinted palette across
the app and website, giving Paseo a warmer, more recognizable feel.
App uses a restrained tint (G-R ~3), website is slightly stronger
(G-R ~6) as a brand showcase.

* fix(opencode): handle message.part.delta events for assistant text streaming

OpenCode v2 streams assistant text via `message.part.delta` events (with
field "text" or "reasoning"), but the translator only handled
`message.part.updated`. This caused assistant messages to be silently
dropped during live streaming.

* feat: show agent short ID in tab context menu and tooltip (#161)

Add agent short ID to the "Copy agent id" menu item as trailing hint
text and to the tab tooltip next to the title. Add leading icons to
all workspace tab context menu items.

* add batch close rpc for workspace tabs
2026-04-01 14:31:38 +08:00

343 lines
7.3 KiB
CSS

@import "tailwindcss";
@keyframes voice-bar {
0% { transform: scaleY(1); }
100% { transform: scaleY(0.3); }
}
/* 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);
padding: 0.125rem 0.375rem;
border-radius: 0.25rem;
font-size: 0.875em;
}
/* Markdown rendering styles for /changelog */
.changelog-markdown {
color: rgba(250, 250, 250, 0.82);
line-height: 1.7;
}
.changelog-markdown h1 {
color: var(--color-foreground);
font-size: 2rem;
line-height: 1.2;
font-weight: 600;
margin-bottom: 1rem;
}
.changelog-markdown h2 {
color: var(--color-foreground);
font-size: 1.5rem;
line-height: 1.3;
font-weight: 600;
margin-top: 2rem;
margin-bottom: 0.75rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--color-border);
}
.changelog-markdown h3 {
color: var(--color-foreground);
font-size: 1.125rem;
line-height: 1.4;
font-weight: 600;
margin-top: 1.5rem;
margin-bottom: 0.5rem;
}
.changelog-markdown p {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}
.changelog-markdown ul {
list-style: disc;
margin-left: 1.25rem;
margin-top: 0.75rem;
margin-bottom: 0.75rem;
display: grid;
gap: 0.5rem;
}
.changelog-markdown li {
padding-left: 0.125rem;
}
.changelog-markdown a {
color: var(--color-foreground);
text-decoration: underline;
text-underline-offset: 2px;
}
.changelog-markdown a:hover {
color: rgba(250, 250, 250, 0.8);
}
/* 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: #252B2A;
--color-muted-foreground: #A8ADAC;
--color-card: #171D1C;
--color-border: #252B2A;
--color-primary: #3b82f6;
--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: #ef4444;
--color-mock-amber: #f59e0b;
--color-mock-blue: #3b82f6;
--color-mock-zinc500: #71717a;
--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);
}
}