8.3 KB400 lines
Blame
1@import url('https://fonts.googleapis.com/css2?family=Libre+Caslon+Text:ital,wght@0,400;1,400&family=JetBrains+Mono:wght@400;500&display=swap');
2@import "tailwindcss";
3
4/* ── Light theme (default) ── */
5:root {
6 --bg-page: #faf8f5;
7 --bg-card: #f2efe9;
8 --bg-inset: #eae6df;
9 --bg-hover: #e2ddd5;
10 --bg-input: #ffffff;
11
12 --text-primary: #2c2824;
13 --text-secondary: #4a4540;
14 --text-muted: #7a746c;
15 --text-faint: #a09888;
16
17 --accent: #4d8a78;
18 --accent-hover: #3d7a68;
19 --accent-subtle: #e8f2ee;
20 --accent-text: #ffffff;
21
22 --border: #d9d3ca;
23 --border-subtle: #e8e3db;
24 --divide: #e2ddd580;
25
26 --status-open-bg: #e8f2ee;
27 --status-open-text: #2d6b56;
28 --status-open-border: #b0d4c5;
29 --status-merged-bg: #ede8f5;
30 --status-merged-text: #6b4fa0;
31 --status-merged-border: #c5b8dc;
32 --status-closed-bg: #f5e8e8;
33 --status-closed-text: #a05050;
34 --status-closed-border: #dcb8b8;
35
36 --error-bg: #f5e8e8;
37 --error-border: #dcb8b8;
38 --error-text: #a05050;
39
40 --code-bg: #f2efe9;
41
42 --diff-add-bg: rgba(46, 160, 67, 0.08);
43 --diff-add-text: #1a7f37;
44 --diff-del-bg: rgba(248, 81, 73, 0.08);
45 --diff-del-text: #cf222e;
46}
47
48/* ── Dark theme (Photodesk warm) ── */
49[data-theme="dark"] {
50 --bg-page: #1a1918;
51 --bg-card: #242220;
52 --bg-inset: #2e2c29;
53 --bg-hover: #383532;
54 --bg-input: #2e2c29;
55
56 --text-primary: #e8e4df;
57 --text-secondary: #c4bfb8;
58 --text-muted: #9a948c;
59 --text-faint: #6b665f;
60
61 --accent: #7aab9c;
62 --accent-hover: #8dbdaf;
63 --accent-subtle: #2a3632;
64 --accent-text: #1a1918;
65
66 --border: #3a3835;
67 --border-subtle: #302e2b;
68 --divide: #3a383580;
69
70 --status-open-bg: #2a3632;
71 --status-open-text: #7aab9c;
72 --status-open-border: #3d5249;
73 --status-merged-bg: #2e2a38;
74 --status-merged-text: #a892cc;
75 --status-merged-border: #4a3d66;
76 --status-closed-bg: #382a2a;
77 --status-closed-text: #cc9292;
78 --status-closed-border: #664040;
79
80 --error-bg: #382a2a;
81 --error-border: #664040;
82 --error-text: #cc9292;
83
84 --code-bg: #242220;
85
86 --diff-add-bg: rgba(46, 160, 67, 0.15);
87 --diff-add-text: #3fb950;
88 --diff-del-bg: rgba(248, 81, 73, 0.15);
89 --diff-del-text: #f85149;
90}
91
92/* ── Base styles ── */
93@media (pointer: fine) {
94 html {
95 scrollbar-gutter: stable both-edges;
96 }
97}
98
99@supports not (scrollbar-gutter: stable) {
100 @media (pointer: fine) {
101 html {
102 overflow-y: scroll;
103 }
104 }
105}
106
107body {
108 font-family: 'Libre Caslon Text', 'Georgia', serif;
109 background-color: var(--bg-page);
110 color: var(--text-primary);
111 overflow-x: hidden;
112}
113
114.grove-body {
115 height: 100dvh;
116 overflow: hidden;
117 display: flex;
118 flex-direction: column;
119}
120.grove-scroll {
121 flex: 1;
122 min-height: 0;
123 overflow: auto;
124 /* iOS momentum scrolling */
125 -webkit-overflow-scrolling: touch;
126}
127
128code, pre, .font-mono, kbd, samp {
129 font-family: 'JetBrains Mono', 'Menlo', monospace;
130}
131
132/* ── Shimmer skeleton ── */
133@keyframes shimmer {
134 0% { background-position: -400px 0; }
135 100% { background-position: 400px 0; }
136}
137.skeleton {
138 background: linear-gradient(
139 90deg,
140 var(--bg-card) 0%,
141 var(--bg-hover) 40%,
142 var(--bg-card) 80%
143 );
144 background-size: 800px 100%;
145 animation: shimmer 1.5s ease-in-out infinite;
146}
147
148/* ── Badge activity cue for running states ── */
149@keyframes badge-running-border {
150 0%, 100% {
151 border-color: currentColor;
152 }
153 50% {
154 border-color: transparent;
155 }
156}
157.badge-running-text-pulse {
158 animation: badge-running-border 2s ease-in-out infinite;
159}
160
161/* ── Focus styles ── */
162*:focus-visible {
163 outline: 2px solid var(--accent);
164 outline-offset: 2px;
165}
166
167/* ── Thin scrollbars site-wide ── */
168* {
169 scrollbar-width: thin;
170 scrollbar-color: var(--border) transparent;
171}
172*::-webkit-scrollbar {
173 width: 6px;
174 height: 6px;
175}
176*::-webkit-scrollbar-track {
177 background: transparent;
178}
179*::-webkit-scrollbar-thumb {
180 background: var(--border);
181 border-radius: 3px;
182}
183*::-webkit-scrollbar-thumb:hover {
184 background: var(--text-faint);
185}
186
187/* ── Interactive row (file trees, lists) ── */
188.hover-row {
189 transition: background-color 0.1s;
190}
191@media (hover: hover) {
192 .hover-row:hover {
193 background-color: var(--bg-hover);
194 }
195}
196.hover-row:active {
197 background-color: var(--bg-hover);
198}
199
200/* ── Log line hover ── */
201.log-line:hover {
202 background-color: var(--bg-inset);
203}
204
205/* ── Docker group hover ── */
206.docker-group-header:hover {
207 background-color: var(--bg-inset) !important;
208}
209.docker-group-header:hover ~ .docker-group-body .log-line {
210 background-color: var(--bg-inset);
211}
212.docker-group-header .docker-group-copy {
213 opacity: 0;
214}
215.docker-group-header:hover .docker-group-copy {
216 opacity: 1;
217}
218
219/* ── Button resets ── */
220.btn-reset {
221 background: none;
222 border: none;
223 cursor: pointer;
224 font: inherit;
225 color: inherit;
226 padding: 0;
227}
228
229/* ── Collab presence avatars ── */
230.collab-avatar {
231 transition: transform 0.15s ease;
232}
233.collab-avatar:hover {
234 transform: scale(1.15);
235}
236.collab-avatar::after {
237 content: attr(data-tooltip);
238 position: absolute;
239 top: calc(100% + 6px);
240 left: 50%;
241 transform: translateX(-50%) scale(0.9);
242 padding: 3px 8px;
243 border-radius: 4px;
244 background: var(--bg-inset, #333);
245 color: var(--text-primary);
246 font-size: 10px;
247 font-family: 'JetBrains Mono', Menlo, monospace;
248 white-space: nowrap;
249 pointer-events: none;
250 opacity: 0;
251 transition: opacity 0.15s ease, transform 0.15s ease;
252 border: 1px solid var(--border);
253 z-index: 50;
254}
255.collab-avatar:hover::after {
256 opacity: 1;
257 transform: translateX(-50%) scale(1);
258}
259
260/* ── Markdown prose ── */
261.prose {
262 color: var(--text-secondary);
263 line-height: 1.7;
264}
265.prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6 {
266 color: var(--text-primary);
267 margin-top: 1.5em;
268 margin-bottom: 0.5em;
269 line-height: 1.3;
270}
271.prose h1 { font-size: 1.5rem; }
272.prose h2 { font-size: 1.25rem; }
273.prose h3 { font-size: 1.1rem; }
274.prose h1:first-child, .prose h2:first-child, .prose h3:first-child {
275 margin-top: 0;
276}
277.prose p {
278 margin: 0.75em 0;
279}
280.prose a {
281 color: var(--accent);
282 text-decoration: underline;
283}
284.prose a:hover {
285 color: var(--accent-hover);
286}
287.prose code {
288 background-color: var(--code-bg);
289 padding: 0.15em 0.35em;
290 font-size: 0.875em;
291}
292.prose pre {
293 background-color: var(--code-bg);
294 padding: 1em;
295 overflow-x: auto;
296 margin: 1em 0;
297 border: 1px solid var(--border-subtle);
298}
299.prose pre code {
300 background: none;
301 padding: 0;
302}
303.prose ul, .prose ol {
304 margin: 0.75em 0;
305 padding-left: 1.5em;
306}
307.prose ul { list-style: disc; }
308.prose ol { list-style: decimal; }
309.prose li { margin: 0.25em 0; }
310.prose blockquote {
311 border-left: 3px solid var(--border);
312 padding-left: 1em;
313 margin: 1em 0;
314 color: var(--text-muted);
315}
316.prose table {
317 width: 100%;
318 border-collapse: collapse;
319 margin: 1em 0;
320 display: block;
321 overflow-x: auto;
322}
323.prose th, .prose td {
324 border: 1px solid var(--border-subtle);
325 padding: 0.4em 0.75em;
326 text-align: left;
327}
328.prose th {
329 background-color: var(--bg-card);
330 font-weight: 600;
331}
332.prose img {
333 max-width: 100%;
334}
335.prose hr {
336 border: none;
337 border-top: 1px solid var(--border);
338 margin: 1.5em 0;
339}
340
341/* ── Shiki syntax highlighting (dual theme) ── */
342.shiki,
343.shiki span {
344 color: var(--shiki-light) !important;
345 background-color: transparent !important;
346}
347[data-theme="dark"] .shiki,
348[data-theme="dark"] .shiki span {
349 color: var(--shiki-dark) !important;
350}
351
352/* ── Card hover states ── */
353.card-hover {
354 transition: background-color 0.15s, border-color 0.15s;
355}
356.card-hover:hover {
357 background-color: var(--bg-hover);
358 border-color: var(--border);
359}
360
361/* ── Dialog ── */
362@keyframes dialog-enter {
363 from {
364 opacity: 0;
365 transform: scale(0.96) translateY(8px);
366 }
367 to {
368 opacity: 1;
369 transform: scale(1) translateY(0);
370 }
371}
372@keyframes backdrop-enter {
373 from { opacity: 0; }
374 to { opacity: 1; }
375}
376dialog::backdrop {
377 background-color: rgba(0, 0, 0, 0.4);
378 animation: backdrop-enter 0.15s ease-out;
379}
380[data-theme="dark"] dialog::backdrop {
381 background-color: rgba(0, 0, 0, 0.6);
382}
383dialog {
384 border: none;
385 padding: 0;
386 max-width: calc(100vw - 2rem);
387}
388dialog[open] {
389 animation: dialog-enter 0.2s ease-out;
390}
391
392/* ── Toast entrance ── */
393@keyframes toast-enter {
394 from { opacity: 0; transform: translateY(8px); }
395 to { opacity: 1; transform: translateY(0); }
396}
397.toast-enter {
398 animation: toast-enter 0.15s ease-out;
399}
400